summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/gudhi/Active_witness/Active_witness.h67
-rw-r--r--include/gudhi/Active_witness/Active_witness_iterator.h108
-rw-r--r--include/gudhi/Alpha_complex.h434
-rw-r--r--include/gudhi/Bitmap_cubical_complex.h582
-rw-r--r--include/gudhi/Bitmap_cubical_complex/counter.h145
-rw-r--r--include/gudhi/Bitmap_cubical_complex_base.h854
-rw-r--r--include/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h396
-rw-r--r--include/gudhi/Bottleneck.h123
-rw-r--r--include/gudhi/Cech_complex.h130
-rw-r--r--include/gudhi/Cech_complex_blocker.h91
-rw-r--r--include/gudhi/Clock.h89
-rw-r--r--include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h101
-rw-r--r--include/gudhi/Contraction/Edge_profile.h130
-rw-r--r--include/gudhi/Contraction/policies/Contraction_visitor.h91
-rw-r--r--include/gudhi/Contraction/policies/Cost_policy.h53
-rw-r--r--include/gudhi/Contraction/policies/Dummy_valid_contraction.h49
-rw-r--r--include/gudhi/Contraction/policies/Edge_length_cost.h56
-rw-r--r--include/gudhi/Contraction/policies/First_vertex_placement.h52
-rw-r--r--include/gudhi/Contraction/policies/Link_condition_valid_contraction.h56
-rw-r--r--include/gudhi/Contraction/policies/Middle_placement.h51
-rw-r--r--include/gudhi/Contraction/policies/Placement_policy.h51
-rw-r--r--include/gudhi/Contraction/policies/Valid_contraction_policy.h51
-rw-r--r--include/gudhi/Debug_utils.h57
-rw-r--r--include/gudhi/Edge_contraction.h231
-rw-r--r--include/gudhi/Euclidean_strong_witness_complex.h104
-rw-r--r--include/gudhi/Euclidean_witness_complex.h106
-rw-r--r--include/gudhi/GIC.h1371
-rw-r--r--include/gudhi/Graph_matching.h174
-rw-r--r--include/gudhi/Hasse_complex.h248
-rw-r--r--include/gudhi/Internal_point.h91
-rw-r--r--include/gudhi/Kd_tree_search.h286
-rw-r--r--include/gudhi/Miniball.COPYRIGHT4
-rw-r--r--include/gudhi/Miniball.README26
-rw-r--r--include/gudhi/Miniball.hpp523
-rw-r--r--include/gudhi/Neighbors_finder.h193
-rw-r--r--include/gudhi/Null_output_iterator.h48
-rw-r--r--include/gudhi/Off_reader.h187
-rw-r--r--include/gudhi/PSSK.h168
-rw-r--r--include/gudhi/Persistence_graph.h188
-rw-r--r--include/gudhi/Persistence_heat_maps.h919
-rw-r--r--include/gudhi/Persistence_intervals.h570
-rw-r--r--include/gudhi/Persistence_intervals_with_distances.h63
-rw-r--r--include/gudhi/Persistence_landscape.h1383
-rw-r--r--include/gudhi/Persistence_landscape_on_grid.h1348
-rw-r--r--include/gudhi/Persistence_vectors.h640
-rw-r--r--include/gudhi/Persistent_cohomology.h769
-rw-r--r--include/gudhi/Persistent_cohomology/Field_Zp.h116
-rw-r--r--include/gudhi/Persistent_cohomology/Multi_field.h185
-rw-r--r--include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h140
-rw-r--r--include/gudhi/Point.h170
-rw-r--r--include/gudhi/Points_3D_off_io.h202
-rw-r--r--include/gudhi/Points_off_io.h183
-rw-r--r--include/gudhi/Rips_complex.h185
-rw-r--r--include/gudhi/Simple_object_pool.h81
-rw-r--r--include/gudhi/Simplex_tree.h1483
-rw-r--r--include/gudhi/Simplex_tree/Simplex_tree_iterators.h354
-rw-r--r--include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h72
-rw-r--r--include/gudhi/Simplex_tree/Simplex_tree_siblings.h131
-rw-r--r--include/gudhi/Simplex_tree/indexing_tag.h39
-rw-r--r--include/gudhi/Skeleton_blocker.h250
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h144
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h77
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h203
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h99
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h190
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h374
-rw-r--r--include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h273
-rw-r--r--include/gudhi/Skeleton_blocker/internal/Top_faces.h73
-rw-r--r--include/gudhi/Skeleton_blocker/internal/Trie.h269
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h134
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h147
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h32
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h402
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h226
-rw-r--r--include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h170
-rw-r--r--include/gudhi/Skeleton_blocker_complex.h1605
-rw-r--r--include/gudhi/Skeleton_blocker_contractor.h582
-rw-r--r--include/gudhi/Skeleton_blocker_geometric_complex.h227
-rw-r--r--include/gudhi/Skeleton_blocker_link_complex.h299
-rw-r--r--include/gudhi/Skeleton_blocker_simplifiable_complex.h467
-rw-r--r--include/gudhi/Sparse_rips_complex.h175
-rw-r--r--include/gudhi/Strong_witness_complex.h182
-rw-r--r--include/gudhi/Tangential_complex.h2008
-rw-r--r--include/gudhi/Tangential_complex/Simplicial_complex.h539
-rw-r--r--include/gudhi/Tangential_complex/config.h43
-rw-r--r--include/gudhi/Tangential_complex/utilities.h195
-rw-r--r--include/gudhi/Unitary_tests_utils.h40
-rw-r--r--include/gudhi/Witness_complex.h201
-rw-r--r--include/gudhi/Witness_complex/all_faces_in.h55
-rw-r--r--include/gudhi/allocator.h55
-rw-r--r--include/gudhi/choose_n_farthest_points.h133
-rw-r--r--include/gudhi/common_persistence_representations.h127
-rw-r--r--include/gudhi/console_color.h97
-rw-r--r--include/gudhi/distance_functions.h123
-rw-r--r--include/gudhi/graph_simplicial_complex.h111
-rw-r--r--include/gudhi/pick_n_random_points.h86
-rw-r--r--include/gudhi/random_point_generators.h507
-rw-r--r--include/gudhi/read_persistence_from_file.h120
-rw-r--r--include/gudhi/reader_utils.h369
-rw-r--r--include/gudhi/sparsify_point_set.h113
-rw-r--r--include/gudhi/writing_persistence_to_file.h117
101 files changed, 0 insertions, 28437 deletions
diff --git a/include/gudhi/Active_witness/Active_witness.h b/include/gudhi/Active_witness/Active_witness.h
deleted file mode 100644
index 8cb8662b..00000000
--- a/include/gudhi/Active_witness/Active_witness.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ACTIVE_WITNESS_ACTIVE_WITNESS_H_
-#define ACTIVE_WITNESS_ACTIVE_WITNESS_H_
-
-#include <gudhi/Active_witness/Active_witness_iterator.h>
-#include <list>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
- /* \class Active_witness
- * \brief Class representing a list of nearest neighbors to a given witness.
- * \details Every element is a pair of a landmark identifier and the squared distance to it.
- */
-template< typename Id_distance_pair,
- typename INS_range >
-class Active_witness {
- public:
- typedef Active_witness<Id_distance_pair, INS_range> ActiveWitness;
- typedef typename INS_range::iterator INS_iterator;
- typedef Active_witness_iterator< ActiveWitness, Id_distance_pair, INS_iterator > iterator;
- typedef typename std::list<Id_distance_pair> Table;
-
- Table nearest_landmark_table_;
- INS_range search_range_;
- INS_iterator iterator_next_;
- INS_iterator iterator_end_;
-
- Active_witness(const INS_range& search_range)
- : search_range_(search_range), iterator_next_(search_range_.begin()), iterator_end_(search_range_.end()) {
- }
-
- iterator begin() {
- return iterator(this, nearest_landmark_table_.begin());
- }
-
- iterator end() {
- return iterator(this);
- }
-};
-
-} // namespace witness_complex
-} // namespace Gudhi
-
-#endif // ACTIVE_WITNESS_ACTIVE_WITNESS_H_
diff --git a/include/gudhi/Active_witness/Active_witness_iterator.h b/include/gudhi/Active_witness/Active_witness_iterator.h
deleted file mode 100644
index 10d2ec52..00000000
--- a/include/gudhi/Active_witness/Active_witness_iterator.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_
-#define ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_
-
-#include <boost/iterator/iterator_facade.hpp>
-#include <list>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
-/* \brief Iterator in the nearest landmark list.
- * \details After the iterator reaches the end of the list,
- * the list is augmented by a (nearest landmark, distance) pair if possible.
- * If all the landmarks are present in the list, iterator returns the specific end value
- * of the corresponding 'Active_witness' object.
- */
-template< typename Active_witness,
- typename Id_distance_pair,
- typename INS_iterator >
-class Active_witness_iterator
- : public boost::iterator_facade< Active_witness_iterator <Active_witness, Id_distance_pair, INS_iterator>,
- Id_distance_pair const,
- boost::forward_traversal_tag,
- Id_distance_pair const> {
- friend class boost::iterator_core_access;
-
- typedef typename std::list<Id_distance_pair>::iterator Pair_iterator;
- typedef typename Gudhi::witness_complex::Active_witness_iterator<Active_witness,
- Id_distance_pair,
- INS_iterator> Iterator;
-
- Active_witness *aw_;
- Pair_iterator lh_; // landmark handle
- bool is_end_; // true only if the pointer is end and there are no more neighbors to add
-
- public:
- Active_witness_iterator(Active_witness* aw)
- : aw_(aw), lh_(aw_->nearest_landmark_table_.end()), is_end_(true) {
- }
-
- Active_witness_iterator(Active_witness* aw, const Pair_iterator& lh)
- : aw_(aw), lh_(lh) {
- is_end_ = false;
- if (lh_ == aw_->nearest_landmark_table_.end()) {
- if (aw_->iterator_next_ == aw_->iterator_end_) {
- is_end_ = true;
- } else {
- aw_->nearest_landmark_table_.push_back(*aw_->iterator_next_);
- lh_ = --aw_->nearest_landmark_table_.end();
- ++(aw_->iterator_next_);
- }
- }
- }
-
- private :
- Id_distance_pair& dereference() const {
- return *lh_;
- }
-
- bool equal(const Iterator& other) const {
- return (is_end_ == other.is_end_) || (lh_ == other.lh_);
- }
-
- void increment() {
- // the neighbor search can't be at the end iterator of a list
- GUDHI_CHECK(!is_end_ && lh_ != aw_->nearest_landmark_table_.end(),
- std::logic_error("Wrong active witness increment."));
- // if the id of the current landmark is the same as the last one
-
- lh_++;
- if (lh_ == aw_->nearest_landmark_table_.end()) {
- if (aw_->iterator_next_ == aw_->iterator_end_) {
- is_end_ = true;
- } else {
- aw_->nearest_landmark_table_.push_back(*aw_->iterator_next_);
- lh_ = std::prev(aw_->nearest_landmark_table_.end());
- ++(aw_->iterator_next_);
- }
- }
- }
-};
-
-} // namespace witness_complex
-} // namespace Gudhi
-
-#endif // ACTIVE_WITNESS_ACTIVE_WITNESS_ITERATOR_H_
diff --git a/include/gudhi/Alpha_complex.h b/include/gudhi/Alpha_complex.h
deleted file mode 100644
index 4c07eddb..00000000
--- a/include/gudhi/Alpha_complex.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ALPHA_COMPLEX_H_
-#define ALPHA_COMPLEX_H_
-
-#include <gudhi/Debug_utils.h>
-// to construct Alpha_complex from a OFF file of points
-#include <gudhi/Points_off_io.h>
-
-#include <stdlib.h>
-#include <math.h> // isnan, fmax
-
-#include <CGAL/Delaunay_triangulation.h>
-#include <CGAL/Epick_d.h>
-#include <CGAL/Spatial_sort_traits_adapter_d.h>
-#include <CGAL/property_map.h> // for CGAL::Identity_property_map
-#include <CGAL/NT_converter.h>
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <limits> // NaN
-#include <map>
-#include <utility> // std::pair
-#include <stdexcept>
-#include <numeric> // for std::iota
-
-namespace Gudhi {
-
-namespace alpha_complex {
-
-/**
- * \class Alpha_complex Alpha_complex.h gudhi/Alpha_complex.h
- * \brief Alpha complex data structure.
- *
- * \ingroup alpha_complex
- *
- * \details
- * The data structure is constructing a CGAL Delaunay triangulation (for more informations on CGAL Delaunay
- * triangulation, please refer to the corresponding chapter in page http://doc.cgal.org/latest/Triangulation/) from a
- * range of points or from an OFF file (cf. Points_off_reader).
- *
- * Please refer to \ref alpha_complex for examples.
- *
- * The complex is a template class requiring an Epick_d <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/index.html#Chapter_dD_Geometry_Kernel">dD Geometry Kernel</a>
- * \cite cgal:s-gkd-15b from CGAL as template, default value is <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a>
- * < <a target="_blank" href="http://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Dynamic__dimension__tag.html">
- * CGAL::Dynamic_dimension_tag </a> >
- *
- * \remark When Alpha_complex is constructed with an infinite value of alpha, the complex is a Delaunay complex.
- *
- */
-template<class Kernel = CGAL::Epick_d<CGAL::Dynamic_dimension_tag>>
-class Alpha_complex {
- public:
- // Add an int in TDS to save point index in the structure
- typedef CGAL::Triangulation_data_structure<typename Kernel::Dimension,
- CGAL::Triangulation_vertex<Kernel, std::ptrdiff_t>,
- CGAL::Triangulation_full_cell<Kernel> > TDS;
- /** \brief A Delaunay triangulation of a set of points in \f$ \mathbb{R}^D\f$.*/
- typedef CGAL::Delaunay_triangulation<Kernel, TDS> Delaunay_triangulation;
-
- /** \brief A point in Euclidean space.*/
- typedef typename Kernel::Point_d Point_d;
- /** \brief Geometric traits class that provides the geometric types and predicates needed by Delaunay
- * triangulations.*/
- typedef Kernel Geom_traits;
-
- private:
- typedef typename Kernel::Compute_squared_radius_d Squared_Radius;
- typedef typename Kernel::Side_of_bounded_sphere_d Is_Gabriel;
- typedef typename Kernel::Point_dimension_d Point_Dimension;
-
- // Type required to compute squared radius, or side of bounded sphere on a vector of points.
- typedef typename std::vector<Point_d> Vector_of_CGAL_points;
-
- // Vertex_iterator type from CGAL.
- typedef typename Delaunay_triangulation::Vertex_iterator CGAL_vertex_iterator;
-
- // size_type type from CGAL.
- typedef typename Delaunay_triangulation::size_type size_type;
-
- // Map type to switch from simplex tree vertex handle to CGAL vertex iterator.
- typedef typename std::map< std::size_t, CGAL_vertex_iterator > Vector_vertex_iterator;
-
- private:
- /** \brief Vertex iterator vector to switch from simplex tree vertex handle to CGAL vertex iterator.
- * Vertex handles are inserted sequentially, starting at 0.*/
- Vector_vertex_iterator vertex_handle_to_iterator_;
- /** \brief Pointer on the CGAL Delaunay triangulation.*/
- Delaunay_triangulation* triangulation_;
- /** \brief Kernel for triangulation_ functions access.*/
- Kernel kernel_;
-
- public:
- /** \brief Alpha_complex constructor from an OFF file name.
- *
- * Uses the Points_off_reader to construct the Delaunay triangulation required to initialize
- * the Alpha_complex.
- *
- * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous.
- *
- * @param[in] off_file_name OFF file [path and] name.
- */
- Alpha_complex(const std::string& off_file_name)
- : triangulation_(nullptr) {
- Gudhi::Points_off_reader<Point_d> off_reader(off_file_name);
- if (!off_reader.is_valid()) {
- std::cerr << "Alpha_complex - Unable to read file " << off_file_name << "\n";
- exit(-1); // ----- >>
- }
-
- init_from_range(off_reader.get_point_cloud());
- }
-
- /** \brief Alpha_complex constructor from a list of points.
- *
- * Duplicate points are inserted once in the Alpha_complex. This is the reason why the vertices may be not contiguous.
- *
- * @param[in] points Range of points to triangulate. Points must be in Kernel::Point_d
- *
- * The type InputPointRange must be a range for which std::begin and
- * std::end return input iterators on a Kernel::Point_d.
- */
- template<typename InputPointRange >
- Alpha_complex(const InputPointRange& points)
- : triangulation_(nullptr) {
- init_from_range(points);
- }
-
- /** \brief Alpha_complex destructor deletes the Delaunay triangulation.
- */
- ~Alpha_complex() {
- delete triangulation_;
- }
-
- // Forbid copy/move constructor/assignment operator
- Alpha_complex(const Alpha_complex& other) = delete;
- Alpha_complex& operator= (const Alpha_complex& other) = delete;
- Alpha_complex (Alpha_complex&& other) = delete;
- Alpha_complex& operator= (Alpha_complex&& other) = delete;
-
- /** \brief get_point returns the point corresponding to the vertex given as parameter.
- *
- * @param[in] vertex Vertex handle of the point to retrieve.
- * @return The point found.
- * @exception std::out_of_range In case vertex is not found (cf. std::vector::at).
- */
- const Point_d& get_point(std::size_t vertex) const {
- return vertex_handle_to_iterator_.at(vertex)->point();
- }
-
- /** \brief number_of_vertices returns the number of vertices (same as the number of points).
- *
- * @return The number of vertices.
- */
- std::size_t number_of_vertices() const {
- return vertex_handle_to_iterator_.size();
- }
-
- private:
- template<typename InputPointRange >
- void init_from_range(const InputPointRange& points) {
- auto first = std::begin(points);
- auto last = std::end(points);
-
- if (first != last) {
- // point_dimension function initialization
- Point_Dimension point_dimension = kernel_.point_dimension_d_object();
-
- // Delaunay triangulation is point dimension.
- triangulation_ = new Delaunay_triangulation(point_dimension(*first));
-
- std::vector<Point_d> point_cloud(first, last);
-
- // Creates a vector {0, 1, ..., N-1}
- std::vector<std::ptrdiff_t> indices(boost::counting_iterator<std::ptrdiff_t>(0),
- boost::counting_iterator<std::ptrdiff_t>(point_cloud.size()));
-
- typedef boost::iterator_property_map<typename std::vector<Point_d>::iterator,
- CGAL::Identity_property_map<std::ptrdiff_t>> Point_property_map;
- typedef CGAL::Spatial_sort_traits_adapter_d<Kernel, Point_property_map> Search_traits_d;
-
- CGAL::spatial_sort(indices.begin(), indices.end(), Search_traits_d(std::begin(point_cloud)));
-
- typename Delaunay_triangulation::Full_cell_handle hint;
- for (auto index : indices) {
- typename Delaunay_triangulation::Vertex_handle pos = triangulation_->insert(point_cloud[index], hint);
- // Save index value as data to retrieve it after insertion
- pos->data() = index;
- hint = pos->full_cell();
- }
- // --------------------------------------------------------------------------------------------
- // double map to retrieve simplex tree vertex handles from CGAL vertex iterator and vice versa
- // Loop on triangulation vertices list
- for (CGAL_vertex_iterator vit = triangulation_->vertices_begin(); vit != triangulation_->vertices_end(); ++vit) {
- if (!triangulation_->is_infinite(*vit)) {
-#ifdef DEBUG_TRACES
- std::cout << "Vertex insertion - " << vit->data() << " -> " << vit->point() << std::endl;
-#endif // DEBUG_TRACES
- vertex_handle_to_iterator_.emplace(vit->data(), vit);
- }
- }
- // --------------------------------------------------------------------------------------------
- }
- }
-
- public:
- template <typename SimplicialComplexForAlpha>
- bool create_complex(SimplicialComplexForAlpha& complex) {
- typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value;
- return create_complex(complex, std::numeric_limits<Filtration_value>::infinity());
- }
-
- /** \brief Inserts all Delaunay triangulation into the simplicial complex.
- * It also computes the filtration values accordingly to the \ref createcomplexalgorithm
- *
- * \tparam SimplicialComplexForAlpha must meet `SimplicialComplexForAlpha` concept.
- *
- * @param[in] complex SimplicialComplexForAlpha to be created.
- * @param[in] max_alpha_square maximum for alpha square value. Default value is +\f$\infty\f$.
- *
- * @return true if creation succeeds, false otherwise.
- *
- * @pre Delaunay triangulation must be already constructed with dimension strictly greater than 0.
- * @pre The simplicial complex must be empty (no vertices)
- *
- * Initialization can be launched once.
- */
- template <typename SimplicialComplexForAlpha, typename Filtration_value>
- bool create_complex(SimplicialComplexForAlpha& complex, Filtration_value max_alpha_square) {
- // From SimplicialComplexForAlpha type required to insert into a simplicial complex (with or without subfaces).
- typedef typename SimplicialComplexForAlpha::Vertex_handle Vertex_handle;
- typedef typename SimplicialComplexForAlpha::Simplex_handle Simplex_handle;
- typedef std::vector<Vertex_handle> Vector_vertex;
-
- if (triangulation_ == nullptr) {
- std::cerr << "Alpha_complex cannot create_complex from a NULL triangulation\n";
- return false; // ----- >>
- }
- if (triangulation_->maximal_dimension() < 1) {
- std::cerr << "Alpha_complex cannot create_complex from a zero-dimension triangulation\n";
- return false; // ----- >>
- }
- if (complex.num_vertices() > 0) {
- std::cerr << "Alpha_complex create_complex - complex is not empty\n";
- return false; // ----- >>
- }
-
- // --------------------------------------------------------------------------------------------
- // Simplex_tree construction from loop on triangulation finite full cells list
- if (triangulation_->number_of_vertices() > 0) {
- for (auto cit = triangulation_->finite_full_cells_begin(); cit != triangulation_->finite_full_cells_end(); ++cit) {
- Vector_vertex vertexVector;
-#ifdef DEBUG_TRACES
- std::cout << "Simplex_tree insertion ";
-#endif // DEBUG_TRACES
- for (auto vit = cit->vertices_begin(); vit != cit->vertices_end(); ++vit) {
- if (*vit != nullptr) {
-#ifdef DEBUG_TRACES
- std::cout << " " << (*vit)->data();
-#endif // DEBUG_TRACES
- // Vector of vertex construction for simplex_tree structure
- vertexVector.push_back((*vit)->data());
- }
- }
-#ifdef DEBUG_TRACES
- std::cout << std::endl;
-#endif // DEBUG_TRACES
- // Insert each simplex and its subfaces in the simplex tree - filtration is NaN
- complex.insert_simplex_and_subfaces(vertexVector, std::numeric_limits<double>::quiet_NaN());
- }
- }
- // --------------------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------------------
- // Will be re-used many times
- Vector_of_CGAL_points pointVector;
- // ### For i : d -> 0
- for (int decr_dim = triangulation_->maximal_dimension(); decr_dim >= 0; decr_dim--) {
- // ### Foreach Sigma of dim i
- for (Simplex_handle f_simplex : complex.skeleton_simplex_range(decr_dim)) {
- int f_simplex_dim = complex.dimension(f_simplex);
- if (decr_dim == f_simplex_dim) {
- pointVector.clear();
-#ifdef DEBUG_TRACES
- std::cout << "Sigma of dim " << decr_dim << " is";
-#endif // DEBUG_TRACES
- for (auto vertex : complex.simplex_vertex_range(f_simplex)) {
- pointVector.push_back(get_point(vertex));
-#ifdef DEBUG_TRACES
- std::cout << " " << vertex;
-#endif // DEBUG_TRACES
- }
-#ifdef DEBUG_TRACES
- std::cout << std::endl;
-#endif // DEBUG_TRACES
- // ### If filt(Sigma) is NaN : filt(Sigma) = alpha(Sigma)
- if (std::isnan(complex.filtration(f_simplex))) {
- Filtration_value alpha_complex_filtration = 0.0;
- // No need to compute squared_radius on a single point - alpha is 0.0
- if (f_simplex_dim > 0) {
- // squared_radius function initialization
- Squared_Radius squared_radius = kernel_.compute_squared_radius_d_object();
- CGAL::NT_converter<typename Geom_traits::FT, Filtration_value> cv;
-
- alpha_complex_filtration = cv(squared_radius(pointVector.begin(), pointVector.end()));
- }
- complex.assign_filtration(f_simplex, alpha_complex_filtration);
-#ifdef DEBUG_TRACES
- std::cout << "filt(Sigma) is NaN : filt(Sigma) =" << complex.filtration(f_simplex) << std::endl;
-#endif // DEBUG_TRACES
- }
- propagate_alpha_filtration(complex, f_simplex, decr_dim);
- }
- }
- }
- // --------------------------------------------------------------------------------------------
-
- // --------------------------------------------------------------------------------------------
- // As Alpha value is an approximation, we have to make filtration non decreasing while increasing the dimension
- complex.make_filtration_non_decreasing();
- // Remove all simplices that have a filtration value greater than max_alpha_square
- complex.prune_above_filtration(max_alpha_square);
- // --------------------------------------------------------------------------------------------
- return true;
- }
-
- private:
- template <typename SimplicialComplexForAlpha, typename Simplex_handle>
- void propagate_alpha_filtration(SimplicialComplexForAlpha& complex, Simplex_handle f_simplex, int decr_dim) {
- // From SimplicialComplexForAlpha type required to assign filtration values.
- typedef typename SimplicialComplexForAlpha::Filtration_value Filtration_value;
-#ifdef DEBUG_TRACES
- typedef typename SimplicialComplexForAlpha::Vertex_handle Vertex_handle;
-#endif // DEBUG_TRACES
-
- // ### Foreach Tau face of Sigma
- for (auto f_boundary : complex.boundary_simplex_range(f_simplex)) {
-#ifdef DEBUG_TRACES
- std::cout << " | --------------------------------------------------\n";
- std::cout << " | Tau ";
- for (auto vertex : complex.simplex_vertex_range(f_boundary)) {
- std::cout << vertex << " ";
- }
- std::cout << "is a face of Sigma\n";
- std::cout << " | isnan(complex.filtration(Tau)=" << std::isnan(complex.filtration(f_boundary)) << std::endl;
-#endif // DEBUG_TRACES
- // ### If filt(Tau) is not NaN
- if (!std::isnan(complex.filtration(f_boundary))) {
- // ### filt(Tau) = fmin(filt(Tau), filt(Sigma))
- Filtration_value alpha_complex_filtration = fmin(complex.filtration(f_boundary),
- complex.filtration(f_simplex));
- complex.assign_filtration(f_boundary, alpha_complex_filtration);
-#ifdef DEBUG_TRACES
- std::cout << " | filt(Tau) = fmin(filt(Tau), filt(Sigma)) = " << complex.filtration(f_boundary) << std::endl;
-#endif // DEBUG_TRACES
- // ### Else
- } else {
- // No need to compute is_gabriel for dimension <= 2
- // i.e. : Sigma = (3,1) => Tau = 1
- if (decr_dim > 1) {
- // insert the Tau points in a vector for is_gabriel function
- Vector_of_CGAL_points pointVector;
-#ifdef DEBUG_TRACES
- Vertex_handle vertexForGabriel = Vertex_handle();
-#endif // DEBUG_TRACES
- for (auto vertex : complex.simplex_vertex_range(f_boundary)) {
- pointVector.push_back(get_point(vertex));
- }
- // Retrieve the Sigma point that is not part of Tau - parameter for is_gabriel function
- Point_d point_for_gabriel;
- for (auto vertex : complex.simplex_vertex_range(f_simplex)) {
- point_for_gabriel = get_point(vertex);
- if (std::find(pointVector.begin(), pointVector.end(), point_for_gabriel) == pointVector.end()) {
-#ifdef DEBUG_TRACES
- // vertex is not found in Tau
- vertexForGabriel = vertex;
-#endif // DEBUG_TRACES
- // No need to continue loop
- break;
- }
- }
- // is_gabriel function initialization
- Is_Gabriel is_gabriel = kernel_.side_of_bounded_sphere_d_object();
- bool is_gab = is_gabriel(pointVector.begin(), pointVector.end(), point_for_gabriel)
- != CGAL::ON_BOUNDED_SIDE;
-#ifdef DEBUG_TRACES
- std::cout << " | Tau is_gabriel(Sigma)=" << is_gab << " - vertexForGabriel=" << vertexForGabriel << std::endl;
-#endif // DEBUG_TRACES
- // ### If Tau is not Gabriel of Sigma
- if (false == is_gab) {
- // ### filt(Tau) = filt(Sigma)
- Filtration_value alpha_complex_filtration = complex.filtration(f_simplex);
- complex.assign_filtration(f_boundary, alpha_complex_filtration);
-#ifdef DEBUG_TRACES
- std::cout << " | filt(Tau) = filt(Sigma) = " << complex.filtration(f_boundary) << std::endl;
-#endif // DEBUG_TRACES
- }
- }
- }
- }
- }
-};
-
-} // namespace alpha_complex
-
-namespace alphacomplex = alpha_complex;
-
-} // namespace Gudhi
-
-#endif // ALPHA_COMPLEX_H_
diff --git a/include/gudhi/Bitmap_cubical_complex.h b/include/gudhi/Bitmap_cubical_complex.h
deleted file mode 100644
index cc19b8b5..00000000
--- a/include/gudhi/Bitmap_cubical_complex.h
+++ /dev/null
@@ -1,582 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BITMAP_CUBICAL_COMPLEX_H_
-#define BITMAP_CUBICAL_COMPLEX_H_
-
-#include <gudhi/Bitmap_cubical_complex_base.h>
-#include <gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h>
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_sort.h>
-#endif
-
-#include <limits>
-#include <utility> // for pair<>
-#include <algorithm> // for sort
-#include <vector>
-#include <numeric> // for iota
-#include <cstddef>
-
-namespace Gudhi {
-
-namespace cubical_complex {
-
-// global variable, was used just for debugging.
-const bool globalDbg = false;
-
-template <typename T>
-class is_before_in_filtration;
-
-/**
- * @brief Cubical complex represented as a bitmap.
- * @ingroup cubical_complex
- * @details This is a Bitmap_cubical_complex class. It joints a functionalities of Bitmap_cubical_complex_base and
- * Bitmap_cubical_complex_periodic_boundary_conditions_base classes into
- * Gudhi persistent homology engine. It is a template class that inherit from its template parameter. The template
- * parameter is supposed to be either Bitmap_cubical_complex_base or
- * Bitmap_cubical_complex_periodic_boundary_conditions_base class.
- **/
-template <typename T>
-class Bitmap_cubical_complex : public T {
- public:
- //*********************************************//
- // Typedefs and typenames
- //*********************************************//
- typedef std::size_t Simplex_key;
- typedef typename T::filtration_type Filtration_value;
- typedef Simplex_key Simplex_handle;
-
- //*********************************************//
- // Constructors
- //*********************************************//
- // Over here we need to define various input types. I am proposing the following ones:
- // Perseus style
- // TODO(PD) H5 files?
- // TODO(PD) binary files with little endiangs / big endians ?
- // TODO(PD) constructor from a vector of elements of a type T. ?
-
- /**
- * Constructor form a Perseus-style file.
- **/
- Bitmap_cubical_complex(const char* perseus_style_file)
- : T(perseus_style_file), key_associated_to_simplex(this->total_number_of_cells + 1) {
- if (globalDbg) {
- std::cerr << "Bitmap_cubical_complex( const char* perseus_style_file )\n";
- }
- for (std::size_t i = 0; i != this->total_number_of_cells; ++i) {
- this->key_associated_to_simplex[i] = i;
- }
- // we initialize this only once, in each constructor, when the bitmap is constructed.
- // If the user decide to change some elements of the bitmap, then this procedure need
- // to be called again.
- this->initialize_simplex_associated_to_key();
- }
-
- /**
- * Constructor that requires vector of elements of type unsigned, which gives number of top dimensional cells
- * in the following directions and vector of element of a type T
- * with filtration on top dimensional cells.
- **/
- Bitmap_cubical_complex(const std::vector<unsigned>& dimensions,
- const std::vector<Filtration_value>& top_dimensional_cells)
- : T(dimensions, top_dimensional_cells), key_associated_to_simplex(this->total_number_of_cells + 1) {
- for (std::size_t i = 0; i != this->total_number_of_cells; ++i) {
- this->key_associated_to_simplex[i] = i;
- }
- // we initialize this only once, in each constructor, when the bitmap is constructed.
- // If the user decide to change some elements of the bitmap, then this procedure need
- // to be called again.
- this->initialize_simplex_associated_to_key();
- }
-
- /**
- * Constructor that requires vector of elements of type unsigned, which gives number of top dimensional cells
- * in the following directions and vector of element of a type Filtration_value
- * with filtration on top dimensional cells. The last parameter of the constructor is a vector of boolean of a length
- * equal to the dimension of cubical complex.
- * If the position i on this vector is true, then we impose periodic boundary conditions in this direction.
- **/
- Bitmap_cubical_complex(const std::vector<unsigned>& dimensions,
- const std::vector<Filtration_value>& top_dimensional_cells,
- std::vector<bool> directions_in_which_periodic_b_cond_are_to_be_imposed)
- : T(dimensions, top_dimensional_cells, directions_in_which_periodic_b_cond_are_to_be_imposed),
- key_associated_to_simplex(this->total_number_of_cells + 1) {
- for (std::size_t i = 0; i != this->total_number_of_cells; ++i) {
- this->key_associated_to_simplex[i] = i;
- }
- // we initialize this only once, in each constructor, when the bitmap is constructed.
- // If the user decide to change some elements of the bitmap, then this procedure need
- // to be called again.
- this->initialize_simplex_associated_to_key();
- }
-
- /**
- * Destructor of the Bitmap_cubical_complex class.
- **/
- virtual ~Bitmap_cubical_complex() {}
-
- //*********************************************//
- // Other 'easy' functions
- //*********************************************//
-
- /**
- * Returns number of all cubes in the complex.
- **/
- std::size_t num_simplices() const { return this->total_number_of_cells; }
-
- /**
- * Returns a Simplex_handle to a cube that do not exist in this complex.
- **/
- static Simplex_handle null_simplex() {
- if (globalDbg) {
- std::cerr << "Simplex_handle null_simplex()\n";
- }
- return std::numeric_limits<Simplex_handle>::max();
- }
-
- /**
- * Returns dimension of the complex.
- **/
- inline std::size_t dimension() const { return this->sizes.size(); }
-
- /**
- * Return dimension of a cell pointed by the Simplex_handle.
- **/
- inline unsigned dimension(Simplex_handle sh) const {
- if (globalDbg) {
- std::cerr << "unsigned dimension(const Simplex_handle& sh)\n";
- }
- if (sh != null_simplex()) return this->get_dimension_of_a_cell(sh);
- return -1;
- }
-
- /**
- * Return the filtration of a cell pointed by the Simplex_handle.
- **/
- Filtration_value filtration(Simplex_handle sh) {
- if (globalDbg) {
- std::cerr << "Filtration_value filtration(const Simplex_handle& sh)\n";
- }
- // Returns the filtration value of a simplex.
- if (sh != null_simplex()) return this->data[sh];
- return std::numeric_limits<Filtration_value>::infinity();
- }
-
- /**
- * Return a key which is not a key of any cube in the considered data structure.
- **/
- static Simplex_key null_key() {
- if (globalDbg) {
- std::cerr << "Simplex_key null_key()\n";
- }
- return std::numeric_limits<Simplex_handle>::max();
- }
-
- /**
- * Return the key of a cube pointed by the Simplex_handle.
- **/
- Simplex_key key(Simplex_handle sh) const {
- if (globalDbg) {
- std::cerr << "Simplex_key key(const Simplex_handle& sh)\n";
- }
- if (sh != null_simplex()) {
- return this->key_associated_to_simplex[sh];
- }
- return this->null_key();
- }
-
- /**
- * Return the Simplex_handle given the key of the cube.
- **/
- Simplex_handle simplex(Simplex_key key) {
- if (globalDbg) {
- std::cerr << "Simplex_handle simplex(Simplex_key key)\n";
- }
- if (key != null_key()) {
- return this->simplex_associated_to_key[key];
- }
- return null_simplex();
- }
-
- /**
- * Assign key to a cube pointed by the Simplex_handle
- **/
- void assign_key(Simplex_handle sh, Simplex_key key) {
- if (globalDbg) {
- std::cerr << "void assign_key(Simplex_handle& sh, Simplex_key key)\n";
- }
- if (key == null_key()) return;
- this->key_associated_to_simplex[sh] = key;
- this->simplex_associated_to_key[key] = sh;
- }
-
- /**
- * Function called from a constructor. It is needed for Filtration_simplex_iterator to work.
- **/
- void initialize_simplex_associated_to_key();
-
- //*********************************************//
- // Iterators
- //*********************************************//
-
- /**
- * Boundary_simplex_range class provides ranges for boundary iterators.
- **/
- typedef typename std::vector<Simplex_handle>::iterator Boundary_simplex_iterator;
- typedef typename std::vector<Simplex_handle> Boundary_simplex_range;
-
- /**
- * Filtration_simplex_iterator class provides an iterator though the whole structure in the order of filtration.
- * Secondary criteria for filtration are:
- * (1) Dimension of a cube (lower dimensional comes first).
- * (2) Position in the data structure (the ones that are earlies in the data structure comes first).
- **/
- class Filtration_simplex_range;
-
- class Filtration_simplex_iterator : std::iterator<std::input_iterator_tag, Simplex_handle> {
- // Iterator over all simplices of the complex in the order of the indexing scheme.
- // 'value_type' must be 'Simplex_handle'.
- public:
- Filtration_simplex_iterator(Bitmap_cubical_complex* b) : b(b), position(0) {}
-
- Filtration_simplex_iterator() : b(NULL), position(0) {}
-
- Filtration_simplex_iterator operator++() {
- if (globalDbg) {
- std::cerr << "Filtration_simplex_iterator operator++\n";
- }
- ++this->position;
- return (*this);
- }
-
- Filtration_simplex_iterator operator++(int) {
- Filtration_simplex_iterator result = *this;
- ++(*this);
- return result;
- }
-
- Filtration_simplex_iterator& operator=(const Filtration_simplex_iterator& rhs) {
- if (globalDbg) {
- std::cerr << "Filtration_simplex_iterator operator =\n";
- }
- this->b = rhs.b;
- this->position = rhs.position;
- return (*this);
- }
-
- bool operator==(const Filtration_simplex_iterator& rhs) const {
- if (globalDbg) {
- std::cerr << "bool operator == ( const Filtration_simplex_iterator& rhs )\n";
- }
- return (this->position == rhs.position);
- }
-
- bool operator!=(const Filtration_simplex_iterator& rhs) const {
- if (globalDbg) {
- std::cerr << "bool operator != ( const Filtration_simplex_iterator& rhs )\n";
- }
- return !(*this == rhs);
- }
-
- Simplex_handle operator*() {
- if (globalDbg) {
- std::cerr << "Simplex_handle operator*()\n";
- }
- return this->b->simplex_associated_to_key[this->position];
- }
-
- friend class Filtration_simplex_range;
-
- private:
- Bitmap_cubical_complex<T>* b;
- std::size_t position;
- };
-
- /**
- * @brief Filtration_simplex_range provides the ranges for Filtration_simplex_iterator.
- **/
- class Filtration_simplex_range {
- // Range over the simplices of the complex in the order of the filtration.
- // .begin() and .end() return type Filtration_simplex_iterator.
- public:
- typedef Filtration_simplex_iterator const_iterator;
- typedef Filtration_simplex_iterator iterator;
-
- Filtration_simplex_range(Bitmap_cubical_complex<T>* b) : b(b) {}
-
- Filtration_simplex_iterator begin() {
- if (globalDbg) {
- std::cerr << "Filtration_simplex_iterator begin() \n";
- }
- return Filtration_simplex_iterator(this->b);
- }
-
- Filtration_simplex_iterator end() {
- if (globalDbg) {
- std::cerr << "Filtration_simplex_iterator end()\n";
- }
- Filtration_simplex_iterator it(this->b);
- it.position = this->b->simplex_associated_to_key.size();
- return it;
- }
-
- private:
- Bitmap_cubical_complex<T>* b;
- };
-
- //*********************************************//
- // Methods to access iterators from the container:
-
- /**
- * boundary_simplex_range creates an object of a Boundary_simplex_range class
- * that provides ranges for the Boundary_simplex_iterator.
- **/
- Boundary_simplex_range boundary_simplex_range(Simplex_handle sh) { return this->get_boundary_of_a_cell(sh); }
-
- /**
- * filtration_simplex_range creates an object of a Filtration_simplex_range class
- * that provides ranges for the Filtration_simplex_iterator.
- **/
- Filtration_simplex_range filtration_simplex_range() {
- if (globalDbg) {
- std::cerr << "Filtration_simplex_range filtration_simplex_range()\n";
- }
- // Returns a range over the simplices of the complex in the order of the filtration
- return Filtration_simplex_range(this);
- }
- //*********************************************//
-
- //*********************************************//
- // Elements which are in Gudhi now, but I (and in all the cases I asked also Marc) do not understand why they are
- // there.
- // TODO(PD) the file IndexingTag.h in the Gudhi library contains an empty structure, so
- // I understand that this is something that was planned (for simplicial maps?)
- // but was never finished. The only idea I have here is to use the same empty structure from
- // IndexingTag.h file, but only if the compiler needs it. If the compiler
- // do not need it, then I would rather not add here elements which I do not understand.
- // typedef Indexing_tag
-
- /**
- * Function needed for compatibility with Gudhi. Not useful for other purposes.
- **/
- std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
- std::vector<std::size_t> bdry = this->get_boundary_of_a_cell(sh);
- if (globalDbg) {
- std::cerr << "std::pair<Simplex_handle, Simplex_handle> endpoints( Simplex_handle sh )\n";
- std::cerr << "bdry.size() : " << bdry.size() << "\n";
- }
- // this method returns two first elements from the boundary of sh.
- if (bdry.size() < 2)
- throw(
- "Error in endpoints in Bitmap_cubical_complex class. The cell have less than two elements in the "
- "boundary.");
- return std::make_pair(bdry[0], bdry[1]);
- }
-
- /**
- * Class needed for compatibility with Gudhi. Not useful for other purposes.
- **/
- class Skeleton_simplex_range;
-
- class Skeleton_simplex_iterator : std::iterator<std::input_iterator_tag, Simplex_handle> {
- // Iterator over all simplices of the complex in the order of the indexing scheme.
- // 'value_type' must be 'Simplex_handle'.
- public:
- Skeleton_simplex_iterator(Bitmap_cubical_complex* b, std::size_t d) : b(b), dimension(d) {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_iterator ( Bitmap_cubical_complex* b , std::size_t d )\n";
- }
- // find the position of the first simplex of a dimension d
- this->position = 0;
- while ((this->position != b->data.size()) &&
- (this->b->get_dimension_of_a_cell(this->position) != this->dimension)) {
- ++this->position;
- }
- }
-
- Skeleton_simplex_iterator() : b(NULL), position(0), dimension(0) {}
-
- Skeleton_simplex_iterator operator++() {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_iterator operator++()\n";
- }
- // increment the position as long as you did not get to the next element of the dimension dimension.
- ++this->position;
- while ((this->position != this->b->data.size()) &&
- (this->b->get_dimension_of_a_cell(this->position) != this->dimension)) {
- ++this->position;
- }
- return (*this);
- }
-
- Skeleton_simplex_iterator operator++(int) {
- Skeleton_simplex_iterator result = *this;
- ++(*this);
- return result;
- }
-
- Skeleton_simplex_iterator& operator=(const Skeleton_simplex_iterator& rhs) {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_iterator operator =\n";
- }
- this->b = rhs.b;
- this->position = rhs.position;
- this->dimension = rhs.dimension;
- return (*this);
- }
-
- bool operator==(const Skeleton_simplex_iterator& rhs) const {
- if (globalDbg) {
- std::cerr << "bool operator ==\n";
- }
- return (this->position == rhs.position);
- }
-
- bool operator!=(const Skeleton_simplex_iterator& rhs) const {
- if (globalDbg) {
- std::cerr << "bool operator != ( const Skeleton_simplex_iterator& rhs )\n";
- }
- return !(*this == rhs);
- }
-
- Simplex_handle operator*() {
- if (globalDbg) {
- std::cerr << "Simplex_handle operator*() \n";
- }
- return this->position;
- }
-
- friend class Skeleton_simplex_range;
-
- private:
- Bitmap_cubical_complex<T>* b;
- std::size_t position;
- unsigned dimension;
- };
-
- /**
- * @brief Class needed for compatibility with Gudhi. Not useful for other purposes.
- **/
- class Skeleton_simplex_range {
- // Range over the simplices of the complex in the order of the filtration.
- // .begin() and .end() return type Filtration_simplex_iterator.
- public:
- typedef Skeleton_simplex_iterator const_iterator;
- typedef Skeleton_simplex_iterator iterator;
-
- Skeleton_simplex_range(Bitmap_cubical_complex<T>* b, unsigned dimension) : b(b), dimension(dimension) {}
-
- Skeleton_simplex_iterator begin() {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_iterator begin()\n";
- }
- return Skeleton_simplex_iterator(this->b, this->dimension);
- }
-
- Skeleton_simplex_iterator end() {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_iterator end()\n";
- }
- Skeleton_simplex_iterator it(this->b, this->dimension);
- it.position = this->b->data.size();
- return it;
- }
-
- private:
- Bitmap_cubical_complex<T>* b;
- unsigned dimension;
- };
-
- /**
- * Function needed for compatibility with Gudhi. Not useful for other purposes.
- **/
- Skeleton_simplex_range skeleton_simplex_range(unsigned dimension) {
- if (globalDbg) {
- std::cerr << "Skeleton_simplex_range skeleton_simplex_range( unsigned dimension )\n";
- }
- return Skeleton_simplex_range(this, dimension);
- }
-
- friend class is_before_in_filtration<T>;
-
- protected:
- std::vector<std::size_t> key_associated_to_simplex;
- std::vector<std::size_t> simplex_associated_to_key;
-}; // Bitmap_cubical_complex
-
-template <typename T>
-void Bitmap_cubical_complex<T>::initialize_simplex_associated_to_key() {
- if (globalDbg) {
- std::cerr << "void Bitmap_cubical_complex<T>::initialize_elements_ordered_according_to_filtration() \n";
- }
- this->simplex_associated_to_key = std::vector<std::size_t>(this->data.size());
- std::iota(std::begin(simplex_associated_to_key), std::end(simplex_associated_to_key), 0);
-#ifdef GUDHI_USE_TBB
- tbb::parallel_sort(simplex_associated_to_key.begin(), simplex_associated_to_key.end(),
- is_before_in_filtration<T>(this));
-#else
- std::sort(simplex_associated_to_key.begin(), simplex_associated_to_key.end(), is_before_in_filtration<T>(this));
-#endif
-
- // we still need to deal here with a key_associated_to_simplex:
- for (std::size_t i = 0; i != simplex_associated_to_key.size(); ++i) {
- this->key_associated_to_simplex[simplex_associated_to_key[i]] = i;
- }
-}
-
-template <typename T>
-class is_before_in_filtration {
- public:
- explicit is_before_in_filtration(Bitmap_cubical_complex<T>* CC) : CC_(CC) {}
-
- bool operator()(const typename Bitmap_cubical_complex<T>::Simplex_handle& sh1,
- const typename Bitmap_cubical_complex<T>::Simplex_handle& sh2) const {
- // Not using st_->filtration(sh1) because it uselessly tests for null_simplex.
- typedef typename T::filtration_type Filtration_value;
- Filtration_value fil1 = CC_->data[sh1];
- Filtration_value fil2 = CC_->data[sh2];
- if (fil1 != fil2) {
- return fil1 < fil2;
- }
- // in this case they are on the same filtration level, so the dimension decide.
- std::size_t dim1 = CC_->get_dimension_of_a_cell(sh1);
- std::size_t dim2 = CC_->get_dimension_of_a_cell(sh2);
- if (dim1 != dim2) {
- return dim1 < dim2;
- }
- // in this case both filtration and dimensions of the considered cubes are the same. To have stable sort, we simply
- // compare their positions in the bitmap:
- return sh1 < sh2;
- }
-
- protected:
- Bitmap_cubical_complex<T>* CC_;
-};
-
-} // namespace cubical_complex
-
-namespace Cubical_complex = cubical_complex;
-
-} // namespace Gudhi
-
-#endif // BITMAP_CUBICAL_COMPLEX_H_
diff --git a/include/gudhi/Bitmap_cubical_complex/counter.h b/include/gudhi/Bitmap_cubical_complex/counter.h
deleted file mode 100644
index f82d4cc3..00000000
--- a/include/gudhi/Bitmap_cubical_complex/counter.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BITMAP_CUBICAL_COMPLEX_COUNTER_H_
-#define BITMAP_CUBICAL_COMPLEX_COUNTER_H_
-
-#include <iostream>
-#include <vector>
-#include <cstddef>
-
-namespace Gudhi {
-
-namespace cubical_complex {
-
-/**
- * @brief This is an implementation of a counter being a vector of integers.
- * @details The constructor of the class takes as an input two vectors W and V.
- * It assumes that W < V coordinatewise.
- * If the initial counter W is not specified, it is assumed to be vector of zeros.
- * The class allows to iterate between W and V by using increment() function.
- * The increment() function returns a bool value.
- * The current counter reach the end counter V if the value returned by the increment function is FALSE.
- * This class is needed for the implementation of a bitmapCubicalComplex.
- **/
-class counter {
- public:
- /**
- * Constructor of a counter class. It takes only the parameter which is the end value of the counter.
- * The default beginning value is a vector of the same length as the endd, filled-in with zeros.
- **/
- counter(const std::vector<unsigned>& endd) : begin(endd.size(), 0), end(endd), current(endd.size(), 0) { }
-
- /**
- * Constructor of a counter class. It takes as the input beginn and end vector.
- * It assumes that begin vector is lexicographically below the end vector.
- **/
- counter(const std::vector< unsigned >& beginn, const std::vector< unsigned >& endd) : begin(beginn), end(endd), current(endd.size(), 0) {
- if (beginn.size() != endd.size())
- throw "In constructor of a counter, begin and end vectors do not have the same size. Program terminate";
- }
-
- /**
- * Function to increment the counter. If the value returned by the function is true,
- * then the incrementation process was successful.
- * If the value of the function is false, that means, that the counter have reached its end-value.
- **/
- bool increment() {
- std::size_t i = 0;
- while ((i != this->end.size()) && (this->current[i] == this->end[i])) {
- ++i;
- }
-
- if (i == this->end.size())return false;
- ++this->current[i];
- for (std::size_t j = 0; j != i; ++j) {
- this->current[j] = this->begin[j];
- }
- return true;
- }
-
- /**
- * Function to check if we are at the end of counter.
- **/
- bool isFinal() {
- for (std::size_t i = 0; i != this->current.size(); ++i) {
- if (this->current[i] == this->end[i])return true;
- }
- return false;
- }
-
- /**
- * Function required in the implementation of bitmapCubicalComplexWPeriodicBoundaryCondition.
- * Its aim is to find an counter corresponding to the element the following
- * boundary element is identified with when periodic boundary conditions are imposed.
- **/
- std::vector< unsigned > find_opposite(const std::vector< bool >& directionsForPeriodicBCond) {
- std::vector< unsigned > result;
- for (std::size_t i = 0; i != this->current.size(); ++i) {
- if ((this->current[i] == this->end[i]) && (directionsForPeriodicBCond[i] == true)) {
- result.push_back(this->begin[i]);
- } else {
- result.push_back(this->current[i]);
- }
- }
- return result;
- }
-
- /**
- * Function checking at which positions the current value of a counter is the final value of the counter.
- **/
- std::vector< bool > directions_of_finals() {
- std::vector< bool > result;
- for (std::size_t i = 0; i != this->current.size(); ++i) {
- if (this->current[i] == this->end[i]) {
- result.push_back(true);
- } else {
- result.push_back(false);
- }
- }
- return result;
- }
-
- /**
- * Function to write counter to the stream.
- **/
- friend std::ostream& operator<<(std::ostream& out, const counter& c) {
- // std::cerr << "c.current.size() : " << c.current.size() << endl;
- for (std::size_t i = 0; i != c.current.size(); ++i) {
- out << c.current[i] << " ";
- }
- return out;
- }
-
- private:
- std::vector< unsigned > begin;
- std::vector< unsigned > end;
- std::vector< unsigned > current;
-};
-
-} // namespace cubical_complex
-
-namespace Cubical_complex = cubical_complex;
-
-} // namespace Gudhi
-
-#endif // BITMAP_CUBICAL_COMPLEX_COUNTER_H_
diff --git a/include/gudhi/Bitmap_cubical_complex_base.h b/include/gudhi/Bitmap_cubical_complex_base.h
deleted file mode 100644
index 9b74e267..00000000
--- a/include/gudhi/Bitmap_cubical_complex_base.h
+++ /dev/null
@@ -1,854 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BITMAP_CUBICAL_COMPLEX_BASE_H_
-#define BITMAP_CUBICAL_COMPLEX_BASE_H_
-
-#include <gudhi/Bitmap_cubical_complex/counter.h>
-
-#include <iostream>
-#include <vector>
-#include <string>
-#include <fstream>
-#include <algorithm>
-#include <iterator>
-#include <limits>
-#include <utility>
-#include <stdexcept>
-#include <cstddef>
-
-namespace Gudhi {
-
-namespace cubical_complex {
-
-/**
- * @brief Cubical complex represented as a bitmap, class with basic implementation.
- * @ingroup cubical_complex
- * @details This is a class implementing a basic bitmap data structure to store cubical complexes.
- * It implements only the most basic subroutines.
- * The idea of the bitmap is the following. Our aim is to have a memory efficient
- * data structure to store d-dimensional cubical complex
- * C being a cubical decomposition
- * of a rectangular region of a space. This is achieved by storing C as a
- * vector of bits (this is where the name 'bitmap' came from).
- * Each cell is represented by a single
- * bit (in case of black and white bitmaps, or by a single element of a type T
- * (here T is a filtration type of a bitmap, typically a double).
- * All the informations needed for homology and
- * persistent homology computations (like dimension of a cell, boundary and
- * coboundary elements of a cell, are then obtained from the
- * position of the element in C.
- * The default filtration used in this implementation is the lower star filtration.
- */
-template <typename T>
-class Bitmap_cubical_complex_base {
- public:
- typedef T filtration_type;
-
- /**
- *Default constructor
- **/
- Bitmap_cubical_complex_base() : total_number_of_cells(0) {}
- /**
- * There are a few constructors of a Bitmap_cubical_complex_base class.
- * First one, that takes vector<unsigned>, creates an empty bitmap of a dimension equal
- * the number of elements in the
- * input vector and size in the i-th dimension equal the number in the position i-of the input vector.
- */
- Bitmap_cubical_complex_base(const std::vector<unsigned>& sizes);
- /**
- * The second constructor takes as a input a Perseus style file. For more details,
- * please consult the documentations of
- * Perseus software as well as examples attached to this
- * implementation.
- **/
- Bitmap_cubical_complex_base(const char* perseus_style_file);
- /**
- * The last constructor of a Bitmap_cubical_complex_base class accepts vector of dimensions (as the first one)
- * together with vector of filtration values of top dimensional cells.
- **/
- Bitmap_cubical_complex_base(const std::vector<unsigned>& dimensions, const std::vector<T>& top_dimensional_cells);
-
- /**
- * Destructor of the Bitmap_cubical_complex_base class.
- **/
- virtual ~Bitmap_cubical_complex_base() {}
-
- /**
- * The functions get_boundary_of_a_cell, get_coboundary_of_a_cell, get_dimension_of_a_cell
- * and get_cell_data are the basic
- * functions that compute boundary / coboundary / dimension and the filtration
- * value form a position of a cell in the structure of a bitmap. The input parameter of all of those function is a
- * non-negative integer, indicating a position of a cube in the data structure.
- * In the case of functions that compute (co)boundary, the output is a vector if non-negative integers pointing to
- * the positions of (co)boundary element of the input cell.
- * The boundary elements are guaranteed to be returned so that the
- * incidence coefficients of boundary elements are alternating.
- */
- virtual inline std::vector<std::size_t> get_boundary_of_a_cell(std::size_t cell) const;
- /**
- * The functions get_coboundary_of_a_cell, get_coboundary_of_a_cell,
- * get_dimension_of_a_cell and get_cell_data are the basic
- * functions that compute boundary / coboundary / dimension and the filtration
- * value form a position of a cell in the structure of a bitmap.
- * The input parameter of all of those function is a non-negative integer,
- * indicating a position of a cube in the data structure.
- * In the case of functions that compute (co)boundary, the output is a vector if
- * non-negative integers pointing to the
- * positions of (co)boundary element of the input cell.
- * Note that unlike in the case of boundary, over here the elements are
- * not guaranteed to be returned with alternating incidence numbers.
- *
- **/
- virtual inline std::vector<std::size_t> get_coboundary_of_a_cell(std::size_t cell) const;
-
- /**
- * This procedure compute incidence numbers between cubes. For a cube \f$A\f$ of
- * dimension n and a cube \f$B \subset A\f$ of dimension n-1, an incidence
- * between \f$A\f$ and \f$B\f$ is the integer with which \f$B\f$ appears in the boundary of \f$A\f$.
- * Note that first parameter is a cube of dimension n,
- * and the second parameter is an adjusted cube in dimension n-1.
- * Given \f$A = [b_1,e_1] \times \ldots \ [b_{j-1},e_{j-1}] \times [b_{j},e_{j}] \times [b_{j+1},e_{j+1}] \times \ldots
- *\times [b_{n},e_{n}] \f$
- * such that \f$ b_{j} \neq e_{j} \f$
- * and \f$B = [b_1,e_1] \times \ldots \ [b_{j-1},e_{j-1}] \times [a,a] \times [b_{j+1},e_{j+1}] \times \ldots \times
- *[b_{n},e_{n}] \f$
- * where \f$ a = b_{j}\f$ or \f$ a = e_{j}\f$, the incidence between \f$A\f$ and \f$B\f$
- * computed by this procedure is given by formula:
- * \f$ c\ (-1)^{\sum_{i=1}^{j-1} dim [b_{i},e_{i}]} \f$
- * Where \f$ dim [b_{i},e_{i}] = 0 \f$ if \f$ b_{i}=e_{i} \f$ and 1 in other case.
- * c is -1 if \f$ a = b_{j}\f$ and 1 if \f$ a = e_{j}\f$.
- * @exception std::logic_error In case when the cube \f$B\f$ is not n-1
- * dimensional face of a cube \f$A\f$.
- **/
- virtual int compute_incidence_between_cells(std::size_t coface, std::size_t face) const {
- // first get the counters for coface and face:
- std::vector<unsigned> coface_counter = this->compute_counter_for_given_cell(coface);
- std::vector<unsigned> face_counter = this->compute_counter_for_given_cell(face);
-
- // coface_counter and face_counter should agree at all positions except from one:
- int number_of_position_in_which_counters_do_not_agree = -1;
- std::size_t number_of_full_faces_that_comes_before = 0;
- for (std::size_t i = 0; i != coface_counter.size(); ++i) {
- if ((coface_counter[i] % 2 == 1) && (number_of_position_in_which_counters_do_not_agree == -1)) {
- ++number_of_full_faces_that_comes_before;
- }
- if (coface_counter[i] != face_counter[i]) {
- if (number_of_position_in_which_counters_do_not_agree != -1) {
- std::cout << "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.\n";
- throw std::logic_error(
- "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.");
- }
- number_of_position_in_which_counters_do_not_agree = i;
- }
- }
-
- int incidence = 1;
- if (number_of_full_faces_that_comes_before % 2) incidence = -1;
- // if the face cell is on the right from coface cell:
- if (coface_counter[number_of_position_in_which_counters_do_not_agree] + 1 ==
- face_counter[number_of_position_in_which_counters_do_not_agree]) {
- incidence *= -1;
- }
-
- return incidence;
- }
-
- /**
-* In the case of get_dimension_of_a_cell function, the output is a non-negative integer
-* indicating the dimension of a cell.
-* Note that unlike in the case of boundary, over here the elements are
-* not guaranteed to be returned with alternating incidence numbers.
-* To compute incidence between cells use compute_incidence_between_cells
-* procedure
-**/
- inline unsigned get_dimension_of_a_cell(std::size_t cell) const;
-
- /**
- * In the case of get_cell_data, the output parameter is a reference to the value of a cube in a given position.
- * This allows reading and changing the value of filtration. Note that if the value of a filtration is changed, the
- * code do not check if we have a filtration or not. i.e. it do not check if the value of a filtration of a cell is
- * not smaller than the value of a filtration of its boundary and not greater than the value of its coboundary.
- **/
- inline T& get_cell_data(std::size_t cell);
-
- /**
- * Typical input used to construct a baseBitmap class is a filtration given at the top dimensional cells.
- * Then, there are a few ways one can pick the filtration of lower dimensional
- * cells. The most typical one is by so called lower star filtration. This function is always called by any
- * constructor which takes the top dimensional cells. If you use such a constructor,
- * then there is no need to call this function. Call it only if you are putting the filtration
- * of the cells by your own (for instance by using Top_dimensional_cells_iterator).
- **/
- void impose_lower_star_filtration(); // assume that top dimensional cells are already set.
-
- /**
- * Returns dimension of a complex.
- **/
- inline unsigned dimension() const { return sizes.size(); }
-
- /**
- * Returns number of all cubes in the data structure.
- **/
- inline unsigned size() const { return this->data.size(); }
-
- /**
- * Writing to stream operator. By using it we get the values T of cells in order in which they are stored in the
- * structure. This procedure is used for debugging purposes.
- **/
- template <typename K>
- friend std::ostream& operator<<(std::ostream& os, const Bitmap_cubical_complex_base<K>& b);
-
- /**
- * Function that put the input data to bins. By putting data to bins we mean rounding them to a sequence of values
- * equally distributed in the range of data.
- * Sometimes if most of the cells have different birth-death times, the performance of the algorithms to compute
- * persistence gets worst. When dealing with this type of data, one may want to put different values on cells to
- * some number of bins. The function put_data_to_bins( std::size_t number_of_bins ) is designed for that purpose.
- * The parameter of the function is the number of bins (distinct values) we want to have in the cubical complex.
- **/
- void put_data_to_bins(std::size_t number_of_bins);
-
- /**
- * Function that put the input data to bins. By putting data to bins we mean rounding them to a sequence of values
- * equally distributed in the range of data.
- * Sometimes if most of the cells have different birth-death times, the performance of the algorithms to compute
- * persistence gets worst. When dealing with this type of data, one may want to put different values on cells to
- * some number of bins. The function put_data_to_bins( T diameter_of_bin ) is designed for that purpose.
- * The parameter of it is the diameter of each bin. Note that the bottleneck distance between the persistence
- * diagram of the cubical complex before and after using such a function will be bounded by the parameter
- * diameter_of_bin.
- **/
- void put_data_to_bins(T diameter_of_bin);
-
- /**
- * Functions to find min and max values of filtration.
- **/
- std::pair<T, T> min_max_filtration();
-
- // ITERATORS
-
- /**
- * @brief Iterator through all cells in the complex (in order they appear in the structure -- i.e.
- * in lexicographical order).
- **/
- class All_cells_iterator : std::iterator<std::input_iterator_tag, T> {
- public:
- All_cells_iterator() { this->counter = 0; }
-
- All_cells_iterator operator++() {
- // first find first element of the counter that can be increased:
- ++this->counter;
- return *this;
- }
-
- All_cells_iterator operator++(int) {
- All_cells_iterator result = *this;
- ++(*this);
- return result;
- }
-
- All_cells_iterator& operator=(const All_cells_iterator& rhs) {
- this->counter = rhs.counter;
- return *this;
- }
-
- bool operator==(const All_cells_iterator& rhs) const {
- if (this->counter != rhs.counter) return false;
- return true;
- }
-
- bool operator!=(const All_cells_iterator& rhs) const { return !(*this == rhs); }
-
- /*
- * The operator * returns position of a cube in the structure of cubical complex. This position can be then used as
- * an argument of the following functions:
- * get_boundary_of_a_cell, get_coboundary_of_a_cell, get_dimension_of_a_cell to get information about the cell
- * boundary and coboundary and dimension
- * and in function get_cell_data to get a filtration of a cell.
- */
- std::size_t operator*() { return this->counter; }
- friend class Bitmap_cubical_complex_base;
-
- protected:
- std::size_t counter;
- };
-
- /**
- * Function returning a All_cells_iterator to the first cell of the bitmap.
- **/
- All_cells_iterator all_cells_iterator_begin() {
- All_cells_iterator a;
- return a;
- }
-
- /**
- * Function returning a All_cells_iterator to the last cell of the bitmap.
- **/
- All_cells_iterator all_cells_iterator_end() {
- All_cells_iterator a;
- a.counter = this->data.size();
- return a;
- }
-
- /**
- * @brief All_cells_range class provides ranges for All_cells_iterator
- **/
- class All_cells_range {
- public:
- All_cells_range(Bitmap_cubical_complex_base* b) : b(b) {}
-
- All_cells_iterator begin() { return b->all_cells_iterator_begin(); }
-
- All_cells_iterator end() { return b->all_cells_iterator_end(); }
-
- private:
- Bitmap_cubical_complex_base<T>* b;
- };
-
- All_cells_range all_cells_range() { return All_cells_range(this); }
-
- /**
- * Boundary_range class provides ranges for boundary iterators.
- **/
- typedef typename std::vector<std::size_t>::const_iterator Boundary_iterator;
- typedef typename std::vector<std::size_t> Boundary_range;
-
- /**
- * boundary_simplex_range creates an object of a Boundary_simplex_range class
- * that provides ranges for the Boundary_simplex_iterator.
- **/
- Boundary_range boundary_range(std::size_t sh) { return this->get_boundary_of_a_cell(sh); }
-
- /**
- * Coboundary_range class provides ranges for boundary iterators.
- **/
- typedef typename std::vector<std::size_t>::const_iterator Coboundary_iterator;
- typedef typename std::vector<std::size_t> Coboundary_range;
-
- /**
- * boundary_simplex_range creates an object of a Boundary_simplex_range class
- * that provides ranges for the Boundary_simplex_iterator.
- **/
- Coboundary_range coboundary_range(std::size_t sh) { return this->get_coboundary_of_a_cell(sh); }
-
- /**
- * @brief Iterator through top dimensional cells of the complex. The cells appear in order they are stored
- * in the structure (i.e. in lexicographical order)
- **/
- class Top_dimensional_cells_iterator : std::iterator<std::input_iterator_tag, T> {
- public:
- Top_dimensional_cells_iterator(Bitmap_cubical_complex_base& b) : b(b) {
- this->counter = std::vector<std::size_t>(b.dimension());
- // std::fill( this->counter.begin() , this->counter.end() , 0 );
- }
-
- Top_dimensional_cells_iterator operator++() {
- // first find first element of the counter that can be increased:
- std::size_t dim = 0;
- while ((dim != this->b.dimension()) && (this->counter[dim] == this->b.sizes[dim] - 1)) ++dim;
-
- if (dim != this->b.dimension()) {
- ++this->counter[dim];
- for (std::size_t i = 0; i != dim; ++i) {
- this->counter[i] = 0;
- }
- } else {
- ++this->counter[0];
- }
- return *this;
- }
-
- Top_dimensional_cells_iterator operator++(int) {
- Top_dimensional_cells_iterator result = *this;
- ++(*this);
- return result;
- }
-
- Top_dimensional_cells_iterator& operator=(const Top_dimensional_cells_iterator& rhs) {
- this->counter = rhs.counter;
- this->b = rhs.b;
- return *this;
- }
-
- bool operator==(const Top_dimensional_cells_iterator& rhs) const {
- if (&this->b != &rhs.b) return false;
- if (this->counter.size() != rhs.counter.size()) return false;
- for (std::size_t i = 0; i != this->counter.size(); ++i) {
- if (this->counter[i] != rhs.counter[i]) return false;
- }
- return true;
- }
-
- bool operator!=(const Top_dimensional_cells_iterator& rhs) const { return !(*this == rhs); }
-
- /*
- * The operator * returns position of a cube in the structure of cubical complex. This position can be then used as
- * an argument of the following functions:
- * get_boundary_of_a_cell, get_coboundary_of_a_cell, get_dimension_of_a_cell to get information about the cell
- * boundary and coboundary and dimension
- * and in function get_cell_data to get a filtration of a cell.
- */
- std::size_t operator*() { return this->compute_index_in_bitmap(); }
-
- std::size_t compute_index_in_bitmap() const {
- std::size_t index = 0;
- for (std::size_t i = 0; i != this->counter.size(); ++i) {
- index += (2 * this->counter[i] + 1) * this->b.multipliers[i];
- }
- return index;
- }
-
- void print_counter() const {
- for (std::size_t i = 0; i != this->counter.size(); ++i) {
- std::cout << this->counter[i] << " ";
- }
- }
- friend class Bitmap_cubical_complex_base;
-
- protected:
- std::vector<std::size_t> counter;
- Bitmap_cubical_complex_base& b;
- };
-
- /**
- * Function returning a Top_dimensional_cells_iterator to the first top dimensional cell of the bitmap.
- **/
- Top_dimensional_cells_iterator top_dimensional_cells_iterator_begin() {
- Top_dimensional_cells_iterator a(*this);
- return a;
- }
-
- /**
- * Function returning a Top_dimensional_cells_iterator to the last top dimensional cell of the bitmap.
- **/
- Top_dimensional_cells_iterator top_dimensional_cells_iterator_end() {
- Top_dimensional_cells_iterator a(*this);
- for (std::size_t i = 0; i != this->dimension(); ++i) {
- a.counter[i] = this->sizes[i] - 1;
- }
- a.counter[0]++;
- return a;
- }
-
- /**
- * @brief Top_dimensional_cells_iterator_range class provides ranges for Top_dimensional_cells_iterator_range
- **/
- class Top_dimensional_cells_range {
- public:
- Top_dimensional_cells_range(Bitmap_cubical_complex_base* b) : b(b) {}
-
- Top_dimensional_cells_iterator begin() { return b->top_dimensional_cells_iterator_begin(); }
-
- Top_dimensional_cells_iterator end() { return b->top_dimensional_cells_iterator_end(); }
-
- private:
- Bitmap_cubical_complex_base<T>* b;
- };
-
- Top_dimensional_cells_range top_dimensional_cells_range() { return Top_dimensional_cells_range(this); }
-
- //****************************************************************************************************************//
- //****************************************************************************************************************//
- //****************************************************************************************************************//
- //****************************************************************************************************************//
-
- inline std::size_t number_cells() const { return this->total_number_of_cells; }
-
- //****************************************************************************************************************//
- //****************************************************************************************************************//
- //****************************************************************************************************************//
- //****************************************************************************************************************//
-
- protected:
- std::vector<unsigned> sizes;
- std::vector<unsigned> multipliers;
- std::vector<T> data;
- std::size_t total_number_of_cells;
-
- void set_up_containers(const std::vector<unsigned>& sizes) {
- unsigned multiplier = 1;
- for (std::size_t i = 0; i != sizes.size(); ++i) {
- this->sizes.push_back(sizes[i]);
- this->multipliers.push_back(multiplier);
- multiplier *= 2 * sizes[i] + 1;
- }
- this->data = std::vector<T>(multiplier, std::numeric_limits<T>::infinity());
- this->total_number_of_cells = multiplier;
- }
-
- std::size_t compute_position_in_bitmap(const std::vector<unsigned>& counter) {
- std::size_t position = 0;
- for (std::size_t i = 0; i != this->multipliers.size(); ++i) {
- position += this->multipliers[i] * counter[i];
- }
- return position;
- }
-
- std::vector<unsigned> compute_counter_for_given_cell(std::size_t cell) const {
- std::vector<unsigned> counter;
- counter.reserve(this->sizes.size());
- for (std::size_t dim = this->sizes.size(); dim != 0; --dim) {
- counter.push_back(cell / this->multipliers[dim - 1]);
- cell = cell % this->multipliers[dim - 1];
- }
- std::reverse(counter.begin(), counter.end());
- return counter;
- }
- void read_perseus_style_file(const char* perseus_style_file);
- void setup_bitmap_based_on_top_dimensional_cells_list(const std::vector<unsigned>& sizes_in_following_directions,
- const std::vector<T>& top_dimensional_cells);
- Bitmap_cubical_complex_base(const char* perseus_style_file, std::vector<bool> directions);
- Bitmap_cubical_complex_base(const std::vector<unsigned>& sizes, std::vector<bool> directions);
- Bitmap_cubical_complex_base(const std::vector<unsigned>& dimensions, const std::vector<T>& top_dimensional_cells,
- std::vector<bool> directions);
-};
-
-template <typename T>
-void Bitmap_cubical_complex_base<T>::put_data_to_bins(std::size_t number_of_bins) {
- bool dbg = false;
-
- std::pair<T, T> min_max = this->min_max_filtration();
- T dx = (min_max.second - min_max.first) / (T)number_of_bins;
-
- // now put the data into the appropriate bins:
- for (std::size_t i = 0; i != this->data.size(); ++i) {
- if (dbg) {
- std::cerr << "Before binning : " << this->data[i] << std::endl;
- }
- this->data[i] = min_max.first + dx * (this->data[i] - min_max.first) / number_of_bins;
- if (dbg) {
- std::cerr << "After binning : " << this->data[i] << std::endl;
- }
- }
-}
-
-template <typename T>
-void Bitmap_cubical_complex_base<T>::put_data_to_bins(T diameter_of_bin) {
- bool dbg = false;
- std::pair<T, T> min_max = this->min_max_filtration();
-
- std::size_t number_of_bins = (min_max.second - min_max.first) / diameter_of_bin;
- // now put the data into the appropriate bins:
- for (std::size_t i = 0; i != this->data.size(); ++i) {
- if (dbg) {
- std::cerr << "Before binning : " << this->data[i] << std::endl;
- }
- this->data[i] = min_max.first + diameter_of_bin * (this->data[i] - min_max.first) / number_of_bins;
- if (dbg) {
- std::cerr << "After binning : " << this->data[i] << std::endl;
- }
- }
-}
-
-template <typename T>
-std::pair<T, T> Bitmap_cubical_complex_base<T>::min_max_filtration() {
- std::pair<T, T> min_max(std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity());
- for (std::size_t i = 0; i != this->data.size(); ++i) {
- if (this->data[i] < min_max.first) min_max.first = this->data[i];
- if (this->data[i] > min_max.second) min_max.second = this->data[i];
- }
- return min_max;
-}
-
-template <typename K>
-std::ostream& operator<<(std::ostream& out, const Bitmap_cubical_complex_base<K>& b) {
- for (typename Bitmap_cubical_complex_base<K>::all_cells_const_iterator it = b.all_cells_const_begin();
- it != b.all_cells_const_end(); ++it) {
- out << *it << " ";
- }
- return out;
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const std::vector<unsigned>& sizes) {
- this->set_up_containers(sizes);
-}
-
-template <typename T>
-void Bitmap_cubical_complex_base<T>::setup_bitmap_based_on_top_dimensional_cells_list(
- const std::vector<unsigned>& sizes_in_following_directions, const std::vector<T>& top_dimensional_cells) {
- this->set_up_containers(sizes_in_following_directions);
-
- std::size_t number_of_top_dimensional_elements = 1;
- for (std::size_t i = 0; i != sizes_in_following_directions.size(); ++i) {
- number_of_top_dimensional_elements *= sizes_in_following_directions[i];
- }
- if (number_of_top_dimensional_elements != top_dimensional_cells.size()) {
- std::cerr << "Error in constructor Bitmap_cubical_complex_base ( std::vector<std::size_t> "
- << "sizes_in_following_directions, std::vector<T> top_dimensional_cells ). Number of top dimensional "
- << "elements that follow from sizes_in_following_directions vector is different than the size of "
- << "top_dimensional_cells vector."
- << std::endl;
- throw(
- "Error in constructor Bitmap_cubical_complex_base( std::vector<std::size_t> sizes_in_following_directions,"
- "std::vector<T> top_dimensional_cells ). Number of top dimensional elements that follow from "
- "sizes_in_following_directions vector is different than the size of top_dimensional_cells vector.");
- }
-
- Bitmap_cubical_complex_base<T>::Top_dimensional_cells_iterator it(*this);
- std::size_t index = 0;
- for (it = this->top_dimensional_cells_iterator_begin(); it != this->top_dimensional_cells_iterator_end(); ++it) {
- this->get_cell_data(*it) = top_dimensional_cells[index];
- ++index;
- }
- this->impose_lower_star_filtration();
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const std::vector<unsigned>& sizes_in_following_directions,
- const std::vector<T>& top_dimensional_cells) {
- this->setup_bitmap_based_on_top_dimensional_cells_list(sizes_in_following_directions, top_dimensional_cells);
-}
-
-template <typename T>
-void Bitmap_cubical_complex_base<T>::read_perseus_style_file(const char* perseus_style_file) {
- bool dbg = false;
- std::ifstream inFiltration;
- inFiltration.open(perseus_style_file);
- unsigned dimensionOfData;
- inFiltration >> dimensionOfData;
-
- if (dbg) {
- std::cerr << "dimensionOfData : " << dimensionOfData << std::endl;
- }
-
- std::vector<unsigned> sizes;
- sizes.reserve(dimensionOfData);
- // all dimensions multiplied
- std::size_t dimensions = 1;
- for (std::size_t i = 0; i != dimensionOfData; ++i) {
- unsigned size_in_this_dimension;
- inFiltration >> size_in_this_dimension;
- sizes.push_back(size_in_this_dimension);
- dimensions *= size_in_this_dimension;
- if (dbg) {
- std::cerr << "size_in_this_dimension : " << size_in_this_dimension << std::endl;
- }
- }
- this->set_up_containers(sizes);
-
- Bitmap_cubical_complex_base<T>::Top_dimensional_cells_iterator it(*this);
- it = this->top_dimensional_cells_iterator_begin();
-
- T filtrationLevel;
- for (std::size_t i = 0; i < dimensions; ++i) {
- if (!(inFiltration >> filtrationLevel) || (inFiltration.eof())) {
- throw std::ios_base::failure("Bad Perseus file format.");
- }
- if (dbg) {
- std::cerr << "Cell of an index : " << it.compute_index_in_bitmap()
- << " and dimension: " << this->get_dimension_of_a_cell(it.compute_index_in_bitmap())
- << " get the value : " << filtrationLevel << std::endl;
- }
- this->get_cell_data(*it) = filtrationLevel;
- ++it;
- }
-
- inFiltration.close();
- this->impose_lower_star_filtration();
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const char* perseus_style_file,
- std::vector<bool> directions) {
- // this constructor is here just for compatibility with a class that creates cubical complexes with periodic boundary
- // conditions.
- // It ignores the last parameter of the function.
- this->read_perseus_style_file(perseus_style_file);
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const std::vector<unsigned>& sizes,
- std::vector<bool> directions) {
- // this constructor is here just for compatibility with a class that creates cubical complexes with periodic boundary
- // conditions.
- // It ignores the last parameter of the function.
- this->set_up_containers(sizes);
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const std::vector<unsigned>& dimensions,
- const std::vector<T>& top_dimensional_cells,
- std::vector<bool> directions) {
- // this constructor is here just for compatibility with a class that creates cubical complexes with periodic boundary
- // conditions.
- // It ignores the last parameter of the function.
- this->setup_bitmap_based_on_top_dimensional_cells_list(dimensions, top_dimensional_cells);
-}
-
-template <typename T>
-Bitmap_cubical_complex_base<T>::Bitmap_cubical_complex_base(const char* perseus_style_file) {
- this->read_perseus_style_file(perseus_style_file);
-}
-
-template <typename T>
-std::vector<std::size_t> Bitmap_cubical_complex_base<T>::get_boundary_of_a_cell(std::size_t cell) const {
- std::vector<std::size_t> boundary_elements;
-
- // Speed traded of for memory. Check if it is better in practice.
- boundary_elements.reserve(this->dimension() * 2);
-
- std::size_t sum_of_dimensions = 0;
- std::size_t cell1 = cell;
- for (std::size_t i = this->multipliers.size(); i != 0; --i) {
- unsigned position = cell1 / this->multipliers[i - 1];
- if (position % 2 == 1) {
- if (sum_of_dimensions % 2) {
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- } else {
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- }
- ++sum_of_dimensions;
- }
- cell1 = cell1 % this->multipliers[i - 1];
- }
-
- return boundary_elements;
-}
-
-template <typename T>
-std::vector<std::size_t> Bitmap_cubical_complex_base<T>::get_coboundary_of_a_cell(std::size_t cell) const {
- std::vector<unsigned> counter = this->compute_counter_for_given_cell(cell);
- std::vector<std::size_t> coboundary_elements;
- std::size_t cell1 = cell;
- for (std::size_t i = this->multipliers.size(); i != 0; --i) {
- unsigned position = cell1 / this->multipliers[i - 1];
- if (position % 2 == 0) {
- if ((cell > this->multipliers[i - 1]) && (counter[i - 1] != 0)) {
- coboundary_elements.push_back(cell - this->multipliers[i - 1]);
- }
- if ((cell + this->multipliers[i - 1] < this->data.size()) && (counter[i - 1] != 2 * this->sizes[i - 1])) {
- coboundary_elements.push_back(cell + this->multipliers[i - 1]);
- }
- }
- cell1 = cell1 % this->multipliers[i - 1];
- }
- return coboundary_elements;
-}
-
-template <typename T>
-unsigned Bitmap_cubical_complex_base<T>::get_dimension_of_a_cell(std::size_t cell) const {
- bool dbg = false;
- if (dbg) std::cerr << "\n\n\n Computing position o a cell of an index : " << cell << std::endl;
- unsigned dimension = 0;
- for (std::size_t i = this->multipliers.size(); i != 0; --i) {
- unsigned position = cell / this->multipliers[i - 1];
-
- if (dbg) {
- std::cerr << "i-1 :" << i - 1 << std::endl;
- std::cerr << "cell : " << cell << std::endl;
- std::cerr << "position : " << position << std::endl;
- std::cerr << "multipliers[" << i - 1 << "] = " << this->multipliers[i - 1] << std::endl;
- }
-
- if (position % 2 == 1) {
- if (dbg) std::cerr << "Nonzero length in this direction \n";
- dimension++;
- }
- cell = cell % this->multipliers[i - 1];
- }
- return dimension;
-}
-
-template <typename T>
-inline T& Bitmap_cubical_complex_base<T>::get_cell_data(std::size_t cell) {
- return this->data[cell];
-}
-
-template <typename T>
-void Bitmap_cubical_complex_base<T>::impose_lower_star_filtration() {
- bool dbg = false;
-
- // this vector will be used to check which elements have already been taken care of in imposing lower star filtration
- std::vector<bool> is_this_cell_considered(this->data.size(), false);
-
- std::size_t size_to_reserve = 1;
- for (std::size_t i = 0; i != this->multipliers.size(); ++i) {
- size_to_reserve *= (std::size_t)((this->multipliers[i] - 1) / 2);
- }
-
- std::vector<std::size_t> indices_to_consider;
- indices_to_consider.reserve(size_to_reserve);
- // we assume here that we already have a filtration on the top dimensional cells and
- // we have to extend it to lower ones.
- typename Bitmap_cubical_complex_base<T>::Top_dimensional_cells_iterator it(*this);
- for (it = this->top_dimensional_cells_iterator_begin(); it != this->top_dimensional_cells_iterator_end(); ++it) {
- indices_to_consider.push_back(it.compute_index_in_bitmap());
- }
-
- while (indices_to_consider.size()) {
- if (dbg) {
- std::cerr << "indices_to_consider in this iteration \n";
- for (std::size_t i = 0; i != indices_to_consider.size(); ++i) {
- std::cout << indices_to_consider[i] << " ";
- }
- }
- std::vector<std::size_t> new_indices_to_consider;
- for (std::size_t i = 0; i != indices_to_consider.size(); ++i) {
- std::vector<std::size_t> bd = this->get_boundary_of_a_cell(indices_to_consider[i]);
- for (std::size_t boundaryIt = 0; boundaryIt != bd.size(); ++boundaryIt) {
- if (dbg) {
- std::cerr << "filtration of a cell : " << bd[boundaryIt] << " is : " << this->data[bd[boundaryIt]]
- << " while of a cell: " << indices_to_consider[i] << " is: " << this->data[indices_to_consider[i]]
- << std::endl;
- }
- if (this->data[bd[boundaryIt]] > this->data[indices_to_consider[i]]) {
- this->data[bd[boundaryIt]] = this->data[indices_to_consider[i]];
- if (dbg) {
- std::cerr << "Setting the value of a cell : " << bd[boundaryIt]
- << " to : " << this->data[indices_to_consider[i]] << std::endl;
- }
- }
- if (is_this_cell_considered[bd[boundaryIt]] == false) {
- new_indices_to_consider.push_back(bd[boundaryIt]);
- is_this_cell_considered[bd[boundaryIt]] = true;
- }
- }
- }
- indices_to_consider.swap(new_indices_to_consider);
- }
-}
-
-template <typename T>
-bool compareFirstElementsOfTuples(const std::pair<std::pair<T, std::size_t>, char>& first,
- const std::pair<std::pair<T, std::size_t>, char>& second) {
- if (first.first.first < second.first.first) {
- return true;
- } else {
- if (first.first.first > second.first.first) {
- return false;
- }
- // in this case first.first.first == second.first.first, so we need to compare dimensions
- return first.second < second.second;
- }
-}
-
-} // namespace cubical_complex
-
-namespace Cubical_complex = cubical_complex;
-
-} // namespace Gudhi
-
-#endif // BITMAP_CUBICAL_COMPLEX_BASE_H_
diff --git a/include/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h b/include/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h
deleted file mode 100644
index 8c35f590..00000000
--- a/include/gudhi/Bitmap_cubical_complex_periodic_boundary_conditions_base.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
-#define BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
-
-#include <gudhi/Bitmap_cubical_complex_base.h>
-
-#include <cmath>
-#include <limits> // for numeric_limits<>
-#include <vector>
-#include <stdexcept>
-#include <cstddef>
-
-namespace Gudhi {
-
-namespace cubical_complex {
-
-// in this class, we are storing all the elements which are in normal bitmap (i.e. the bitmap without the periodic
-// boundary conditions). But, we set up the iterators and the procedures to compute boundary and coboundary in the way
-// that it is all right. We assume here that all the cells that are on the left / bottom and so on remains, while all
-// the cells on the right / top are not in the Bitmap_cubical_complex_periodic_boundary_conditions_base
-
-/**
- * @brief Cubical complex with periodic boundary conditions represented as a bitmap.
- * @ingroup cubical_complex
- * @details This is a class implementing a bitmap data structure with periodic boundary conditions. Most of the
- * functions are
- * identical to the functions from Bitmap_cubical_complex_base.
- * The ones that needed to be updated are the constructors and get_boundary_of_a_cell and get_coboundary_of_a_cell.
- */
-template <typename T>
-class Bitmap_cubical_complex_periodic_boundary_conditions_base : public Bitmap_cubical_complex_base<T> {
- public:
- // constructors that take an extra parameter:
-
- /**
- * Default constructor of Bitmap_cubical_complex_periodic_boundary_conditions_base class.
- */
- Bitmap_cubical_complex_periodic_boundary_conditions_base() {}
- /**
- * A constructor of Bitmap_cubical_complex_periodic_boundary_conditions_base class that takes the following
- * parameters: (1) vector with numbers of top dimensional cells in all dimensions and (2) vector of booleans. If
- * at i-th position of this vector there is true value, that means that periodic boundary conditions are to be
- * imposed in this direction. In case of false, the periodic boundary conditions will not be imposed in the direction
- * i.
- */
- Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& sizes,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
- /**
- * A constructor of Bitmap_cubical_complex_periodic_boundary_conditions_base class that takes the name of Perseus
- * style file as an input. Please consult the documentation about the specification of the file.
- */
- Bitmap_cubical_complex_periodic_boundary_conditions_base(const char* perseusStyleFile);
- /**
- * A constructor of Bitmap_cubical_complex_periodic_boundary_conditions_base class that takes the following
- * parameters: (1) vector with numbers of top dimensional cells in all dimensions and (2) vector of top dimensional
- * cells (ordered lexicographically) and (3) vector of booleans. If at i-th position of this vector there is true
- * value, that means that periodic boundary conditions are to be imposed in this direction. In case of false, the
- * periodic boundary conditions will not be imposed in the direction i.
- */
- Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
-
- /**
- * Destructor of the Bitmap_cubical_complex_periodic_boundary_conditions_base class.
- **/
- virtual ~Bitmap_cubical_complex_periodic_boundary_conditions_base() {}
-
- // overwritten methods co compute boundary and coboundary
- /**
- * A version of a function that return boundary of a given cell for an object of
- * Bitmap_cubical_complex_periodic_boundary_conditions_base class.
- * The boundary elements are guaranteed to be returned so that the
- * incidence coefficients are alternating.
- */
- virtual std::vector<std::size_t> get_boundary_of_a_cell(std::size_t cell) const;
-
- /**
- * A version of a function that return coboundary of a given cell for an object of
- * Bitmap_cubical_complex_periodic_boundary_conditions_base class.
- * Note that unlike in the case of boundary, over here the elements are
- * not guaranteed to be returned with alternating incidence numbers.
- * To compute incidence between cells use compute_incidence_between_cells
- * procedure
- */
- virtual std::vector<std::size_t> get_coboundary_of_a_cell(std::size_t cell) const;
-
- /**
- * This procedure compute incidence numbers between cubes. For a cube \f$A\f$ of
- * dimension n and a cube \f$B \subset A\f$ of dimension n-1, an incidence
- * between \f$A\f$ and \f$B\f$ is the integer with which \f$B\f$ appears in the boundary of \f$A\f$.
- * Note that first parameter is a cube of dimension n,
- * and the second parameter is an adjusted cube in dimension n-1.
- * Given \f$A = [b_1,e_1] \times \ldots \ [b_{j-1},e_{j-1}] \times [b_{j},e_{j}] \times [b_{j+1},e_{j+1}] \times \ldots
- *\times [b_{n},e_{n}] \f$
- * such that \f$ b_{j} \neq e_{j} \f$
- * and \f$B = [b_1,e_1] \times \ldots \ [b_{j-1},e_{j-1}] \times [a,a] \times [b_{j+1},e_{j+1}] \times \ldots \times
- *[b_{n},e_{n}]s \f$
- * where \f$ a = b_{j}\f$ or \f$ a = e_{j}\f$, the incidence between \f$A\f$ and \f$B\f$
- * computed by this procedure is given by formula:
- * \f$ c\ (-1)^{\sum_{i=1}^{j-1} dim [b_{i},e_{i}]} \f$
- * Where \f$ dim [b_{i},e_{i}] = 0 \f$ if \f$ b_{i}=e_{i} \f$ and 1 in other case.
- * c is -1 if \f$ a = b_{j}\f$ and 1 if \f$ a = e_{j}\f$.
- * @exception std::logic_error In case when the cube \f$B\f$ is not n-1
- * dimensional face of a cube \f$A\f$.
- **/
- virtual int compute_incidence_between_cells(std::size_t coface, std::size_t face) {
- // first get the counters for coface and face:
- std::vector<unsigned> coface_counter = this->compute_counter_for_given_cell(coface);
- std::vector<unsigned> face_counter = this->compute_counter_for_given_cell(face);
-
- // coface_counter and face_counter should agree at all positions except from one:
- int number_of_position_in_which_counters_do_not_agree = -1;
- std::size_t number_of_full_faces_that_comes_before = 0;
- for (std::size_t i = 0; i != coface_counter.size(); ++i) {
- if ((coface_counter[i] % 2 == 1) && (number_of_position_in_which_counters_do_not_agree == -1)) {
- ++number_of_full_faces_that_comes_before;
- }
- if (coface_counter[i] != face_counter[i]) {
- if (number_of_position_in_which_counters_do_not_agree != -1) {
- std::cout << "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.\n";
- throw std::logic_error(
- "Cells given to compute_incidence_between_cells procedure do not form a pair of coface-face.");
- }
- number_of_position_in_which_counters_do_not_agree = i;
- }
- }
-
- int incidence = 1;
- if (number_of_full_faces_that_comes_before % 2) incidence = -1;
- // if the face cell is on the right from coface cell:
- if ((coface_counter[number_of_position_in_which_counters_do_not_agree] + 1 ==
- face_counter[number_of_position_in_which_counters_do_not_agree]) ||
- ((coface_counter[number_of_position_in_which_counters_do_not_agree] != 1) &&
- (face_counter[number_of_position_in_which_counters_do_not_agree] == 0))) {
- incidence *= -1;
- }
-
- return incidence;
- }
-
- protected:
- std::vector<bool> directions_in_which_periodic_b_cond_are_to_be_imposed;
-
- void set_up_containers(const std::vector<unsigned>& sizes) {
- unsigned multiplier = 1;
- for (std::size_t i = 0; i != sizes.size(); ++i) {
- this->sizes.push_back(sizes[i]);
- this->multipliers.push_back(multiplier);
-
- if (directions_in_which_periodic_b_cond_are_to_be_imposed[i]) {
- multiplier *= 2 * sizes[i];
- } else {
- multiplier *= 2 * sizes[i] + 1;
- }
- }
- // std::reverse( this->sizes.begin() , this->sizes.end() );
- this->data = std::vector<T>(multiplier, std::numeric_limits<T>::infinity());
- this->total_number_of_cells = multiplier;
- }
- Bitmap_cubical_complex_periodic_boundary_conditions_base(const std::vector<unsigned>& sizes);
- Bitmap_cubical_complex_periodic_boundary_conditions_base(const std::vector<unsigned>& dimensions,
- const std::vector<T>& topDimensionalCells);
-
- /**
- * A procedure used to construct the data structures in the class.
- **/
- void construct_complex_based_on_top_dimensional_cells(
- const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed);
-};
-
-template <typename T>
-void Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::construct_complex_based_on_top_dimensional_cells(
- const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
- this->directions_in_which_periodic_b_cond_are_to_be_imposed = directions_in_which_periodic_b_cond_are_to_be_imposed;
- this->set_up_containers(dimensions);
-
- std::size_t i = 0;
- for (auto it = this->top_dimensional_cells_iterator_begin(); it != this->top_dimensional_cells_iterator_end(); ++it) {
- this->get_cell_data(*it) = topDimensionalCells[i];
- ++i;
- }
- this->impose_lower_star_filtration();
-}
-
-template <typename T>
-Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& sizes,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
- this->directions_in_which_periodic_b_cond_are_to_be_imposed(directions_in_which_periodic_b_cond_are_to_be_imposed);
- this->set_up_containers(sizes);
-}
-
-template <typename T>
-Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const char* perseus_style_file) {
- // for Perseus style files:
- bool dbg = false;
-
- std::ifstream inFiltration;
- inFiltration.open(perseus_style_file);
- unsigned dimensionOfData;
- inFiltration >> dimensionOfData;
-
- this->directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(dimensionOfData, false);
-
- std::vector<unsigned> sizes;
- sizes.reserve(dimensionOfData);
- for (std::size_t i = 0; i != dimensionOfData; ++i) {
- int size_in_this_dimension;
- inFiltration >> size_in_this_dimension;
- if (size_in_this_dimension < 0) {
- this->directions_in_which_periodic_b_cond_are_to_be_imposed[i] = true;
- }
- sizes.push_back(abs(size_in_this_dimension));
- }
- this->set_up_containers(sizes);
-
- typename Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Top_dimensional_cells_iterator it(*this);
- it = this->top_dimensional_cells_iterator_begin();
-
- while (!inFiltration.eof()) {
- double filtrationLevel;
- inFiltration >> filtrationLevel;
- if (inFiltration.eof()) break;
-
- if (dbg) {
- std::cerr << "Cell of an index : " << it.compute_index_in_bitmap()
- << " and dimension: " << this->get_dimension_of_a_cell(it.compute_index_in_bitmap())
- << " get the value : " << filtrationLevel << std::endl;
- }
- this->get_cell_data(*it) = filtrationLevel;
- ++it;
- }
- inFiltration.close();
- this->impose_lower_star_filtration();
-}
-
-template <typename T>
-Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& sizes) {
- this->directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(sizes.size(), false);
- this->set_up_containers(sizes);
-}
-
-template <typename T>
-Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells) {
- std::vector<bool> directions_in_which_periodic_b_cond_are_to_be_imposed = std::vector<bool>(dimensions.size(), false);
- this->construct_complex_based_on_top_dimensional_cells(dimensions, topDimensionalCells,
- directions_in_which_periodic_b_cond_are_to_be_imposed);
-}
-
-template <typename T>
-Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::Bitmap_cubical_complex_periodic_boundary_conditions_base(
- const std::vector<unsigned>& dimensions, const std::vector<T>& topDimensionalCells,
- const std::vector<bool>& directions_in_which_periodic_b_cond_are_to_be_imposed) {
- this->construct_complex_based_on_top_dimensional_cells(dimensions, topDimensionalCells,
- directions_in_which_periodic_b_cond_are_to_be_imposed);
-}
-
-// ***********************Methods************************ //
-
-template <typename T>
-std::vector<std::size_t> Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::get_boundary_of_a_cell(
- std::size_t cell) const {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Computations of boundary of a cell : " << cell << std::endl;
- }
-
- std::vector<std::size_t> boundary_elements;
- boundary_elements.reserve(this->dimension() * 2);
- std::size_t cell1 = cell;
- std::size_t sum_of_dimensions = 0;
-
- for (std::size_t i = this->multipliers.size(); i != 0; --i) {
- unsigned position = cell1 / this->multipliers[i - 1];
- // this cell have a nonzero length in this direction, therefore we can compute its boundary in this direction.
- if (position % 2 == 1) {
- // if there are no periodic boundary conditions in this direction, we do not have to do anything.
- if (!directions_in_which_periodic_b_cond_are_to_be_imposed[i - 1]) {
- // std::cerr << "A\n";
- if (sum_of_dimensions % 2) {
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- } else {
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- }
- if (dbg) {
- std::cerr << cell - this->multipliers[i - 1] << " " << cell + this->multipliers[i - 1] << " ";
- }
- } else {
- // in this direction we have to do boundary conditions. Therefore, we need to check if we are not at the end.
- if (position != 2 * this->sizes[i - 1] - 1) {
- // std::cerr << "B\n";
- if (sum_of_dimensions % 2) {
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- } else {
- boundary_elements.push_back(cell + this->multipliers[i - 1]);
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- }
- if (dbg) {
- std::cerr << cell - this->multipliers[i - 1] << " " << cell + this->multipliers[i - 1] << " ";
- }
- } else {
- // std::cerr << "C\n";
- if (sum_of_dimensions % 2) {
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- boundary_elements.push_back(cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
- } else {
- boundary_elements.push_back(cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
- boundary_elements.push_back(cell - this->multipliers[i - 1]);
- }
- if (dbg) {
- std::cerr << cell - this->multipliers[i - 1] << " "
- << cell - (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1] << " ";
- }
- }
- }
- ++sum_of_dimensions;
- }
- cell1 = cell1 % this->multipliers[i - 1];
- }
- return boundary_elements;
-}
-
-template <typename T>
-std::vector<std::size_t> Bitmap_cubical_complex_periodic_boundary_conditions_base<T>::get_coboundary_of_a_cell(
- std::size_t cell) const {
- std::vector<unsigned> counter = this->compute_counter_for_given_cell(cell);
- std::vector<std::size_t> coboundary_elements;
- std::size_t cell1 = cell;
- for (std::size_t i = this->multipliers.size(); i != 0; --i) {
- unsigned position = cell1 / this->multipliers[i - 1];
- // if the cell has zero length in this direction, then it will have cbd in this direction.
- if (position % 2 == 0) {
- if (!this->directions_in_which_periodic_b_cond_are_to_be_imposed[i - 1]) {
- // no periodic boundary conditions in this direction
- if ((counter[i - 1] != 0) && (cell > this->multipliers[i - 1])) {
- coboundary_elements.push_back(cell - this->multipliers[i - 1]);
- }
- if ((counter[i - 1] != 2 * this->sizes[i - 1]) && (cell + this->multipliers[i - 1] < this->data.size())) {
- coboundary_elements.push_back(cell + this->multipliers[i - 1]);
- }
- } else {
- // we want to have periodic boundary conditions in this direction
- if (counter[i - 1] != 0) {
- coboundary_elements.push_back(cell - this->multipliers[i - 1]);
- coboundary_elements.push_back(cell + this->multipliers[i - 1]);
- } else {
- // in this case counter[i-1] == 0.
- coboundary_elements.push_back(cell + this->multipliers[i - 1]);
- coboundary_elements.push_back(cell + (2 * this->sizes[i - 1] - 1) * this->multipliers[i - 1]);
- }
- }
- }
-
- cell1 = cell1 % this->multipliers[i - 1];
- }
- return coboundary_elements;
-}
-
-} // namespace cubical_complex
-
-namespace Cubical_complex = cubical_complex;
-
-} // namespace Gudhi
-
-#endif // BITMAP_CUBICAL_COMPLEX_PERIODIC_BOUNDARY_CONDITIONS_BASE_H_
diff --git a/include/gudhi/Bottleneck.h b/include/gudhi/Bottleneck.h
deleted file mode 100644
index 7a553006..00000000
--- a/include/gudhi/Bottleneck.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Francois Godi
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef BOTTLENECK_H_
-#define BOTTLENECK_H_
-
-#include <gudhi/Graph_matching.h>
-
-#include <vector>
-#include <algorithm> // for max
-#include <limits> // for numeric_limits
-
-#include <cmath>
-#include <cfloat> // FLT_EVAL_METHOD
-
-namespace Gudhi {
-
-namespace persistence_diagram {
-
-inline double bottleneck_distance_approx(Persistence_graph& g, double e) {
- double b_lower_bound = 0.;
- double b_upper_bound = g.diameter_bound();
- const double alpha = std::pow(g.size(), 1. / 5.);
- Graph_matching m(g);
- Graph_matching biggest_unperfect(g);
- while (b_upper_bound - b_lower_bound > 2 * e) {
- double step = b_lower_bound + (b_upper_bound - b_lower_bound) / alpha;
-#if !defined FLT_EVAL_METHOD || FLT_EVAL_METHOD < 0 || FLT_EVAL_METHOD > 1
- // On platforms where double computation is done with excess precision,
- // we force it to its true precision so the following test is reliable.
- volatile double drop_excess_precision = step;
- step = drop_excess_precision;
- // Alternative: step = CGAL::IA_force_to_double(step);
-#endif
- if (step <= b_lower_bound || step >= b_upper_bound) // Avoid precision problem
- break;
- m.set_r(step);
- while (m.multi_augment()) {} // compute a maximum matching (in the graph corresponding to the current r)
- if (m.perfect()) {
- m = biggest_unperfect;
- b_upper_bound = step;
- } else {
- biggest_unperfect = m;
- b_lower_bound = step;
- }
- }
- return (b_lower_bound + b_upper_bound) / 2.;
-}
-
-inline double bottleneck_distance_exact(Persistence_graph& g) {
- std::vector<double> sd = g.sorted_distances();
- long lower_bound_i = 0;
- long upper_bound_i = sd.size() - 1;
- const double alpha = std::pow(g.size(), 1. / 5.);
- Graph_matching m(g);
- Graph_matching biggest_unperfect(g);
- while (lower_bound_i != upper_bound_i) {
- long step = lower_bound_i + static_cast<long> ((upper_bound_i - lower_bound_i - 1) / alpha);
- m.set_r(sd.at(step));
- while (m.multi_augment()) {} // compute a maximum matching (in the graph corresponding to the current r)
- if (m.perfect()) {
- m = biggest_unperfect;
- upper_bound_i = step;
- } else {
- biggest_unperfect = m;
- lower_bound_i = step + 1;
- }
- }
- return sd.at(lower_bound_i);
-}
-
-/** \brief Function to compute the Bottleneck distance between two persistence diagrams.
- *
- * \tparam Persistence_diagram1,Persistence_diagram2
- * models of the concept `PersistenceDiagram`.
- * \param[in] e
- * \parblock
- * If `e` is 0, this uses an expensive algorithm to compute the exact distance.
- *
- * If `e` is not 0, it asks for an additive `e`-approximation, and currently
- * also allows a small multiplicative error (the last 2 or 3 bits of the
- * mantissa may be wrong). This version of the algorithm takes advantage of the
- * limited precision of `double` and is usually a lot faster to compute,
- * whatever the value of `e`.
- *
- * Thus, by default, `e` is the smallest positive double.
- * \endparblock
- *
- * \ingroup bottleneck_distance
- */
-template<typename Persistence_diagram1, typename Persistence_diagram2>
-double bottleneck_distance(const Persistence_diagram1 &diag1, const Persistence_diagram2 &diag2,
- double e = (std::numeric_limits<double>::min)()) {
- Persistence_graph g(diag1, diag2, e);
- if (g.bottleneck_alive() == std::numeric_limits<double>::infinity())
- return std::numeric_limits<double>::infinity();
- return (std::max)(g.bottleneck_alive(), e == 0. ? bottleneck_distance_exact(g) : bottleneck_distance_approx(g, e));
-}
-
-} // namespace persistence_diagram
-
-} // namespace Gudhi
-
-#endif // BOTTLENECK_H_
diff --git a/include/gudhi/Cech_complex.h b/include/gudhi/Cech_complex.h
deleted file mode 100644
index f9b8a269..00000000
--- a/include/gudhi/Cech_complex.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2018 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CECH_COMPLEX_H_
-#define CECH_COMPLEX_H_
-
-#include <gudhi/distance_functions.h> // for Gudhi::Minimal_enclosing_ball_radius
-#include <gudhi/graph_simplicial_complex.h> // for Gudhi::Proximity_graph
-#include <gudhi/Debug_utils.h> // for GUDHI_CHECK
-#include <gudhi/Cech_complex_blocker.h> // for Gudhi::cech_complex::Cech_blocker
-
-#include <iostream>
-#include <stdexcept> // for exception management
-#include <vector>
-
-namespace Gudhi {
-
-namespace cech_complex {
-
-/**
- * \class Cech_complex
- * \brief Cech complex data structure.
- *
- * \ingroup cech_complex
- *
- * \details
- * The data structure is a proximity graph, containing edges when the edge length is less or equal
- * to a given max_radius. Edge length is computed from `Gudhi::Minimal_enclosing_ball_radius` distance function.
- *
- * \tparam SimplicialComplexForProximityGraph furnishes `Vertex_handle` and `Filtration_value` type definition required
- * by `Gudhi::Proximity_graph`.
- *
- * \tparam ForwardPointRange must be a range for which `std::begin()` and `std::end()` methods return input
- * iterators on a point. `std::begin()` and `std::end()` methods are also required for a point.
- */
-template <typename SimplicialComplexForProximityGraph, typename ForwardPointRange>
-class Cech_complex {
- private:
- // Required by compute_proximity_graph
- using Vertex_handle = typename SimplicialComplexForProximityGraph::Vertex_handle;
- using Filtration_value = typename SimplicialComplexForProximityGraph::Filtration_value;
- using Proximity_graph = Gudhi::Proximity_graph<SimplicialComplexForProximityGraph>;
-
- // Retrieve Coordinate type from ForwardPointRange
- using Point_from_range_iterator = typename boost::range_const_iterator<ForwardPointRange>::type;
- using Point_from_range = typename std::iterator_traits<Point_from_range_iterator>::value_type;
- using Coordinate_iterator = typename boost::range_const_iterator<Point_from_range>::type;
- using Coordinate = typename std::iterator_traits<Coordinate_iterator>::value_type;
-
- public:
- // Point and Point_cloud type definition
- using Point = std::vector<Coordinate>;
- using Point_cloud = std::vector<Point>;
-
- public:
- /** \brief Cech_complex constructor from a list of points.
- *
- * @param[in] points Range of points.
- * @param[in] max_radius Maximal radius value.
- *
- * \tparam ForwardPointRange must be a range of Point. Point must be a range of <b>copyable</b> Cartesian coordinates.
- *
- */
- Cech_complex(const ForwardPointRange& points, Filtration_value max_radius) : max_radius_(max_radius) {
- // Point cloud deep copy
- point_cloud_.reserve(boost::size(points));
- for (auto&& point : points) point_cloud_.emplace_back(std::begin(point), std::end(point));
-
- cech_skeleton_graph_ = Gudhi::compute_proximity_graph<SimplicialComplexForProximityGraph>(
- point_cloud_, max_radius_, Gudhi::Minimal_enclosing_ball_radius());
- }
-
- /** \brief Initializes the simplicial complex from the proximity graph and expands it until a given maximal
- * dimension, using the Cech blocker oracle.
- *
- * @param[in] complex SimplicialComplexForCech to be created.
- * @param[in] dim_max graph expansion until this given maximal dimension.
- * @exception std::invalid_argument In debug mode, if `complex.num_vertices()` does not return 0.
- *
- */
- template <typename SimplicialComplexForCechComplex>
- void create_complex(SimplicialComplexForCechComplex& complex, int dim_max) {
- GUDHI_CHECK(complex.num_vertices() == 0,
- std::invalid_argument("Cech_complex::create_complex - simplicial complex is not empty"));
-
- // insert the proximity graph in the simplicial complex
- complex.insert_graph(cech_skeleton_graph_);
- // expand the graph until dimension dim_max
- complex.expansion_with_blockers(dim_max,
- Cech_blocker<SimplicialComplexForCechComplex, Cech_complex>(&complex, this));
- }
-
- /** @return max_radius value given at construction. */
- Filtration_value max_radius() const { return max_radius_; }
-
- /** @param[in] vertex Point position in the range.
- * @return The point.
- */
- const Point& get_point(Vertex_handle vertex) const { return point_cloud_[vertex]; }
-
- private:
- Proximity_graph cech_skeleton_graph_;
- Filtration_value max_radius_;
- Point_cloud point_cloud_;
-};
-
-} // namespace cech_complex
-
-} // namespace Gudhi
-
-#endif // CECH_COMPLEX_H_
diff --git a/include/gudhi/Cech_complex_blocker.h b/include/gudhi/Cech_complex_blocker.h
deleted file mode 100644
index b0d347b1..00000000
--- a/include/gudhi/Cech_complex_blocker.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2018 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CECH_COMPLEX_BLOCKER_H_
-#define CECH_COMPLEX_BLOCKER_H_
-
-#include <gudhi/distance_functions.h> // for Gudhi::Minimal_enclosing_ball_radius
-
-#include <iostream>
-#include <vector>
-#include <cmath> // for std::sqrt
-
-namespace Gudhi {
-
-namespace cech_complex {
-
-/** \internal
- * \class Cech_blocker
- * \brief ÄŒech complex blocker.
- *
- * \ingroup cech_complex
- *
- * \details
- * ÄŒech blocker is an oracle constructed from a Cech_complex and a simplicial complex.
- *
- * \tparam SimplicialComplexForProximityGraph furnishes `Simplex_handle` and `Filtration_value` type definition,
- * `simplex_vertex_range(Simplex_handle sh)`and `assign_filtration(Simplex_handle sh, Filtration_value filt)` methods.
- *
- * \tparam Chech_complex is required by the blocker.
- */
-template <typename SimplicialComplexForCech, typename Cech_complex>
-class Cech_blocker {
- private:
- using Point_cloud = typename Cech_complex::Point_cloud;
-
- using Simplex_handle = typename SimplicialComplexForCech::Simplex_handle;
- using Filtration_value = typename SimplicialComplexForCech::Filtration_value;
-
- public:
- /** \internal \brief ÄŒech complex blocker operator() - the oracle - assigns the filtration value from the simplex
- * radius and returns if the simplex expansion must be blocked.
- * \param[in] sh The Simplex_handle.
- * \return true if the simplex radius is greater than the Cech_complex max_radius*/
- bool operator()(Simplex_handle sh) {
- Point_cloud points;
- for (auto vertex : sc_ptr_->simplex_vertex_range(sh)) {
- points.push_back(cc_ptr_->get_point(vertex));
-#ifdef DEBUG_TRACES
- std::cout << "#(" << vertex << ")#";
-#endif // DEBUG_TRACES
- }
- Filtration_value radius = Gudhi::Minimal_enclosing_ball_radius()(points);
-#ifdef DEBUG_TRACES
- if (radius > cc_ptr_->max_radius()) std::cout << "radius > max_radius => expansion is blocked\n";
-#endif // DEBUG_TRACES
- sc_ptr_->assign_filtration(sh, radius);
- return (radius > cc_ptr_->max_radius());
- }
-
- /** \internal \brief ÄŒech complex blocker constructor. */
- Cech_blocker(SimplicialComplexForCech* sc_ptr, Cech_complex* cc_ptr) : sc_ptr_(sc_ptr), cc_ptr_(cc_ptr) {}
-
- private:
- SimplicialComplexForCech* sc_ptr_;
- Cech_complex* cc_ptr_;
-};
-
-} // namespace cech_complex
-
-} // namespace Gudhi
-
-#endif // CECH_COMPLEX_BLOCKER_H_
diff --git a/include/gudhi/Clock.h b/include/gudhi/Clock.h
deleted file mode 100644
index cdf18cb2..00000000
--- a/include/gudhi/Clock.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CLOCK_H_
-#define CLOCK_H_
-
-#include <iostream>
-#include <string>
-#include <chrono>
-
-namespace Gudhi {
-
-class Clock {
- public:
- // Construct and start the timer
- Clock(const std::string& msg_ = std::string())
- : startTime(std::chrono::system_clock::now()),
- end_called(false),
- msg(msg_) { }
-
- // Restart the timer
- void begin() const {
- end_called = false;
- startTime = std::chrono::system_clock::now();
- }
-
- // Stop the timer
- void end() const {
- end_called = true;
- endTime = std::chrono::system_clock::now();
- }
-
- std::string message() const {
- return msg;
- }
-
- // Print current value to std::cout
- void print() const {
- std::cout << *this << std::endl;
- }
-
- friend std::ostream& operator<<(std::ostream& stream, const Clock& clock) {
- if (!clock.msg.empty())
- stream << clock.msg << ": ";
-
- stream << clock.num_seconds() << "s\n";
- return stream;
- }
-
- // Get the number of seconds between the timer start and:
- // - the last call of end() if it was called
- // - or now otherwise. In this case, the timer is not stopped.
- double num_seconds() const {
- if (!end_called) {
- auto end = std::chrono::system_clock::now();
- return std::chrono::duration_cast<std::chrono::milliseconds>(end-startTime).count() / 1000.;
- } else {
- return std::chrono::duration_cast<std::chrono::milliseconds>(endTime-startTime).count() / 1000.;
- }
- }
-
- private:
- mutable std::chrono::time_point<std::chrono::system_clock> startTime, endTime;
- mutable bool end_called;
- std::string msg;
-};
-
-} // namespace Gudhi
-
-#endif // CLOCK_H_
diff --git a/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h b/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h
deleted file mode 100644
index 5a55c513..00000000
--- a/include/gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2006-2011 GeometryFactory (France). All rights reserved.
-//
-// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation; either version 3 of the License,
-// or (at your option) any later version.
-//
-// Licensees holding a valid commercial license may use this file in
-// accordance with the commercial license agreement provided with the software.
-//
-// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
-// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-//
-// $URL$
-// $Id$
-//
-// Author(s) : Fernando Cacciola <fernando.cacciola@geometryfactory.com>
-//
-#ifndef CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_
-#define CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_
-
-#define CGAL_SURFACE_MESH_SIMPLIFICATION_USE_RELAXED_HEAP
-
-#include <boost/optional.hpp>
-#include <boost/pending/relaxed_heap.hpp>
-
-#include <climits> // Neeeded by the following Boost header for CHAR_BIT.
-#include <functional> // for less
-
-namespace CGAL {
-
-template <class IndexedType_, class Compare_ = std::less<IndexedType_>, class ID_ = boost::identity_property_map>
-class Modifiable_priority_queue {
- public:
- typedef Modifiable_priority_queue Self;
-
- typedef IndexedType_ IndexedType;
- typedef Compare_ Compare;
- typedef ID_ ID;
-
- typedef boost::relaxed_heap<IndexedType, Compare, ID> Heap;
- typedef typename Heap::value_type value_type;
- typedef typename Heap::size_type size_type;
-
- typedef bool handle;
-
- public:
- Modifiable_priority_queue(size_type largest_ID, Compare const& c, ID const& id) : mHeap(largest_ID, c, id) { }
-
- handle push(value_type const& v) {
- mHeap.push(v);
- return handle(true);
- }
-
- handle update(value_type const& v, handle h) {
- mHeap.update(v);
- return h;
- }
-
- handle erase(value_type const& v, handle) {
- mHeap.remove(v);
- return null_handle();
- }
-
- value_type top() const {
- return mHeap.top();
- }
-
- void pop() {
- mHeap.pop();
- }
-
- bool empty() const {
- return mHeap.empty();
- }
-
- bool contains(value_type const& v) {
- return mHeap.contains(v);
- }
-
- boost::optional<value_type> extract_top() {
- boost::optional<value_type> r;
- if (!empty()) {
- value_type v = top();
- pop();
- r = boost::optional<value_type>(v);
- }
- return r;
- }
-
- static handle null_handle() {
- return handle(false);
- }
-
- private:
- Heap mHeap;
-};
-
-} // namespace CGAL
-
-#endif // CONTRACTION_CGAL_QUEUE_MODIFIABLE_PRIORITY_QUEUE_H_
diff --git a/include/gudhi/Contraction/Edge_profile.h b/include/gudhi/Contraction/Edge_profile.h
deleted file mode 100644
index 30b1b80a..00000000
--- a/include/gudhi/Contraction/Edge_profile.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_EDGE_PROFILE_H_
-#define CONTRACTION_EDGE_PROFILE_H_
-
-#include <ostream>
-
-namespace Gudhi {
-
-namespace contraction {
-
-template<typename GeometricSimplifiableComplex> class Edge_profile {
- public:
- typedef GeometricSimplifiableComplex Complex;
- typedef typename Complex::GT GT;
-
- typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle;
- typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle;
-
-
- typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle;
- typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex;
- typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge;
- typedef typename GeometricSimplifiableComplex::Point Point;
-
- Edge_profile(GeometricSimplifiableComplex& complex, Edge_handle edge) : complex_(complex), edge_handle_(edge),
- v0_(complex_.first_vertex(edge_handle_)), v1_(complex_.second_vertex(edge_handle_)) {
- assert(complex_.get_address(complex_[edge_handle_].first()));
- assert(complex_.get_address(complex_[edge_handle_].second()));
- assert(complex_.contains_edge(v0_handle(), v1_handle()));
- assert(v0_handle() != v1_handle());
- }
-
- virtual ~Edge_profile() { }
-
- GeometricSimplifiableComplex& complex() const {
- return complex_;
- }
-
- Edge_handle edge_handle() const {
- return edge_handle_;
- }
-
- Graph_edge& edge() const {
- return complex_[edge_handle_];
- }
-
- Graph_vertex& v0() const {
- return complex_[v0_handle()];
- }
-
- Graph_vertex& v1() const {
- return complex_[v1_handle()];
- }
-
- Vertex_handle v0_handle() const {
- return v0_;
- // Root_vertex_handle root = complex_[edge_handle_].first();
- // assert(complex_.get_address(root));
- // return *complex_.get_address(root);
- }
-
- Vertex_handle v1_handle() const {
- return v1_;
- // Root_vertex_handle root = complex_[edge_handle_].second();
- // assert(complex_.get_address(root));
- // return *complex_.get_address(root);
- }
-
- const Point& p0() const {
- return complex_.point(v0_handle());
- }
-
- const Point& p1() const {
- return complex_.point(v1_handle());
- }
-
- friend std::ostream& operator<<(std::ostream& o, const Edge_profile& v) {
- return o << "v0:" << v.v0_handle() << " v1:" << v.v1_handle();
- }
-
- private:
- GeometricSimplifiableComplex& complex_;
-
- Edge_handle edge_handle_;
-
- Vertex_handle v0_;
-
- Vertex_handle v1_;
-};
-
-template<typename EdgeProfile> class Edge_profile_factory {
- public:
- typedef typename EdgeProfile::Edge_handle Edge_handle_;
- typedef typename EdgeProfile::Complex Complex_;
-
- virtual EdgeProfile make_profile(
- Complex_& complex,
- Edge_handle_ edge) const {
- return EdgeProfile(complex, edge);
- }
-
- virtual ~Edge_profile_factory() { }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_EDGE_PROFILE_H_
diff --git a/include/gudhi/Contraction/policies/Contraction_visitor.h b/include/gudhi/Contraction/policies/Contraction_visitor.h
deleted file mode 100644
index fa02308b..00000000
--- a/include/gudhi/Contraction/policies/Contraction_visitor.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_
-#define CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_
-
-#include <gudhi/Contraction/Edge_profile.h>
-#include <boost/optional.hpp>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@class Contraction_visitor
- *@brief Interface for a visitor of the edge contraction process.
- *@ingroup contr
- */
-template <typename EdgeProfile>
-class Contraction_visitor { // : public Dummy_complex_visitor<typename EdgeProfile::Vertex_handle> {
- public:
- // typedef typename ComplexType::GeometryTrait GT;
- typedef EdgeProfile Profile;
- typedef double FT;
- typedef typename Profile::Complex Complex;
- typedef Complex ComplexType;
- typedef typename ComplexType::Point Point;
-
- virtual ~Contraction_visitor() { }
-
- /**
- * @brief Called before the edge contraction process starts.
- */
- virtual void on_started(ComplexType & complex) { }
-
- /**
- * @brief Called when the algorithm stops.
- */
- virtual void on_stop_condition_reached() { }
-
- /**
- * @brief Called during the collecting phase (when a cost is assigned to the edges), for each edge collected.
- */
- virtual void on_collected(const Profile &profile, boost::optional< FT > cost) { }
-
- /**
- * @brief Called during the processing phase (when edges are contracted), for each edge that is selected.
- */
- virtual void on_selected(const Profile &profile, boost::optional< FT > cost, int initial_count, int current_count) { }
-
- /**
- * @brief Called when an edge is about to be contracted and replaced by a vertex whose position is *placement.
- */
- virtual void on_contracting(const Profile &profile, boost::optional< Point > placement) { }
-
- /**
- * @brief Called when after an edge has been contracted onto a new point placement.
- * A possibility would to remove popable blockers at this point for instance.
- */
- virtual void on_contracted(const Profile &profile, boost::optional< Point > placement) { }
-
- /**
- * @brief Called for each selected edge which cannot be contracted because the ValidContractionPredicate is false
- */
- virtual void on_non_valid(const Profile &profile) { }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_CONTRACTION_VISITOR_H_
diff --git a/include/gudhi/Contraction/policies/Cost_policy.h b/include/gudhi/Contraction/policies/Cost_policy.h
deleted file mode 100644
index 04ce36b6..00000000
--- a/include/gudhi/Contraction/policies/Cost_policy.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_COST_POLICY_H_
-#define CONTRACTION_POLICIES_COST_POLICY_H_
-
-#include <boost/optional.hpp>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@brief Policy to specify the cost of contracting an edge.
- *@ingroup contr
- */
-template< typename EdgeProfile>
-class Cost_policy {
- public:
- typedef typename EdgeProfile::Point Point;
- typedef typename EdgeProfile::Graph_vertex Graph_vertex;
-
- typedef boost::optional<double> Cost_type;
-
- virtual Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const = 0;
-
- virtual ~Cost_policy() { }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_COST_POLICY_H_
diff --git a/include/gudhi/Contraction/policies/Dummy_valid_contraction.h b/include/gudhi/Contraction/policies/Dummy_valid_contraction.h
deleted file mode 100644
index a5567454..00000000
--- a/include/gudhi/Contraction/policies/Dummy_valid_contraction.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_
-#define CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_
-
-#include <gudhi/Contraction/policies/Valid_contraction_policy.h>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@brief Policy that accept all edge contraction.
- */
-template< typename EdgeProfile>
-class Dummy_valid_contraction : public Valid_contraction_policy<EdgeProfile> {
- public:
- typedef typename EdgeProfile::Point Point;
-
- bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) {
- return true;
- }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_DUMMY_VALID_CONTRACTION_H_
diff --git a/include/gudhi/Contraction/policies/Edge_length_cost.h b/include/gudhi/Contraction/policies/Edge_length_cost.h
deleted file mode 100644
index 1b7a825b..00000000
--- a/include/gudhi/Contraction/policies/Edge_length_cost.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_
-#define CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_
-
-#include <gudhi/Contraction/policies/Cost_policy.h>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- * @brief return a cost corresponding to the squared length of the edge
- */
-template< typename EdgeProfile>
-class Edge_length_cost : public Cost_policy<EdgeProfile> {
- public:
- typedef typename Cost_policy<EdgeProfile>::Cost_type Cost_type;
- typedef typename EdgeProfile::Point Point;
-
- Cost_type operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override {
- double res = 0;
- auto p0_coord = profile.p0().begin();
- auto p1_coord = profile.p1().begin();
- for (; p0_coord != profile.p0().end(); p0_coord++, p1_coord++) {
- res += (*p0_coord - *p1_coord) * (*p0_coord - *p1_coord);
- }
- return res;
- }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_EDGE_LENGTH_COST_H_
diff --git a/include/gudhi/Contraction/policies/First_vertex_placement.h b/include/gudhi/Contraction/policies/First_vertex_placement.h
deleted file mode 100644
index 0b9f8775..00000000
--- a/include/gudhi/Contraction/policies/First_vertex_placement.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_
-#define CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_
-
-#include <gudhi/Contraction/policies/Placement_policy.h>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- * @brief Places the contracted point onto the first point of the edge
- */
-template< typename EdgeProfile>
-class First_vertex_placement : public Placement_policy<EdgeProfile> {
- public:
- typedef typename EdgeProfile::Point Point;
- typedef typename EdgeProfile::Edge_handle Edge_handle;
-
- typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type;
-
- Placement_type operator()(const EdgeProfile& profile) const override {
- return Placement_type(profile.p0());
- }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_FIRST_VERTEX_PLACEMENT_H_
diff --git a/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h b/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h
deleted file mode 100644
index 8c869830..00000000
--- a/include/gudhi/Contraction/policies/Link_condition_valid_contraction.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_
-#define CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_
-
-#include <gudhi/Contraction/policies/Valid_contraction_policy.h>
-#include <gudhi/Debug_utils.h>
-
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@brief Policy that only accept edges verifying the link condition (and therefore whose contraction preserving homotopy type).
- *@ingroup contr
- */
-template< typename EdgeProfile>
-class Link_condition_valid_contraction : public Valid_contraction_policy<EdgeProfile> {
- public:
- typedef typename EdgeProfile::Edge_handle Edge_handle;
- typedef typename EdgeProfile::Point Point;
- // typedef typename EdgeProfile::Edge_handle Edge_handle;
-
- bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const override {
- Edge_handle edge(profile.edge_handle());
- DBGMSG("Link_condition_valid_contraction:", profile.complex().link_condition(edge));
- return profile.complex().link_condition(edge);
- }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_LINK_CONDITION_VALID_CONTRACTION_H_
diff --git a/include/gudhi/Contraction/policies/Middle_placement.h b/include/gudhi/Contraction/policies/Middle_placement.h
deleted file mode 100644
index 0ba23a35..00000000
--- a/include/gudhi/Contraction/policies/Middle_placement.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_
-#define CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_
-
-#include <gudhi/Contraction/policies/Placement_policy.h>
-
-namespace Gudhi {
-
-namespace contraction {
-
-template< typename EdgeProfile>
-class Middle_placement : public Placement_policy<EdgeProfile> {
- public:
- typedef typename EdgeProfile::Point Point;
- typedef typename EdgeProfile::Edge_handle Edge_handle;
- typedef typename EdgeProfile::Graph_vertex Graph_vertex;
-
- typedef typename Placement_policy<EdgeProfile>::Placement_type Placement_type;
-
- Placement_type operator()(const EdgeProfile& profile) const override {
- // todo compute the middle
- return Placement_type(profile.p0());
- }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_MIDDLE_PLACEMENT_H_
diff --git a/include/gudhi/Contraction/policies/Placement_policy.h b/include/gudhi/Contraction/policies/Placement_policy.h
deleted file mode 100644
index 19509fad..00000000
--- a/include/gudhi/Contraction/policies/Placement_policy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_PLACEMENT_POLICY_H_
-#define CONTRACTION_POLICIES_PLACEMENT_POLICY_H_
-
-#include <boost/optional.hpp>
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@brief Policy to specify where the merged point had to be placed after an edge contraction.
- *@ingroup contr
- */
-template< typename EdgeProfile>
-class Placement_policy {
- public:
- typedef typename EdgeProfile::Point Point;
- typedef boost::optional<Point> Placement_type;
-
- virtual Placement_type operator()(const EdgeProfile& profile) const = 0;
-
- virtual ~Placement_policy() { }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // CONTRACTION_POLICIES_PLACEMENT_POLICY_H_
diff --git a/include/gudhi/Contraction/policies/Valid_contraction_policy.h b/include/gudhi/Contraction/policies/Valid_contraction_policy.h
deleted file mode 100644
index 8a91f0b5..00000000
--- a/include/gudhi/Contraction/policies/Valid_contraction_policy.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_
-#define CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_
-
-namespace Gudhi {
-
-namespace contraction {
-
-/**
- *@brief Policy to specify if an edge contraction is valid or not.
- *@ingroup contr
- */
-template< typename EdgeProfile>
-class Valid_contraction_policy {
- public:
- typedef typename EdgeProfile::Point Point;
- typedef typename EdgeProfile::Edge_handle Edge_handle;
- typedef typename EdgeProfile::Graph_vertex Graph_vertex;
-
- virtual bool operator()(const EdgeProfile& profile, const boost::optional<Point>& placement) const = 0;
-
- virtual ~Valid_contraction_policy() { }
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-
-#endif // CONTRACTION_POLICIES_VALID_CONTRACTION_POLICY_H_
diff --git a/include/gudhi/Debug_utils.h b/include/gudhi/Debug_utils.h
deleted file mode 100644
index 3f5cb04f..00000000
--- a/include/gudhi/Debug_utils.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef DEBUG_UTILS_H_
-#define DEBUG_UTILS_H_
-
-#include <iostream>
-
-#ifndef NDEBUG
- // GUDHI_DEBUG is the Gudhi official flag for debug mode.
- #define GUDHI_DEBUG
-#endif
-
-// GUDHI_CHECK throw an exception if expression is false in debug mode, but does nothing in release mode
-// Could assert in release mode, but cmake sets NDEBUG (for "NO DEBUG") in this mode, means assert does nothing.
-#ifdef GUDHI_DEBUG
- #define GUDHI_CHECK(expression, excpt) ((expression) ? (void) 0 : (throw excpt))
- #define GUDHI_CHECK_code(CODE) CODE
-#else
- #define GUDHI_CHECK(expression, excpt) (void) 0
- #define GUDHI_CHECK_code(CODE)
-#endif
-
-#define PRINT(a) std::cerr << #a << ": " << (a) << " (DISP)" << std::endl
-
-// #define DBG_VERBOSE
-#ifdef DBG_VERBOSE
- #define DBG(a) std::cout << "DBG: " << (a) << std::endl
- #define DBGMSG(a, b) std::cout << "DBG: " << a << b << std::endl
- #define DBGVALUE(a) std::cout << "DBG: " << #a << ": " << a << std::endl
- #define DBGCONT(a) std::cout << "DBG: container " << #a << " -> "; for (auto x : a) std::cout << x << ","; std::cout << std::endl
-#else
- #define DBG(a) (void) 0
- #define DBGMSG(a, b) (void) 0
- #define DBGVALUE(a) (void) 0
- #define DBGCONT(a) (void) 0
-#endif
-
-#endif // DEBUG_UTILS_H_
diff --git a/include/gudhi/Edge_contraction.h b/include/gudhi/Edge_contraction.h
deleted file mode 100644
index fcd06996..00000000
--- a/include/gudhi/Edge_contraction.h
+++ /dev/null
@@ -1,231 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EDGE_CONTRACTION_H_
-#define EDGE_CONTRACTION_H_
-
-
-#include <gudhi/Skeleton_blocker_contractor.h>
-#include <gudhi/Contraction/policies/Edge_length_cost.h>
-#include <gudhi/Contraction/policies/First_vertex_placement.h>
-#include <gudhi/Contraction/policies/Valid_contraction_policy.h>
-#include <gudhi/Contraction/policies/Dummy_valid_contraction.h>
-#include <gudhi/Contraction/policies/Link_condition_valid_contraction.h>
-#include <gudhi/Debug_utils.h>
-
-namespace Gudhi {
-
-namespace contraction {
-
-
-/** \defgroup contr Edge contraction
-
-\author David Salinas
-
-\section edgecontractionintroduction Introduction
-
-The purpose of this package is to offer a user-friendly interface for edge contraction simplification of huge simplicial complexes.
-It uses the \ref skbl data-structure whose size remains small during simplification
-of most used geometrical complexes of topological data analysis such as the Rips or the Delaunay complexes. In practice, the
-size of this data-structure is even much lower than the total number of simplices.
-
-The edge contraction operation consists in identifying two vertices of a simplicial complex.
-A lot of algorithms have been developed in computer graphics that allows to reduce efficiently the size of 2-dimensional simplicial complexes
- while preserving its geometry (for instance see \cite Garland \cite Lindstrom).
-These approaches can be extended to higher-dimensional simplicial complexes.
-The main advantage of using the Skeleton-Blocker data structure for edge contraction is that when the number of blockers is small,
-the operations needed for edge contraction algorithms have polynomial complexity regarding the size the graph.
-Therefore, the simplification can be done without enumerating the set of simplices that is often non tracktable in high-dimension and is then very efficient
-(sub-linear with regards to the number of simplices in practice).
-
-A typical application of this package is homology group computation. It is illustrated in the next figure where a Rips complex is built uppon a set of high-dimensional points and
-simplified with edge contractions.
-It has initially a big number of simplices (around 20 millions) but simplifying it to a much reduced form with only 15 vertices (and 714 simplices) takes only few seconds on a desktop machine (see the example bellow).
-One can then compute homology group with a simplicial complex having very few simplices instead of running the homology algorithm on the much bigger initial set of
-simplices which would take much more time and memory.
-
-
-\image html "so3.png" "Edge contraction illustration"
-
-\section Design
-
-This class design is policy based and heavily inspired from the similar edge collapse package of CGAL http://doc.cgal.org/latest/Surface_mesh_simplification/index.html (which is however restricted to 2D triangulations).
-
-
-\subsection Policies
-
-Four policies can be customized in this package:
-
-\li Cost_policy: specify how much cost an edge contraction of a given edge. The edge with lowest cost is iteratively picked and contracted if valid.
-\li Valid_contraction_policy: specify if a given edge contraction is valid. For instance, this policy can check the link condition which ensures that the homotopy type is preserved afer the edge contraction.
-\li Placement_policy: every time an edge is contracted, its points are merge to one point specified by this policy. This may be the middle of the edge of some more sophisticated point such as the minimum of a cost as in
-\cite Garland.
-
-
-\subsection Visitor
-
-A visitor which implements the class Contraction_visitor gets called at several key moments
-during the simplification:
-
-\li when the algorithms starts or ends,
-\li when an edge is seen for the first time,
-\li when an edge is considered for an edge contraction,
-\li before and after an edge is contracted.
-
-This allows to implements most of edge contraction based algorithm with this
-package without having to change the main simplification source code.
-
-
-\section Performance
-
-The next figure shows the computation time to reduce a random 2-sphere to a single tetrahedron with
-this package and with the CGAL equivalent package.
-Despite this package is able to deal with \a arbitrary simplicial complexes (any dimensions, manifold or non manifold),
-it is still \a 65% times faster than the CGAL package which is focused on 2-manifold.
-The main reason is that few blockers appears during the simplification and hence,
-the algorithm only have to deal with the graph and not higher-dimensional simplices
-(in this case triangles). However, we recall that higher-dimensional simplices are \a implicitely
-stored in the \ref skbl data-structure. Hence, one has to store
-simplices in an external map if some information needs to be associated with them (information that could be a filtration value or
-an orientation for instance).
-
-
-\image html "sphere_contraction.png" "Time in seconds to simplify random 2-spheres to a tetrahedron" width=10cm
-
-\section Example
-
-
-This example loads points from an OFF file and builds the Rips complex with an user provided parameter. It then simplifies the built Rips complex
-while ensuring its homotopy type is preserved during the contraction (edge are contracted only when the link condition is valid).
-
- \code{.cpp}
-#include <boost/timer/timer.hpp>
-#include <iostream>
-#include <gudhi/Edge_contraction.h>
-#include <gudhi/Skeleton_blocker.h>
-#include <gudhi/Off_reader.h>
-
-
-using namespace std;
-using namespace Gudhi;
-using namespace skeleton_blocker;
-using namespace contraction;
-
-struct Geometry_trait{
- typedef std::vector<double> Point;
-};
-
-typedef Geometry_trait::Point Point;
-typedef Skeleton_blocker_simple_geometric_traits<Geometry_trait> Complex_geometric_traits;
-typedef Skeleton_blocker_geometric_complex< Complex_geometric_traits > Complex;
-typedef Edge_profile<Complex> Profile;
-typedef Skeleton_blocker_contractor<Complex> Complex_contractor;
-
-template<typename Point>
-double eucl_distance(const Point& a,const Point& b){
- double res = 0;
- auto a_coord = a.begin();
- auto b_coord = b.begin();
- for(; a_coord != a.end(); a_coord++, b_coord++){
- res += (*a_coord - *b_coord) * (*a_coord - *b_coord);
- }
- return sqrt(res);
-}
-
-template<typename ComplexType>
-void build_rips(ComplexType& complex, double offset){
- if (offset<=0) return;
- auto vertices = complex.vertex_range();
- for (auto p = vertices.begin(); p != vertices.end(); ++p)
- for (auto q = p; ++q != vertices.end(); )
- if (eucl_distance(complex.point(*p), complex.point(*q)) < 2 * offset)
- complex.add_edge_without_blockers(*p,*q);
-}
-
-int main (int argc, char *argv[])
-{
- if (argc!=3){
- std::cerr << "Usage "<<argv[0]<<" ../../data/SO3_10000.off 0.3 to load the file ../../data/SO3_10000.off and contract the Rips complex built with paremeter 0.3.\n";
- return -1;
- }
-
- Complex complex;
-
- // load the points
- Skeleton_blocker_off_reader<Complex> off_reader(argv[1],complex,true);
- if(!off_reader.is_valid()){
- std::cerr << "Unable to read file:"<<argv[1]<<std::endl;
- return EXIT_FAILURE;
- }
- std::cout << "Build the Rips complex"<<std::endl;
-
- build_rips(complex,atof(argv[2]));
-
- boost::timer::auto_cpu_timer t;
-
- std::cout << "Initial complex has "<<
- complex.num_vertices()<<" vertices and "<<
- complex.num_edges()<<" edges"<<std::endl;
-
- Complex_contractor contractor(complex,
- new Edge_length_cost<Profile>,
- contraction::make_first_vertex_placement<Profile>(),
- contraction::make_link_valid_contraction<Profile>(),
- contraction::make_remove_popable_blockers_visitor<Profile>());
- contractor.contract_edges();
-
- std::cout << "Counting final number of simplices \n";
- unsigned num_simplices = std::distance(complex.star_simplex_range().begin(),complex.star_simplex_range().end());
-
- std::cout << "Final complex has "<<
- complex.num_vertices()<<" vertices, "<<
- complex.num_edges()<<" edges, "<<
- complex.num_blockers()<<" blockers and "<<
- num_simplices<<" simplices"<<std::endl;
-
-
- std::cout << "Time to simplify and enumerate simplices:\n";
-
- return EXIT_SUCCESS;
-}
-}
- \endcode
-
-\verbatim
-./example/Contraction/RipsContraction ../../data/SO3_10000.off 0.3
-[ 50%] [100%] Built target SkeletonBlockerIteration
-Built target RipsContraction
-Build the Rips complex
-Initial complex has 10000 vertices and 195664 edges
-Counting final number of simplices
-Final complex has 15 vertices, 101 edges, 165 blockers and 714 simplices
-Time to simplify and enumerate simplices:
- 3.166621s wall, 3.150000s user + 0.010000s system = 3.160000s CPU (99.8%)
-\endverbatim
-
-*/
-/** @} */ // end defgroup
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // EDGE_CONTRACTION_H_
diff --git a/include/gudhi/Euclidean_strong_witness_complex.h b/include/gudhi/Euclidean_strong_witness_complex.h
deleted file mode 100644
index ea97cd3f..00000000
--- a/include/gudhi/Euclidean_strong_witness_complex.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_
-#define EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_
-
-#include <gudhi/Strong_witness_complex.h>
-#include <gudhi/Active_witness/Active_witness.h>
-#include <gudhi/Kd_tree_search.h>
-
-#include <utility>
-#include <vector>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
-/**
- * \private
- * \class Euclidean_strong_witness_complex
- * \brief Constructs strong witness complex for given sets of witnesses and landmarks in Euclidean space.
- * \ingroup witness_complex
- *
- * \tparam Kernel_ requires a <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> class.
- */
-template< class Kernel_ >
-class Euclidean_strong_witness_complex
- : public Strong_witness_complex<std::vector<typename Gudhi::spatial_searching::Kd_tree_search<Kernel_,
- std::vector<typename Kernel_::Point_d>>::INS_range>> {
- private:
- typedef Kernel_ K;
- typedef typename K::Point_d Point_d;
- typedef std::vector<Point_d> Point_range;
- typedef Gudhi::spatial_searching::Kd_tree_search<Kernel_, Point_range> Kd_tree;
- typedef typename Kd_tree::INS_range Nearest_landmark_range;
- typedef typename std::vector<Nearest_landmark_range> Nearest_landmark_table;
-
- typedef typename Nearest_landmark_range::Point_with_transformed_distance Id_distance_pair;
- typedef typename Id_distance_pair::first_type Landmark_id;
- typedef Landmark_id Vertex_handle;
-
- private:
- Point_range landmarks_;
- Kd_tree landmark_tree_;
- using Strong_witness_complex<Nearest_landmark_table>::nearest_landmark_table_;
-
- public:
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /* @name Constructor
- */
-
- //@{
-
- /**
- * \brief Initializes member variables before constructing simplicial complex.
- * \details Records landmarks from the range 'landmarks' into a
- * table internally, as well as witnesses from the range 'witnesses'.
- * Both ranges should have value_type Kernel_::Point_d.
- */
- template< typename LandmarkRange,
- typename WitnessRange >
- Euclidean_strong_witness_complex(const LandmarkRange & landmarks,
- const WitnessRange & witnesses)
- : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks_) {
- nearest_landmark_table_.reserve(boost::size(witnesses));
- for (auto w : witnesses)
- nearest_landmark_table_.push_back(landmark_tree_.incremental_nearest_neighbors(w));
- }
-
- /** \brief Returns the point corresponding to the given vertex.
- */
- template <typename Vertex_handle>
- Point_d get_point(Vertex_handle vertex) const {
- return landmarks_[vertex];
- }
-
- //@}
-};
-
-} // namespace witness_complex
-
-} // namespace Gudhi
-
-#endif // EUCLIDEAN_STRONG_WITNESS_COMPLEX_H_
diff --git a/include/gudhi/Euclidean_witness_complex.h b/include/gudhi/Euclidean_witness_complex.h
deleted file mode 100644
index 1dacefa5..00000000
--- a/include/gudhi/Euclidean_witness_complex.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EUCLIDEAN_WITNESS_COMPLEX_H_
-#define EUCLIDEAN_WITNESS_COMPLEX_H_
-
-#include <gudhi/Witness_complex.h>
-#include <gudhi/Active_witness/Active_witness.h>
-#include <gudhi/Kd_tree_search.h>
-
-#include <utility>
-#include <vector>
-#include <list>
-#include <limits>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
-/**
- * \private
- * \class Euclidean_witness_complex
- * \brief Constructs (weak) witness complex for given sets of witnesses and landmarks in Euclidean space.
- * \ingroup witness_complex
- *
- * \tparam Kernel_ requires a <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> class.
- */
-template< class Kernel_ >
-class Euclidean_witness_complex
- : public Witness_complex<std::vector<typename Gudhi::spatial_searching::Kd_tree_search<Kernel_,
- std::vector<typename Kernel_::Point_d>>::INS_range>> {
- private:
- typedef Kernel_ K;
- typedef typename K::Point_d Point_d;
- typedef std::vector<Point_d> Point_range;
- typedef Gudhi::spatial_searching::Kd_tree_search<Kernel_, Point_range> Kd_tree;
- typedef typename Kd_tree::INS_range Nearest_landmark_range;
- typedef typename std::vector<Nearest_landmark_range> Nearest_landmark_table;
-
- typedef typename Nearest_landmark_range::Point_with_transformed_distance Id_distance_pair;
- typedef typename Id_distance_pair::first_type Landmark_id;
- typedef Landmark_id Vertex_handle;
-
- private:
- Point_range landmarks_;
- Kd_tree landmark_tree_;
- using Witness_complex<Nearest_landmark_table>::nearest_landmark_table_;
-
- public:
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /* @name Constructor
- */
-
- //@{
-
- /**
- * \brief Initializes member variables before constructing simplicial complex.
- * \details Records landmarks from the range 'landmarks' into a
- * table internally, as well as witnesses from the range 'witnesses'.
- * Both ranges should have value_type Kernel_::Point_d.
- */
- template< typename LandmarkRange,
- typename WitnessRange >
- Euclidean_witness_complex(const LandmarkRange & landmarks,
- const WitnessRange & witnesses)
- : landmarks_(std::begin(landmarks), std::end(landmarks)), landmark_tree_(landmarks) {
- nearest_landmark_table_.reserve(boost::size(witnesses));
- for (auto w : witnesses)
- nearest_landmark_table_.push_back(landmark_tree_.incremental_nearest_neighbors(w));
- }
-
- /** \brief Returns the point corresponding to the given vertex.
- * @param[in] vertex Vertex handle of the point to retrieve.
- */
- Point_d get_point(Vertex_handle vertex) const {
- return landmarks_[vertex];
- }
-
- //@}
-};
-
-} // namespace witness_complex
-
-} // namespace Gudhi
-
-#endif // EUCLIDEAN_WITNESS_COMPLEX_H_
diff --git a/include/gudhi/GIC.h b/include/gudhi/GIC.h
deleted file mode 100644
index fea0b861..00000000
--- a/include/gudhi/GIC.h
+++ /dev/null
@@ -1,1371 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Mathieu Carriere
- *
- * Copyright (C) 2017 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GIC_H_
-#define GIC_H_
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_for.h>
-#include <tbb/mutex.h>
-#endif
-
-#include <gudhi/Debug_utils.h>
-#include <gudhi/graph_simplicial_complex.h>
-#include <gudhi/reader_utils.h>
-#include <gudhi/Simplex_tree.h>
-#include <gudhi/Rips_complex.h>
-#include <gudhi/Points_off_io.h>
-#include <gudhi/distance_functions.h>
-#include <gudhi/Persistent_cohomology.h>
-#include <gudhi/Bottleneck.h>
-
-#include <boost/config.hpp>
-#include <boost/graph/graph_traits.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/connected_components.hpp>
-#include <boost/graph/dijkstra_shortest_paths.hpp>
-#include <boost/graph/subgraph.hpp>
-#include <boost/graph/graph_utility.hpp>
-
-#include <iostream>
-#include <vector>
-#include <map>
-#include <string>
-#include <limits> // for numeric_limits
-#include <utility> // for std::pair<>
-#include <algorithm> // for std::max
-#include <random>
-#include <cassert>
-#include <cmath>
-
-namespace Gudhi {
-
-namespace cover_complex {
-
-using Simplex_tree = Gudhi::Simplex_tree<>;
-using Filtration_value = Simplex_tree::Filtration_value;
-using Rips_complex = Gudhi::rips_complex::Rips_complex<Filtration_value>;
-using Persistence_diagram = std::vector<std::pair<double, double> >;
-using Graph = boost::subgraph<
- boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, boost::no_property,
- boost::property<boost::edge_index_t, int, boost::property<boost::edge_weight_t, double> > > >;
-using Vertex_t = boost::graph_traits<Graph>::vertex_descriptor;
-using Index_map = boost::property_map<Graph, boost::vertex_index_t>::type;
-using Weight_map = boost::property_map<Graph, boost::edge_weight_t>::type;
-
-/**
- * \class Cover_complex
- * \brief Cover complex data structure.
- *
- * \ingroup cover_complex
- *
- * \details
- * The data structure is a simplicial complex, representing a
- * Graph Induced simplicial Complex (GIC) or a Nerve,
- * and whose simplices are computed with a cover C of a point
- * cloud P, which often comes from the preimages of intervals
- * covering the image of a function f defined on P.
- * These intervals are parameterized by their resolution
- * (either their length or their number)
- * and their gain (percentage of overlap).
- * To compute a GIC, one also needs a graph G built on top of P,
- * whose cliques with vertices belonging to different elements of C
- * correspond to the simplices of the GIC.
- *
- */
-template <typename Point>
-class Cover_complex {
- private:
- bool verbose = false; // whether to display information.
- std::string type; // Nerve or GIC
-
- std::vector<Point> point_cloud; // input point cloud.
- std::vector<std::vector<double> > distances; // all pairwise distances.
- int maximal_dim; // maximal dimension of output simplicial complex.
- int data_dimension; // dimension of input data.
- int n; // number of points.
-
- std::vector<double> func; // function used to compute the output simplicial complex.
- std::vector<double> func_color; // function used to compute the colors of the nodes of the output simplicial complex.
- bool functional_cover = false; // whether we use a cover with preimages of a function or not.
-
- Graph one_skeleton_OFF; // one-skeleton given by the input OFF file (if it exists).
- Graph one_skeleton; // one-skeleton used to compute the connected components.
- std::vector<Vertex_t> vertices; // vertices of one_skeleton.
-
- std::vector<std::vector<int> > simplices; // simplices of output simplicial complex.
- std::vector<int> voronoi_subsamples; // Voronoi germs (in case of Voronoi cover).
-
- Persistence_diagram PD;
- std::vector<double> distribution;
-
- std::vector<std::vector<int> >
- cover; // function associating to each data point the vector of cover elements to which it belongs.
- std::map<int, std::vector<int> >
- cover_back; // inverse of cover, in order to get the data points associated to a specific cover element.
- std::map<int, double> cover_std; // standard function (induced by func) used to compute the extended persistence
- // diagram of the output simplicial complex.
- std::map<int, int>
- cover_fct; // integer-valued function that allows to state if two elements of the cover are consecutive or not.
- std::map<int, std::pair<int, double> >
- cover_color; // size and coloring (induced by func_color) of the vertices of the output simplicial complex.
-
- int resolution_int = -1;
- double resolution_double = -1;
- double gain = -1;
- double rate_constant = 10; // Constant in the subsampling.
- double rate_power = 0.001; // Power in the subsampling.
- int mask = 0; // Ignore nodes containing less than mask points.
-
- std::map<int, int> name2id, name2idinv;
-
- std::string cover_name;
- std::string point_cloud_name;
- std::string color_name;
-
- // Remove all edges of a graph.
- void remove_edges(Graph& G) {
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(G); ei != ei_end; ++ei) boost::remove_edge(*ei, G);
- }
-
- // Thread local is not available on XCode version < V.8
- // If not available, random engine is a class member.
-#ifndef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- std::default_random_engine re;
-#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
-
- // Find random number in [0,1].
- double GetUniform() {
- // Thread local is not available on XCode version < V.8
- // If available, random engine is defined for each thread.
-#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- thread_local std::default_random_engine re;
-#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- std::uniform_real_distribution<double> Dist(0, 1);
- return Dist(re);
- }
-
- // Subsample points.
- void SampleWithoutReplacement(int populationSize, int sampleSize, std::vector<int>& samples) {
- int t = 0;
- int m = 0;
- double u;
- while (m < sampleSize) {
- u = GetUniform();
- if ((populationSize - t) * u >= sampleSize - m) {
- t++;
- } else {
- samples[m] = t;
- t++;
- m++;
- }
- }
- }
-
- // *******************************************************************************************************************
- // Utils.
- // *******************************************************************************************************************
-
- public:
- /** \brief Specifies whether the type of the output simplicial complex.
- *
- * @param[in] t std::string (either "GIC" or "Nerve").
- *
- */
- void set_type(const std::string& t) { type = t; }
-
- public:
- /** \brief Specifies whether the program should display information or not.
- *
- * @param[in] verb boolean (true = display info, false = do not display info).
- *
- */
- void set_verbose(bool verb = false) { verbose = verb; }
-
- public:
- /** \brief Sets the constants used to subsample the data set. These constants are
- * explained in \cite Carriere17c.
- *
- * @param[in] constant double.
- * @param[in] power double.
- *
- */
- void set_subsampling(double constant, double power) {
- rate_constant = constant;
- rate_power = power;
- }
-
- public:
- /** \brief Sets the mask, which is a threshold integer such that nodes in the complex that contain a number of data
- * points which is less than or equal to
- * this threshold are not displayed.
- *
- * @param[in] nodemask integer.
- *
- */
- void set_mask(int nodemask) { mask = nodemask; }
-
- public:
- /** \brief Reads and stores the input point cloud.
- *
- * @param[in] off_file_name name of the input .OFF or .nOFF file.
- *
- */
- bool read_point_cloud(const std::string& off_file_name) {
- point_cloud_name = off_file_name;
- std::ifstream input(off_file_name);
- std::string line;
-
- char comment = '#';
- while (comment == '#') {
- std::getline(input, line);
- if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
- comment = line[line.find_first_not_of(' ')];
- }
- if (strcmp((char*)line.c_str(), "nOFF") == 0) {
- comment = '#';
- while (comment == '#') {
- std::getline(input, line);
- if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
- comment = line[line.find_first_not_of(' ')];
- }
- std::stringstream stream(line);
- stream >> data_dimension;
- } else {
- data_dimension = 3;
- }
-
- comment = '#';
- int numedges, numfaces, i, dim;
- while (comment == '#') {
- std::getline(input, line);
- if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
- comment = line[line.find_first_not_of(' ')];
- }
- std::stringstream stream(line);
- stream >> n;
- stream >> numfaces;
- stream >> numedges;
-
- i = 0;
- while (i < n) {
- std::getline(input, line);
- if (!line.empty() && line[line.find_first_not_of(' ')] != '#' &&
- !all_of(line.begin(), line.end(), (int (*)(int))isspace)) {
- std::stringstream iss(line);
- std::vector<double> point;
- point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>());
- point_cloud.emplace_back(point.begin(), point.begin() + data_dimension);
- boost::add_vertex(one_skeleton_OFF);
- vertices.push_back(boost::add_vertex(one_skeleton));
- cover.emplace_back();
- i++;
- }
- }
-
- i = 0;
- while (i < numfaces) {
- std::getline(input, line);
- if (!line.empty() && line[line.find_first_not_of(' ')] != '#' &&
- !all_of(line.begin(), line.end(), (int (*)(int))isspace)) {
- std::vector<int> simplex;
- std::stringstream iss(line);
- simplex.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>());
- dim = simplex[0];
- for (int j = 1; j <= dim; j++)
- for (int k = j + 1; k <= dim; k++)
- boost::add_edge(vertices[simplex[j]], vertices[simplex[k]], one_skeleton_OFF);
- i++;
- }
- }
-
- return input.is_open();
- }
-
- // *******************************************************************************************************************
- // Graphs.
- // *******************************************************************************************************************
-
- public: // Set graph from file.
- /** \brief Creates a graph G from a file containing the edges.
- *
- * @param[in] graph_file_name name of the input graph file.
- * The graph file contains one edge per line,
- * each edge being represented by the IDs of its two nodes.
- *
- */
- void set_graph_from_file(const std::string& graph_file_name) {
- remove_edges(one_skeleton);
- int neighb;
- std::ifstream input(graph_file_name);
- std::string line;
- int source;
- while (std::getline(input, line)) {
- std::stringstream stream(line);
- stream >> source;
- while (stream >> neighb) boost::add_edge(vertices[source], vertices[neighb], one_skeleton);
- }
- }
-
- public: // Set graph from OFF file.
- /** \brief Creates a graph G from the triangulation given by the input .OFF file.
- *
- */
- void set_graph_from_OFF() {
- remove_edges(one_skeleton);
- if (num_edges(one_skeleton_OFF))
- one_skeleton = one_skeleton_OFF;
- else
- std::cout << "No triangulation read in OFF file!" << std::endl;
- }
-
- public: // Set graph from Rips complex.
- /** \brief Creates a graph G from a Rips complex.
- *
- * @param[in] threshold threshold value for the Rips complex.
- * @param[in] distance distance used to compute the Rips complex.
- *
- */
- template <typename Distance>
- void set_graph_from_rips(double threshold, Distance distance) {
- remove_edges(one_skeleton);
- if (distances.size() == 0) compute_pairwise_distances(distance);
- for (int i = 0; i < n; i++) {
- for (int j = i + 1; j < n; j++) {
- if (distances[i][j] <= threshold) {
- boost::add_edge(vertices[i], vertices[j], one_skeleton);
- boost::put(boost::edge_weight, one_skeleton, boost::edge(vertices[i], vertices[j], one_skeleton).first,
- distances[i][j]);
- }
- }
- }
- }
-
- public:
- void set_graph_weights() {
- Index_map index = boost::get(boost::vertex_index, one_skeleton);
- Weight_map weight = boost::get(boost::edge_weight, one_skeleton);
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
- boost::put(weight, *ei,
- distances[index[boost::source(*ei, one_skeleton)]][index[boost::target(*ei, one_skeleton)]]);
- }
-
- public: // Pairwise distances.
- /** \private \brief Computes all pairwise distances.
- */
- template <typename Distance>
- void compute_pairwise_distances(Distance ref_distance) {
- double d;
- std::vector<double> zeros(n);
- for (int i = 0; i < n; i++) distances.push_back(zeros);
- std::string distance = point_cloud_name + "_dist";
- std::ifstream input(distance, std::ios::out | std::ios::binary);
-
- if (input.good()) {
- if (verbose) std::cout << "Reading distances..." << std::endl;
- for (int i = 0; i < n; i++) {
- for (int j = i; j < n; j++) {
- input.read((char*)&d, 8);
- distances[i][j] = d;
- distances[j][i] = d;
- }
- }
- input.close();
- } else {
- if (verbose) std::cout << "Computing distances..." << std::endl;
- input.close();
- std::ofstream output(distance, std::ios::out | std::ios::binary);
- for (int i = 0; i < n; i++) {
- int state = (int)floor(100 * (i * 1.0 + 1) / n) % 10;
- if (state == 0 && verbose) std::cout << "\r" << state << "%" << std::flush;
- for (int j = i; j < n; j++) {
- double dis = ref_distance(point_cloud[i], point_cloud[j]);
- distances[i][j] = dis;
- distances[j][i] = dis;
- output.write((char*)&dis, 8);
- }
- }
- output.close();
- if (verbose) std::cout << std::endl;
- }
- }
-
- public: // Automatic tuning of Rips complex.
- /** \brief Creates a graph G from a Rips complex whose threshold value is automatically tuned with subsampling---see
- * \cite Carriere17c.
- *
- * @param[in] distance distance between data points.
- * @param[in] N number of subsampling iteration (the default reasonable value is 100, but there is no guarantee on
- * how to choose it).
- * @result delta threshold used for computing the Rips complex.
- *
- */
- template <typename Distance>
- double set_graph_from_automatic_rips(Distance distance, int N = 100) {
- int m = floor(n / std::exp((1 + rate_power) * std::log(std::log(n) / std::log(rate_constant))));
- m = std::min(m, n - 1);
- double delta = 0;
-
- if (verbose) std::cout << n << " points in R^" << data_dimension << std::endl;
- if (verbose) std::cout << "Subsampling " << m << " points" << std::endl;
-
- if (distances.size() == 0) compute_pairwise_distances(distance);
-
- // This cannot be parallelized if thread_local is not defined
- // thread_local is not defined for XCode < v.8
- #if defined(GUDHI_USE_TBB) && defined(GUDHI_CAN_USE_CXX11_THREAD_LOCAL)
- tbb::mutex deltamutex;
- tbb::parallel_for(0, N, [&](int i){
- std::vector<int> samples(m);
- SampleWithoutReplacement(n, m, samples);
- double hausdorff_dist = 0;
- for (int j = 0; j < n; j++) {
- double mj = distances[j][samples[0]];
- for (int k = 1; k < m; k++) mj = std::min(mj, distances[j][samples[k]]);
- hausdorff_dist = std::max(hausdorff_dist, mj);
- }
- deltamutex.lock();
- delta += hausdorff_dist / N;
- deltamutex.unlock();
- });
- #else
- for (int i = 0; i < N; i++) {
- std::vector<int> samples(m);
- SampleWithoutReplacement(n, m, samples);
- double hausdorff_dist = 0;
- for (int j = 0; j < n; j++) {
- double mj = distances[j][samples[0]];
- for (int k = 1; k < m; k++) mj = std::min(mj, distances[j][samples[k]]);
- hausdorff_dist = std::max(hausdorff_dist, mj);
- }
- delta += hausdorff_dist / N;
- }
- #endif
-
- if (verbose) std::cout << "delta = " << delta << std::endl;
- set_graph_from_rips(delta, distance);
- return delta;
- }
-
- // *******************************************************************************************************************
- // Functions.
- // *******************************************************************************************************************
-
- public: // Set function from file.
- /** \brief Creates the function f from a file containing the function values.
- *
- * @param[in] func_file_name name of the input function file.
- *
- */
- void set_function_from_file(const std::string& func_file_name) {
- int i = 0;
- std::ifstream input(func_file_name);
- std::string line;
- double f;
- while (std::getline(input, line)) {
- std::stringstream stream(line);
- stream >> f;
- func.push_back(f);
- i++;
- }
- functional_cover = true;
- cover_name = func_file_name;
- }
-
- public: // Set function from kth coordinate
- /** \brief Creates the function f from the k-th coordinate of the point cloud P.
- *
- * @param[in] k coordinate to use (start at 0).
- *
- */
- void set_function_from_coordinate(int k) {
- for (int i = 0; i < n; i++) func.push_back(point_cloud[i][k]);
- functional_cover = true;
- cover_name = "coordinate " + std::to_string(k);
- }
-
- public: // Set function from vector.
- /** \brief Creates the function f from a vector stored in memory.
- *
- * @param[in] function input vector of values.
- *
- */
- template <class InputRange>
- void set_function_from_range(InputRange const& function) {
- for (int i = 0; i < n; i++) func.push_back(function[i]);
- functional_cover = true;
- }
-
- // *******************************************************************************************************************
- // Covers.
- // *******************************************************************************************************************
-
- public: // Automatic tuning of resolution.
- /** \brief Computes the optimal length of intervals
- * (i.e. the smallest interval length avoiding discretization artifacts---see \cite Carriere17c) for a functional
- * cover.
- *
- * @result reso interval length used to compute the cover.
- *
- */
- double set_automatic_resolution() {
- if (!functional_cover) {
- std::cout << "Cover needs to come from the preimages of a function." << std::endl;
- return 0;
- }
- if (type != "Nerve" && type != "GIC") {
- std::cout << "Type of complex needs to be specified." << std::endl;
- return 0;
- }
-
- double reso = 0;
- Index_map index = boost::get(boost::vertex_index, one_skeleton);
-
- if (type == "GIC") {
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
- reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] -
- func[index[boost::target(*ei, one_skeleton)]]));
- if (verbose) std::cout << "resolution = " << reso << std::endl;
- resolution_double = reso;
- }
-
- if (type == "Nerve") {
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
- reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] -
- func[index[boost::target(*ei, one_skeleton)]]) /
- gain);
- if (verbose) std::cout << "resolution = " << reso << std::endl;
- resolution_double = reso;
- }
-
- return reso;
- }
-
- public:
- /** \brief Sets a length of intervals from a value stored in memory.
- *
- * @param[in] reso length of intervals.
- *
- */
- void set_resolution_with_interval_length(double reso) { resolution_double = reso; }
- /** \brief Sets a number of intervals from a value stored in memory.
- *
- * @param[in] reso number of intervals.
- *
- */
- void set_resolution_with_interval_number(int reso) { resolution_int = reso; }
- /** \brief Sets a gain from a value stored in memory (default value 0.3).
- *
- * @param[in] g gain.
- *
- */
- void set_gain(double g = 0.3) { gain = g; }
-
- public: // Set cover with preimages of function.
- /** \brief Creates a cover C from the preimages of the function f.
- *
- */
- void set_cover_from_function() {
- if (resolution_double == -1 && resolution_int == -1) {
- std::cout << "Number and/or length of intervals not specified" << std::endl;
- return;
- }
- if (gain == -1) {
- std::cout << "Gain not specified" << std::endl;
- return;
- }
-
- // Read function values and compute min and max
- double minf = std::numeric_limits<float>::max();
- double maxf = std::numeric_limits<float>::lowest();
- for (int i = 0; i < n; i++) {
- minf = std::min(minf, func[i]);
- maxf = std::max(maxf, func[i]);
- }
- if (verbose) std::cout << "Min function value = " << minf << " and Max function value = " << maxf << std::endl;
-
- // Compute cover of im(f)
- std::vector<std::pair<double, double> > intervals;
- int res;
-
- if (resolution_double == -1) { // Case we use an integer for the number of intervals.
- double incr = (maxf - minf) / resolution_int;
- double x = minf;
- double alpha = (incr * gain) / (2 - 2 * gain);
- double y = minf + incr + alpha;
- std::pair<double, double> interm(x, y);
- intervals.push_back(interm);
- for (int i = 1; i < resolution_int - 1; i++) {
- x = minf + i * incr - alpha;
- y = minf + (i + 1) * incr + alpha;
- std::pair<double, double> inter(x, y);
- intervals.push_back(inter);
- }
- x = minf + (resolution_int - 1) * incr - alpha;
- y = maxf;
- std::pair<double, double> interM(x, y);
- intervals.push_back(interM);
- res = intervals.size();
- if (verbose) {
- for (int i = 0; i < res; i++)
- std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
- << std::endl;
- }
- } else {
- if (resolution_int == -1) { // Case we use a double for the length of the intervals.
- double x = minf;
- double y = x + resolution_double;
- while (y <= maxf && maxf - (y - gain * resolution_double) >= resolution_double) {
- std::pair<double, double> inter(x, y);
- intervals.push_back(inter);
- x = y - gain * resolution_double;
- y = x + resolution_double;
- }
- std::pair<double, double> interM(x, maxf);
- intervals.push_back(interM);
- res = intervals.size();
- if (verbose) {
- for (int i = 0; i < res; i++)
- std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
- << std::endl;
- }
- } else { // Case we use an integer and a double for the length of the intervals.
- double x = minf;
- double y = x + resolution_double;
- int count = 0;
- while (count < resolution_int && y <= maxf && maxf - (y - gain * resolution_double) >= resolution_double) {
- std::pair<double, double> inter(x, y);
- intervals.push_back(inter);
- count++;
- x = y - gain * resolution_double;
- y = x + resolution_double;
- }
- res = intervals.size();
- if (verbose) {
- for (int i = 0; i < res; i++)
- std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
- << std::endl;
- }
- }
- }
-
- // Sort points according to function values
- std::vector<int> points(n);
- for (int i = 0; i < n; i++) points[i] = i;
- std::sort(points.begin(), points.end(), [=](const int & p1, const int & p2){return (this->func[p1] < this->func[p2]);});
-
- int id = 0;
- int pos = 0;
- Index_map index = boost::get(boost::vertex_index, one_skeleton); // int maxc = -1;
- std::map<int, std::vector<int> > preimages;
- std::map<int, double> funcstd;
-
- if (verbose) std::cout << "Computing preimages..." << std::endl;
- for (int i = 0; i < res; i++) {
- // Find points in the preimage
- std::pair<double, double> inter1 = intervals[i];
- int tmp = pos;
- double u, v;
-
- if (i != res - 1) {
- if (i != 0) {
- std::pair<double, double> inter3 = intervals[i - 1];
- while (func[points[tmp]] < inter3.second && tmp != n) {
- preimages[i].push_back(points[tmp]);
- tmp++;
- }
- u = inter3.second;
- } else {
- u = inter1.first;
- }
-
- std::pair<double, double> inter2 = intervals[i + 1];
- while (func[points[tmp]] < inter2.first && tmp != n) {
- preimages[i].push_back(points[tmp]);
- tmp++;
- }
- v = inter2.first;
- pos = tmp;
- while (func[points[tmp]] < inter1.second && tmp != n) {
- preimages[i].push_back(points[tmp]);
- tmp++;
- }
-
- } else {
- std::pair<double, double> inter3 = intervals[i - 1];
- while (func[points[tmp]] < inter3.second && tmp != n) {
- preimages[i].push_back(points[tmp]);
- tmp++;
- }
- while (tmp != n) {
- preimages[i].push_back(points[tmp]);
- tmp++;
- }
- u = inter3.second;
- v = inter1.second;
- }
-
- funcstd[i] = 0.5 * (u + v);
- }
-
- #ifdef GUDHI_USE_TBB
- if (verbose) std::cout << "Computing connected components (parallelized)..." << std::endl;
- tbb::mutex covermutex, idmutex;
- tbb::parallel_for(0, res, [&](int i){
- // Compute connected components
- Graph G = one_skeleton.create_subgraph();
- int num = preimages[i].size();
- std::vector<int> component(num);
- for (int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G);
- boost::connected_components(G, &component[0]);
- int max = 0;
-
- // For each point in preimage
- for (int j = 0; j < num; j++) {
- // Update number of components in preimage
- if (component[j] > max) max = component[j];
-
- // Identify component with Cantor polynomial N^2 -> N
- int identifier = ((i + component[j])*(i + component[j]) + 3 * i + component[j]) / 2;
-
- // Update covers
- covermutex.lock();
- cover[preimages[i][j]].push_back(identifier);
- cover_back[identifier].push_back(preimages[i][j]);
- cover_fct[identifier] = i;
- cover_std[identifier] = funcstd[i];
- cover_color[identifier].second += func_color[preimages[i][j]];
- cover_color[identifier].first += 1;
- covermutex.unlock();
- }
-
- // Maximal dimension is total number of connected components
- idmutex.lock();
- id += max + 1;
- idmutex.unlock();
- });
- #else
- if (verbose) std::cout << "Computing connected components..." << std::endl;
- for (int i = 0; i < res; i++) {
- // Compute connected components
- Graph G = one_skeleton.create_subgraph();
- int num = preimages[i].size();
- std::vector<int> component(num);
- for (int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G);
- boost::connected_components(G, &component[0]);
- int max = 0;
-
- // For each point in preimage
- for (int j = 0; j < num; j++) {
- // Update number of components in preimage
- if (component[j] > max) max = component[j];
-
- // Identify component with Cantor polynomial N^2 -> N
- int identifier = (std::pow(i + component[j], 2) + 3 * i + component[j]) / 2;
-
- // Update covers
- cover[preimages[i][j]].push_back(identifier);
- cover_back[identifier].push_back(preimages[i][j]);
- cover_fct[identifier] = i;
- cover_std[identifier] = funcstd[i];
- cover_color[identifier].second += func_color[preimages[i][j]];
- cover_color[identifier].first += 1;
- }
-
- // Maximal dimension is total number of connected components
- id += max + 1;
- }
- #endif
-
- maximal_dim = id - 1;
- for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++)
- iit->second.second /= iit->second.first;
- }
-
- public: // Set cover from file.
- /** \brief Creates the cover C from a file containing the cover elements of each point (the order has to be the same
- * as in the input file!).
- *
- * @param[in] cover_file_name name of the input cover file.
- *
- */
- void set_cover_from_file(const std::string& cover_file_name) {
- int i = 0;
- int cov;
- std::vector<int> cov_elts, cov_number;
- std::ifstream input(cover_file_name);
- std::string line;
- while (std::getline(input, line)) {
- cov_elts.clear();
- std::stringstream stream(line);
- while (stream >> cov) {
- cov_elts.push_back(cov);
- cov_number.push_back(cov);
- cover_fct[cov] = cov;
- cover_color[cov].second += func_color[i];
- cover_color[cov].first++;
- cover_back[cov].push_back(i);
- }
- cover[i] = cov_elts;
- i++;
- }
-
- std::sort(cov_number.begin(), cov_number.end());
- std::vector<int>::iterator it = std::unique(cov_number.begin(), cov_number.end());
- cov_number.resize(std::distance(cov_number.begin(), it));
-
- maximal_dim = cov_number.size() - 1;
- for (int i = 0; i <= maximal_dim; i++) cover_color[i].second /= cover_color[i].first;
- cover_name = cover_file_name;
- }
-
- public: // Set cover from Voronoi
- /** \brief Creates the cover C from the Voronoï cells of a subsampling of the point cloud.
- *
- * @param[in] distance distance between the points.
- * @param[in] m number of points in the subsample.
- *
- */
- template <typename Distance>
- void set_cover_from_Voronoi(Distance distance, int m = 100) {
- voronoi_subsamples.resize(m);
- SampleWithoutReplacement(n, m, voronoi_subsamples);
- if (distances.size() == 0) compute_pairwise_distances(distance);
- set_graph_weights();
- Weight_map weight = boost::get(boost::edge_weight, one_skeleton);
- Index_map index = boost::get(boost::vertex_index, one_skeleton);
- std::vector<double> mindist(n);
- for (int j = 0; j < n; j++) mindist[j] = std::numeric_limits<double>::max();
-
- // Compute the geodesic distances to subsamples with Dijkstra
- #ifdef GUDHI_USE_TBB
- if (verbose) std::cout << "Computing geodesic distances (parallelized)..." << std::endl;
- tbb::mutex coverMutex; tbb::mutex mindistMutex;
- tbb::parallel_for(0, m, [&](int i){
- int seed = voronoi_subsamples[i];
- std::vector<double> dmap(n);
- boost::dijkstra_shortest_paths(
- one_skeleton, vertices[seed],
- boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index)));
-
- coverMutex.lock(); mindistMutex.lock();
- for (int j = 0; j < n; j++)
- if (mindist[j] > dmap[j]) {
- mindist[j] = dmap[j];
- if (cover[j].size() == 0)
- cover[j].push_back(i);
- else
- cover[j][0] = i;
- }
- coverMutex.unlock(); mindistMutex.unlock();
- });
- #else
- for (int i = 0; i < m; i++) {
- if (verbose) std::cout << "Computing geodesic distances to seed " << i << "..." << std::endl;
- int seed = voronoi_subsamples[i];
- std::vector<double> dmap(n);
- boost::dijkstra_shortest_paths(
- one_skeleton, vertices[seed],
- boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index)));
-
- for (int j = 0; j < n; j++)
- if (mindist[j] > dmap[j]) {
- mindist[j] = dmap[j];
- if (cover[j].size() == 0)
- cover[j].push_back(i);
- else
- cover[j][0] = i;
- }
- }
- #endif
-
- for (int i = 0; i < n; i++) {
- cover_back[cover[i][0]].push_back(i);
- cover_color[cover[i][0]].second += func_color[i];
- cover_color[cover[i][0]].first++;
- }
- for (int i = 0; i < m; i++) cover_color[i].second /= cover_color[i].first;
- maximal_dim = m - 1;
- cover_name = "Voronoi";
- }
-
- public: // return subset of data corresponding to a node
- /** \brief Returns the data subset corresponding to a specific node of the created complex.
- *
- * @param[in] c ID of the node.
- * @result cover_back(c) vector of IDs of data points.
- *
- */
- const std::vector<int>& subpopulation(int c) { return cover_back[name2idinv[c]]; }
-
- // *******************************************************************************************************************
- // Visualization.
- // *******************************************************************************************************************
-
- public: // Set color from file.
- /** \brief Computes the function used to color the nodes of the simplicial complex from a file containing the function
- * values.
- *
- * @param[in] color_file_name name of the input color file.
- *
- */
- void set_color_from_file(const std::string& color_file_name) {
- int i = 0;
- std::ifstream input(color_file_name);
- std::string line;
- double f;
- while (std::getline(input, line)) {
- std::stringstream stream(line);
- stream >> f;
- func_color.push_back(f);
- i++;
- }
- color_name = color_file_name;
- }
-
- public: // Set color from kth coordinate
- /** \brief Computes the function used to color the nodes of the simplicial complex from the k-th coordinate.
- *
- * @param[in] k coordinate to use (start at 0).
- *
- */
- void set_color_from_coordinate(int k = 0) {
- for (int i = 0; i < n; i++) func_color.push_back(point_cloud[i][k]);
- color_name = "coordinate ";
- color_name.append(std::to_string(k));
- }
-
- public: // Set color from vector.
- /** \brief Computes the function used to color the nodes of the simplicial complex from a vector stored in memory.
- *
- * @param[in] color input vector of values.
- *
- */
- void set_color_from_vector(std::vector<double> color) {
- for (unsigned int i = 0; i < color.size(); i++) func_color.push_back(color[i]);
- }
-
- public: // Create a .dot file that can be compiled with neato to produce a .pdf file.
- /** \brief Creates a .dot file called SC.dot for neato (part of the graphviz package) once the simplicial complex is
- * computed to get a visualization
- * of its 1-skeleton in a .pdf file.
- */
- void plot_DOT() {
- std::string mapp = point_cloud_name + "_sc.dot";
- std::ofstream graphic(mapp);
-
- double maxv = std::numeric_limits<double>::lowest();
- double minv = std::numeric_limits<double>::max();
- for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
- maxv = std::max(maxv, iit->second.second);
- minv = std::min(minv, iit->second.second);
- }
-
- int k = 0;
- std::vector<int> nodes;
- nodes.clear();
-
- graphic << "graph GIC {" << std::endl;
- int id = 0;
- for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
- if (iit->second.first > mask) {
- nodes.push_back(iit->first);
- name2id[iit->first] = id;
- name2idinv[id] = iit->first;
- id++;
- graphic << name2id[iit->first] << "[shape=circle fontcolor=black color=black label=\"" << name2id[iit->first]
- << ":" << iit->second.first << "\" style=filled fillcolor=\""
- << (1 - (maxv - iit->second.second) / (maxv - minv)) * 0.6 << ", 1, 1\"]" << std::endl;
- k++;
- }
- }
- int ke = 0;
- int num_simplices = simplices.size();
- for (int i = 0; i < num_simplices; i++)
- if (simplices[i].size() == 2) {
- if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) {
- graphic << " " << name2id[simplices[i][0]] << " -- " << name2id[simplices[i][1]] << " [weight=15];"
- << std::endl;
- ke++;
- }
- }
- graphic << "}";
- graphic.close();
- std::cout << mapp << " file generated. It can be visualized with e.g. neato." << std::endl;
- }
-
- public: // Create a .txt file that can be compiled with KeplerMapper.
- /** \brief Creates a .txt file called SC.txt describing the 1-skeleton, which can then be plotted with e.g.
- * KeplerMapper.
- */
- void write_info() {
- int num_simplices = simplices.size();
- int num_edges = 0;
- std::string mapp = point_cloud_name + "_sc.txt";
- std::ofstream graphic(mapp);
-
- for (int i = 0; i < num_simplices; i++)
- if (simplices[i].size() == 2)
- if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) num_edges++;
-
- graphic << point_cloud_name << std::endl;
- graphic << cover_name << std::endl;
- graphic << color_name << std::endl;
- graphic << resolution_double << " " << gain << std::endl;
- graphic << cover_color.size() << " " << num_edges << std::endl;
-
- int id = 0;
- for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
- graphic << id << " " << iit->second.second << " " << iit->second.first << std::endl;
- name2id[iit->first] = id;
- name2idinv[id] = iit->first;
- id++;
- }
-
- for (int i = 0; i < num_simplices; i++)
- if (simplices[i].size() == 2)
- if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask)
- graphic << name2id[simplices[i][0]] << " " << name2id[simplices[i][1]] << std::endl;
- graphic.close();
- std::cout << mapp
- << " generated. It can be visualized with e.g. python KeplerMapperVisuFromTxtFile.py and firefox."
- << std::endl;
- }
-
- public: // Create a .off file that can be visualized (e.g. with Geomview).
- /** \brief Creates a .off file called SC.off for 3D visualization, which contains the 2-skeleton of the GIC.
- * This function assumes that the cover has been computed with Voronoi. If data points are in 1D or 2D,
- * the remaining coordinates of the points embedded in 3D are set to 0.
- */
- void plot_OFF() {
- assert(cover_name == "Voronoi");
-
- int m = voronoi_subsamples.size();
- int numedges = 0;
- int numfaces = 0;
- std::vector<std::vector<int> > edges, faces;
- int numsimplices = simplices.size();
-
- std::string mapp = point_cloud_name + "_sc.off";
- std::ofstream graphic(mapp);
-
- graphic << "OFF" << std::endl;
- for (int i = 0; i < numsimplices; i++) {
- if (simplices[i].size() == 2) {
- numedges++;
- edges.push_back(simplices[i]);
- }
- if (simplices[i].size() == 3) {
- numfaces++;
- faces.push_back(simplices[i]);
- }
- }
- graphic << m << " " << numedges + numfaces << std::endl;
- for (int i = 0; i < m; i++) {
- if (data_dimension <= 3) {
- for (int j = 0; j < data_dimension; j++) graphic << point_cloud[voronoi_subsamples[i]][j] << " ";
- for (int j = data_dimension; j < 3; j++) graphic << 0 << " ";
- graphic << std::endl;
- } else {
- for (int j = 0; j < 3; j++) graphic << point_cloud[voronoi_subsamples[i]][j] << " ";
- }
- }
- for (int i = 0; i < numedges; i++) graphic << 2 << " " << edges[i][0] << " " << edges[i][1] << std::endl;
- for (int i = 0; i < numfaces; i++)
- graphic << 3 << " " << faces[i][0] << " " << faces[i][1] << " " << faces[i][2] << std::endl;
- graphic.close();
- std::cout << mapp << " generated. It can be visualized with e.g. geomview." << std::endl;
- }
-
- // *******************************************************************************************************************
- // Extended Persistence Diagrams.
- // *******************************************************************************************************************
-
- public:
- /** \brief Computes the extended persistence diagram of the complex.
- *
- */
- void compute_PD() {
- Simplex_tree st;
-
- // Compute max and min
- double maxf = std::numeric_limits<double>::lowest();
- double minf = std::numeric_limits<double>::max();
- for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) {
- maxf = std::max(maxf, it->second);
- minf = std::min(minf, it->second);
- }
-
- // Build filtration
- for (auto const& simplex : simplices) {
- std::vector<int> splx = simplex; splx.push_back(-2);
- st.insert_simplex_and_subfaces(splx, -3);
- }
-
- for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) {
- int vertex = it->first; float val = it->second;
- int vert[] = {vertex}; int edge[] = {vertex, -2};
- st.assign_filtration(st.find(vert), -2 + (val - minf)/(maxf - minf));
- st.assign_filtration(st.find(edge), 2 - (val - minf)/(maxf - minf));
- }
- st.make_filtration_non_decreasing();
-
- // Compute PD
- Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Gudhi::persistent_cohomology::Field_Zp> pcoh(st); pcoh.init_coefficients(2);
- pcoh.compute_persistent_cohomology();
-
- // Output PD
- int max_dim = st.dimension();
- for (int i = 0; i < max_dim; i++) {
- std::vector<std::pair<double, double> > bars = pcoh.intervals_in_dimension(i);
- int num_bars = bars.size(); if(i == 0) num_bars -= 1;
- if(verbose) std::cout << num_bars << " interval(s) in dimension " << i << ":" << std::endl;
- for (int j = 0; j < num_bars; j++) {
- double birth = bars[j].first;
- double death = bars[j].second;
- if (i == 0 && std::isinf(death)) continue;
- if (birth < 0)
- birth = minf + (birth + 2) * (maxf - minf);
- else
- birth = minf + (2 - birth) * (maxf - minf);
- if (death < 0)
- death = minf + (death + 2) * (maxf - minf);
- else
- death = minf + (2 - death) * (maxf - minf);
- PD.push_back(std::pair<double, double>(birth, death));
- if (verbose) std::cout << " [" << birth << ", " << death << "]" << std::endl;
- }
- }
- }
-
- public:
- /** \brief Computes bootstrapped distances distribution.
- *
- * @param[in] N number of bootstrap iterations.
- *
- */
- void compute_distribution(unsigned int N = 100) {
- unsigned int sz = distribution.size();
- if (sz >= N) {
- std::cout << "Already done!" << std::endl;
- } else {
- for (unsigned int i = 0; i < N - sz; i++) {
- if (verbose) std::cout << "Computing " << i << "th bootstrap, bottleneck distance = ";
-
- Cover_complex Cboot; Cboot.n = this->n; Cboot.data_dimension = this->data_dimension; Cboot.type = this->type; Cboot.functional_cover = true;
-
- std::vector<int> boot(this->n);
- for (int j = 0; j < this->n; j++) {
- double u = GetUniform();
- int id = std::floor(u * (this->n)); boot[j] = id;
- Cboot.point_cloud.push_back(this->point_cloud[id]); Cboot.cover.emplace_back(); Cboot.func.push_back(this->func[id]);
- boost::add_vertex(Cboot.one_skeleton_OFF); Cboot.vertices.push_back(boost::add_vertex(Cboot.one_skeleton));
- }
- Cboot.set_color_from_vector(Cboot.func);
-
- for (int j = 0; j < n; j++) {
- std::vector<double> dist(n);
- for (int k = 0; k < n; k++) dist[k] = distances[boot[j]][boot[k]];
- Cboot.distances.push_back(dist);
- }
-
- Cboot.set_graph_from_automatic_rips(Gudhi::Euclidean_distance());
- Cboot.set_gain();
- Cboot.set_automatic_resolution();
- Cboot.set_cover_from_function();
- Cboot.find_simplices();
- Cboot.compute_PD();
- double db = Gudhi::persistence_diagram::bottleneck_distance(this->PD, Cboot.PD);
- if (verbose) std::cout << db << std::endl;
- distribution.push_back(db);
- }
-
- std::sort(distribution.begin(), distribution.end());
- }
- }
-
- public:
- /** \brief Computes the bottleneck distance threshold corresponding to a specific confidence level.
- *
- * @param[in] alpha Confidence level.
- *
- */
- double compute_distance_from_confidence_level(double alpha) {
- unsigned int N = distribution.size();
- double d = distribution[std::floor(alpha * N)];
- if (verbose) std::cout << "Distance corresponding to confidence " << alpha << " is " << d << std::endl;
- return d;
- }
-
- public:
- /** \brief Computes the confidence level of a specific bottleneck distance threshold.
- *
- * @param[in] d Bottleneck distance.
- *
- */
- double compute_confidence_level_from_distance(double d) {
- unsigned int N = distribution.size();
- double level = 1;
- for (unsigned int i = 0; i < N; i++)
- if (distribution[i] > d){ level = i * 1.0 / N; break; }
- if (verbose) std::cout << "Confidence level of distance " << d << " is " << level << std::endl;
- return level;
- }
-
- public:
- /** \brief Computes the p-value, i.e. the opposite of the confidence level of the largest bottleneck
- * distance preserving the points in the persistence diagram of the output simplicial complex.
- *
- */
- double compute_p_value() {
- double distancemin = std::numeric_limits<double>::max(); int N = PD.size();
- for (int i = 0; i < N; i++) distancemin = std::min(distancemin, 0.5 * std::abs(PD[i].second - PD[i].first));
- double p_value = 1 - compute_confidence_level_from_distance(distancemin);
- if (verbose) std::cout << "p value = " << p_value << std::endl;
- return p_value;
- }
-
- // *******************************************************************************************************************
- // Computation of simplices.
- // *******************************************************************************************************************
-
- public:
- /** \brief Creates the simplicial complex.
- *
- * @param[in] complex SimplicialComplex to be created.
- *
- */
- template <typename SimplicialComplex>
- void create_complex(SimplicialComplex& complex) {
- unsigned int dimension = 0;
- for (auto const& simplex : simplices) {
- int numvert = simplex.size();
- double filt = std::numeric_limits<double>::lowest();
- for (int i = 0; i < numvert; i++) filt = std::max(cover_color[simplex[i]].second, filt);
- complex.insert_simplex_and_subfaces(simplex, filt);
- if (dimension < simplex.size() - 1) dimension = simplex.size() - 1;
- }
- }
-
- public:
- /** \brief Computes the simplices of the simplicial complex.
- */
- void find_simplices() {
- if (type != "Nerve" && type != "GIC") {
- std::cout << "Type of complex needs to be specified." << std::endl;
- return;
- }
-
- if (type == "Nerve") {
- for(int i = 0; i < n; i++) simplices.push_back(cover[i]);
- std::sort(simplices.begin(), simplices.end());
- std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
- simplices.resize(std::distance(simplices.begin(), it));
- }
-
- if (type == "GIC") {
- Index_map index = boost::get(boost::vertex_index, one_skeleton);
-
- if (functional_cover) {
- // Computes the simplices in the GIC by looking at all the edges of the graph and adding the
- // corresponding edges in the GIC if the images of the endpoints belong to consecutive intervals.
-
- if (gain >= 0.5)
- throw std::invalid_argument(
- "the output of this function is correct ONLY if the cover is minimal, i.e. the gain is less than 0.5.");
-
- // Loop on all edges.
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) {
- int nums = cover[index[boost::source(*ei, one_skeleton)]].size();
- for (int i = 0; i < nums; i++) {
- int vs = cover[index[boost::source(*ei, one_skeleton)]][i];
- int numt = cover[index[boost::target(*ei, one_skeleton)]].size();
- for (int j = 0; j < numt; j++) {
- int vt = cover[index[boost::target(*ei, one_skeleton)]][j];
- if (cover_fct[vs] == cover_fct[vt] + 1 || cover_fct[vt] == cover_fct[vs] + 1) {
- std::vector<int> edge(2);
- edge[0] = std::min(vs, vt);
- edge[1] = std::max(vs, vt);
- simplices.push_back(edge);
- goto afterLoop;
- }
- }
- }
- afterLoop:;
- }
- std::sort(simplices.begin(), simplices.end());
- std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
- simplices.resize(std::distance(simplices.begin(), it));
-
- } else {
- // Find edges to keep
- Simplex_tree st;
- boost::graph_traits<Graph>::edge_iterator ei, ei_end;
- for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
- if (!(cover[index[boost::target(*ei, one_skeleton)]].size() == 1 &&
- cover[index[boost::target(*ei, one_skeleton)]] == cover[index[boost::source(*ei, one_skeleton)]])) {
- std::vector<int> edge(2);
- edge[0] = index[boost::source(*ei, one_skeleton)];
- edge[1] = index[boost::target(*ei, one_skeleton)];
- st.insert_simplex_and_subfaces(edge);
- }
-
- // st.insert_graph(one_skeleton);
-
- // Build the Simplex Tree corresponding to the graph
- st.expansion(maximal_dim);
-
- // Find simplices of GIC
- simplices.clear();
- for (auto simplex : st.complex_simplex_range()) {
- if (!st.has_children(simplex)) {
- std::vector<int> simplx;
- for (auto vertex : st.simplex_vertex_range(simplex)) {
- unsigned int sz = cover[vertex].size();
- for (unsigned int i = 0; i < sz; i++) {
- simplx.push_back(cover[vertex][i]);
- }
- }
- std::sort(simplx.begin(), simplx.end());
- std::vector<int>::iterator it = std::unique(simplx.begin(), simplx.end());
- simplx.resize(std::distance(simplx.begin(), it));
- simplices.push_back(simplx);
- }
- }
- std::sort(simplices.begin(), simplices.end());
- std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
- simplices.resize(std::distance(simplices.begin(), it));
- }
- }
- }
-};
-
-} // namespace cover_complex
-
-} // namespace Gudhi
-
-#endif // GIC_H_
diff --git a/include/gudhi/Graph_matching.h b/include/gudhi/Graph_matching.h
deleted file mode 100644
index 313e7d9c..00000000
--- a/include/gudhi/Graph_matching.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Francois Godi
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GRAPH_MATCHING_H_
-#define GRAPH_MATCHING_H_
-
-#include <gudhi/Neighbors_finder.h>
-
-#include <vector>
-#include <unordered_set>
-#include <algorithm>
-
-namespace Gudhi {
-
-namespace persistence_diagram {
-
-/** \internal \brief Structure representing a graph matching. The graph is a Persistence_diagrams_graph.
- *
- * \ingroup bottleneck_distance
- */
-class Graph_matching {
- public:
- /** \internal \brief Constructor constructing an empty matching. */
- explicit Graph_matching(Persistence_graph &g);
- /** \internal \brief Is the matching perfect ? */
- bool perfect() const;
- /** \internal \brief Augments the matching with a maximal set of edge-disjoint shortest augmenting paths. */
- bool multi_augment();
- /** \internal \brief Sets the maximum length of the edges allowed to be added in the matching, 0 initially. */
- void set_r(double r);
-
- private:
- Persistence_graph* gp;
- double r;
- /** \internal \brief Given a point from V, provides its matched point in U, null_point_index() if there isn't. */
- std::vector<int> v_to_u;
- /** \internal \brief All the unmatched points in U. */
- std::unordered_set<int> unmatched_in_u;
-
- /** \internal \brief Provides a Layered_neighbors_finder dividing the graph in layers. Basically a BFS. */
- Layered_neighbors_finder layering() const;
- /** \internal \brief Augments the matching with a simple path no longer than max_depth. Basically a DFS. */
- bool augment(Layered_neighbors_finder & layered_nf, int u_start_index, int max_depth);
- /** \internal \brief Update the matching with the simple augmenting path given as parameter. */
- void update(std::vector<int> & path);
-};
-
-inline Graph_matching::Graph_matching(Persistence_graph& g)
- : gp(&g), r(0.), v_to_u(g.size(), null_point_index()), unmatched_in_u(g.size()) {
- for (int u_point_index = 0; u_point_index < g.size(); ++u_point_index)
- unmatched_in_u.insert(u_point_index);
-}
-
-inline bool Graph_matching::perfect() const {
- return unmatched_in_u.empty();
-}
-
-inline bool Graph_matching::multi_augment() {
- if (perfect())
- return false;
- Layered_neighbors_finder layered_nf(layering());
- int max_depth = layered_nf.vlayers_number()*2 - 1;
- double rn = sqrt(gp->size());
- // verification of a necessary criterion in order to shortcut if possible
- if (max_depth < 0 || (unmatched_in_u.size() > rn && max_depth >= rn))
- return false;
- bool successful = false;
- std::vector<int> tries(unmatched_in_u.cbegin(), unmatched_in_u.cend());
- for (auto it = tries.cbegin(); it != tries.cend(); it++)
- // 'augment' has side-effects which have to be always executed, don't change order
- successful = augment(layered_nf, *it, max_depth) || successful;
- return successful;
-}
-
-inline void Graph_matching::set_r(double r) {
- this->r = r;
-}
-
-inline bool Graph_matching::augment(Layered_neighbors_finder & layered_nf, int u_start_index, int max_depth) {
- // V vertices have at most one successor, thus when we backtrack from U we can directly pop_back 2 vertices.
- std::vector<int> path;
- path.emplace_back(u_start_index);
- do {
- if (static_cast<int> (path.size()) > max_depth) {
- path.pop_back();
- path.pop_back();
- }
- if (path.empty())
- return false;
- path.emplace_back(layered_nf.pull_near(path.back(), static_cast<int> (path.size()) / 2));
- while (path.back() == null_point_index()) {
- path.pop_back();
- path.pop_back();
- if (path.empty())
- return false;
- path.pop_back();
- path.emplace_back(layered_nf.pull_near(path.back(), path.size() / 2));
- }
- path.emplace_back(v_to_u.at(path.back()));
- } while (path.back() != null_point_index());
- // if v_to_u.at(path.back()) has no successor, path.back() is an exposed vertex
- path.pop_back();
- update(path);
- return true;
-}
-
-inline Layered_neighbors_finder Graph_matching::layering() const {
- std::vector<int> u_vertices(unmatched_in_u.cbegin(), unmatched_in_u.cend());
- std::vector<int> v_vertices;
- Neighbors_finder nf(*gp, r);
- for (int v_point_index = 0; v_point_index < gp->size(); ++v_point_index)
- nf.add(v_point_index);
- Layered_neighbors_finder layered_nf(*gp, r);
- for (int layer = 0; !u_vertices.empty(); layer++) {
- // one layer is one step in the BFS
- for (auto it1 = u_vertices.cbegin(); it1 != u_vertices.cend(); ++it1) {
- std::vector<int> u_succ(nf.pull_all_near(*it1));
- for (auto it2 = u_succ.begin(); it2 != u_succ.end(); ++it2) {
- layered_nf.add(*it2, layer);
- v_vertices.emplace_back(*it2);
- }
- }
- // When the above for finishes, we have progress of one half-step (from U to V) in the BFS
- u_vertices.clear();
- bool end = false;
- for (auto it = v_vertices.cbegin(); it != v_vertices.cend(); it++)
- if (v_to_u.at(*it) == null_point_index())
- // we stop when a nearest exposed V vertex (from U exposed vertices) has been found
- end = true;
- else
- u_vertices.emplace_back(v_to_u.at(*it));
- // When the above for finishes, we have progress of one half-step (from V to U) in the BFS
- if (end)
- return layered_nf;
- v_vertices.clear();
- }
- return layered_nf;
-}
-
-inline void Graph_matching::update(std::vector<int>& path) {
- // Must return 1.
- unmatched_in_u.erase(path.front());
- for (auto it = path.cbegin(); it != path.cend(); ++it) {
- // Be careful, the iterator is incremented twice each time
- int tmp = *it;
- v_to_u[*(++it)] = tmp;
- }
-}
-
-
-} // namespace persistence_diagram
-
-} // namespace Gudhi
-
-#endif // GRAPH_MATCHING_H_
diff --git a/include/gudhi/Hasse_complex.h b/include/gudhi/Hasse_complex.h
deleted file mode 100644
index efcaea55..00000000
--- a/include/gudhi/Hasse_complex.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HASSE_COMPLEX_H_
-#define HASSE_COMPLEX_H_
-
-#include <gudhi/allocator.h>
-
-#include <boost/iterator/counting_iterator.hpp>
-
-#include <algorithm>
-#include <utility> // for pair
-#include <vector>
-#include <limits> // for infinity value
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_for.h>
-#endif
-
-namespace Gudhi {
-
-template < class HasseCpx >
-struct Hasse_simplex {
- // Complex_ds must verify that cpx->key(sh) is the order of sh in the filtration
-
- template< class Complex_ds >
- Hasse_simplex(Complex_ds & cpx
- , typename Complex_ds::Simplex_handle sh)
- : filtration_(cpx.filtration(sh))
- , boundary_() {
- boundary_.reserve(cpx.dimension(sh) + 1);
- for (auto b_sh : cpx.boundary_simplex_range(sh)) {
- boundary_.push_back(cpx.key(b_sh));
- }
- }
-
- Hasse_simplex(typename HasseCpx::Simplex_key key
- , typename HasseCpx::Filtration_value fil
- , std::vector<typename HasseCpx::Simplex_handle> const& boundary)
- : key_(key)
- , filtration_(fil)
- , boundary_(boundary) { }
-
- typename HasseCpx::Simplex_key key_;
- typename HasseCpx::Filtration_value filtration_;
- std::vector<typename HasseCpx::Simplex_handle> boundary_;
-};
-
-/** \private
- * \brief Data structure representing a Hasse diagram, i.e.
- * a complex where all codimension 1 incidence
- * relations are explicitly encoded.
- *
- * \implements FilteredComplex
- * \ingroup simplex_tree
- */
-template < typename FiltrationValue = double
-, typename SimplexKey = int
-, typename VertexHandle = int
->
-class Hasse_complex {
- public:
- typedef Hasse_simplex<Hasse_complex> Hasse_simp;
- typedef FiltrationValue Filtration_value;
- typedef SimplexKey Simplex_key;
- typedef int Simplex_handle; // index in vector complex_
-
- typedef boost::counting_iterator< Simplex_handle > Filtration_simplex_iterator;
- typedef boost::iterator_range<Filtration_simplex_iterator> Filtration_simplex_range;
-
- typedef typename std::vector< Simplex_handle >::iterator Boundary_simplex_iterator;
- typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
-
- typedef typename std::vector< Simplex_handle >::iterator Skeleton_simplex_iterator;
- typedef boost::iterator_range< Skeleton_simplex_iterator > Skeleton_simplex_range;
-
- /* only dimension 0 skeleton_simplex_range(...) */
- Skeleton_simplex_range skeleton_simplex_range(int dim = 0) {
- if (dim != 0) {
- std::cerr << "Dimension must be 0 \n";
- }
- return Skeleton_simplex_range(vertices_.begin(), vertices_.end());
- }
-
- template < class Complex_ds >
- Hasse_complex(Complex_ds & cpx)
- : complex_(cpx.num_simplices())
- , vertices_()
- , num_vertices_()
- , dim_max_(cpx.dimension()) {
- int size = complex_.size();
-#ifdef GUDHI_USE_TBB
- tbb::parallel_for(0, size, [&](int idx){new (&complex_[idx]) Hasse_simp(cpx, cpx.simplex(idx));});
- for (int idx=0; idx < size; ++idx)
- if (complex_[idx].boundary_.empty())
- vertices_.push_back(idx);
-#else
- for (int idx=0; idx < size; ++idx) {
- new (&complex_[idx]) Hasse_simp(cpx, cpx.simplex(idx));
- if (complex_[idx].boundary_.empty())
- vertices_.push_back(idx);
- }
-#endif
- }
-
- Hasse_complex()
- : complex_()
- , vertices_()
- , num_vertices_(0)
- , dim_max_(-1) { }
-
- size_t num_simplices() {
- return complex_.size();
- }
-
- Filtration_simplex_range filtration_simplex_range() {
- return Filtration_simplex_range(Filtration_simplex_iterator(0)
- , Filtration_simplex_iterator(complex_.size()));
- }
-
- Simplex_key key(Simplex_handle sh) {
- return complex_[sh].key_;
- }
-
- Simplex_key null_key() {
- return -1;
- }
-
- Simplex_handle simplex(Simplex_key key) {
- if (key == null_key()) return null_simplex();
- return key;
- }
-
- Simplex_handle null_simplex() {
- return -1;
- }
-
- Filtration_value filtration(Simplex_handle sh) {
- if (sh == null_simplex()) {
- return std::numeric_limits<Filtration_value>::infinity();
- }
- return complex_[sh].filtration_;
- }
-
- int dimension(Simplex_handle sh) {
- if (complex_[sh].boundary_.empty()) return 0;
- return complex_[sh].boundary_.size() - 1;
- }
-
- int dimension() {
- return dim_max_;
- }
-
- std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
- return std::pair<Simplex_handle, Simplex_handle>(complex_[sh].boundary_[0]
- , complex_[sh].boundary_[1]);
- }
-
- void assign_key(Simplex_handle sh, Simplex_key key) {
- complex_[sh].key_ = key;
- }
-
- Boundary_simplex_range boundary_simplex_range(Simplex_handle sh) {
- return Boundary_simplex_range(complex_[sh].boundary_.begin()
- , complex_[sh].boundary_.end());
- }
-
- void display_simplex(Simplex_handle sh) {
- std::cout << dimension(sh) << " ";
- for (auto sh_b : boundary_simplex_range(sh)) std::cout << sh_b << " ";
- std::cout << " " << filtration(sh) << " key=" << key(sh);
- }
-
- void initialize_filtration() {
- // Setting the keys is done by pcoh, Simplex_tree doesn't do it either.
-#if 0
- Simplex_key key = 0;
- for (auto & h_simp : complex_)
- h_simp.key_ = key++;
-#endif
- }
-
- std::vector< Hasse_simp, Gudhi::no_init_allocator<Hasse_simp> > complex_;
- std::vector<Simplex_handle> vertices_;
- size_t num_vertices_;
- int dim_max_;
-};
-
-template< typename T1, typename T2, typename T3 >
-std::istream& operator>>(std::istream & is
- , Hasse_complex< T1, T2, T3 > & hcpx) {
- assert(hcpx.num_simplices() == 0);
-
- size_t num_simp;
- is >> num_simp;
- hcpx.complex_.reserve(num_simp);
-
- std::vector< typename Hasse_complex<T1, T2, T3>::Simplex_key > boundary;
- typename Hasse_complex<T1, T2, T3>::Filtration_value fil;
- typename Hasse_complex<T1, T2, T3>::Filtration_value max_fil = 0;
- int max_dim = -1;
- int key = 0;
- // read all simplices in the file as a list of vertices
- while (read_hasse_simplex(is, boundary, fil)) {
- // insert every simplex in the simplex tree
- hcpx.complex_.emplace_back(key, fil, boundary);
-
- if (max_dim < hcpx.dimension(key)) {
- max_dim = hcpx.dimension(key);
- }
- if (hcpx.dimension(key) == 0) {
- hcpx.vertices_.push_back(key);
- }
- if (max_fil < fil) {
- max_fil = fil;
- }
-
- ++key;
- boundary.clear();
- }
-
- hcpx.dim_max_ = max_dim;
-
- return is;
-}
-
-} // namespace Gudhi
-
-#endif // HASSE_COMPLEX_H_
diff --git a/include/gudhi/Internal_point.h b/include/gudhi/Internal_point.h
deleted file mode 100644
index 7f350f64..00000000
--- a/include/gudhi/Internal_point.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Francois Godi
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef INTERNAL_POINT_H_
-#define INTERNAL_POINT_H_
-
-namespace Gudhi {
-
-namespace persistence_diagram {
-
-/** \internal \brief Returns the used index for encoding none of the points */
-int null_point_index();
-
-/** \internal \typedef \brief Internal_point is the internal points representation, indexes used outside. */
-struct Internal_point {
- double vec[2];
- int point_index;
-
- Internal_point() { }
-
- Internal_point(double x, double y, int p_i) {
- vec[0] = x;
- vec[1] = y;
- point_index = p_i;
- }
-
- double x() const {
- return vec[ 0 ];
- }
-
- double y() const {
- return vec[ 1 ];
- }
-
- double& x() {
- return vec[ 0 ];
- }
-
- double& y() {
- return vec[ 1 ];
- }
-
- bool operator==(const Internal_point& p) const {
- return point_index == p.point_index;
- }
-
- bool operator!=(const Internal_point& p) const {
- return !(*this == p);
- }
-};
-
-inline int null_point_index() {
- return -1;
-}
-
-struct Construct_coord_iterator {
- typedef const double* result_type;
-
- const double* operator()(const Internal_point& p) const {
- return p.vec;
- }
-
- const double* operator()(const Internal_point& p, int) const {
- return p.vec + 2;
- }
-};
-
-} // namespace persistence_diagram
-
-} // namespace Gudhi
-
-#endif // INTERNAL_POINT_H_
diff --git a/include/gudhi/Kd_tree_search.h b/include/gudhi/Kd_tree_search.h
deleted file mode 100644
index ad1054e5..00000000
--- a/include/gudhi/Kd_tree_search.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef KD_TREE_SEARCH_H_
-#define KD_TREE_SEARCH_H_
-
-#include <CGAL/Orthogonal_k_neighbor_search.h>
-#include <CGAL/Orthogonal_incremental_neighbor_search.h>
-#include <CGAL/Search_traits.h>
-#include <CGAL/Search_traits_adapter.h>
-#include <CGAL/Fuzzy_sphere.h>
-#include <CGAL/property_map.h>
-
-#include <boost/property_map/property_map.hpp>
-#include <boost/iterator/counting_iterator.hpp>
-
-#include <cstddef>
-#include <vector>
-
-namespace Gudhi {
-namespace spatial_searching {
-
-
- /**
- * \class Kd_tree_search Kd_tree_search.h gudhi/Kd_tree_search.h
- * \brief Spatial tree data structure to perform (approximate) nearest and furthest neighbor search.
- *
- * \ingroup spatial_searching
- *
- * \details
- * The class Kd_tree_search is a tree-based data structure, based on
- * <a target="_blank" href="http://doc.cgal.org/latest/Spatial_searching/index.html">CGAL dD spatial searching data structures</a>.
- * It provides a simplified API to perform (approximate) nearest and furthest neighbor searches. Contrary to CGAL default behavior, the tree
- * does not store the points themselves, but stores indices.
- *
- * There are two types of queries: the <i>k-nearest or k-furthest neighbor query</i>, where <i>k</i> is fixed and the <i>k</i> nearest
- * or furthest points are computed right away,
- * and the <i>incremental nearest or furthest neighbor query</i>, where no number of neighbors is provided during the call, as the
- * neighbors will be computed incrementally when the iterator on the range is incremented.
- *
- * \tparam Search_traits must be a model of the <a target="_blank"
- * href="http://doc.cgal.org/latest/Spatial_searching/classSearchTraits.html">SearchTraits</a>
- * concept, such as the <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> class, which
- * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't.
- * \tparam Point_range is the type of the range that provides the points.
- * It must be a range whose iterator type is a `RandomAccessIterator`.
- */
-template <typename Search_traits, typename Point_range>
-class Kd_tree_search {
- typedef boost::iterator_property_map<
- typename Point_range::const_iterator,
- CGAL::Identity_property_map<std::ptrdiff_t> > Point_property_map;
-
- public:
- /// The Traits.
- typedef Search_traits Traits;
- /// Number type used for distances.
- typedef typename Traits::FT FT;
- /// The point type.
- typedef typename Point_range::value_type Point;
-
- typedef CGAL::Search_traits<
- FT, Point,
- typename Traits::Cartesian_const_iterator_d,
- typename Traits::Construct_cartesian_const_iterator_d> Traits_base;
-
- typedef CGAL::Search_traits_adapter<
- std::ptrdiff_t,
- Point_property_map,
- Traits_base> STraits;
- typedef CGAL::Distance_adapter<
- std::ptrdiff_t,
- Point_property_map,
- CGAL::Euclidean_distance<Traits_base> > Orthogonal_distance;
-
- typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search;
- typedef typename K_neighbor_search::Tree Tree;
- typedef typename K_neighbor_search::Distance Distance;
- /// \brief The range returned by a k-nearest or k-furthest neighbor search.
- /// Its value type is `std::pair<std::size_t, FT>` where `first` is the index
- /// of a point P and `second` is the squared distance between P and the query point.
- typedef K_neighbor_search KNS_range;
-
- typedef CGAL::Orthogonal_incremental_neighbor_search<
- STraits, Distance, CGAL::Sliding_midpoint<STraits>, Tree>
- Incremental_neighbor_search;
- /// \brief The range returned by an incremental nearest or furthest neighbor search.
- /// Its value type is `std::pair<std::size_t, FT>` where `first` is the index
- /// of a point P and `second` is the squared distance between P and the query point.
- typedef Incremental_neighbor_search INS_range;
-
- typedef CGAL::Fuzzy_sphere<STraits> Fuzzy_sphere;
- /// \brief Constructor
- /// @param[in] points Const reference to the point range. This range
- /// is not copied, so it should not be destroyed or modified afterwards.
- Kd_tree_search(Point_range const& points)
- : m_points(points),
- m_tree(boost::counting_iterator<std::ptrdiff_t>(0),
- boost::counting_iterator<std::ptrdiff_t>(points.size()),
- typename Tree::Splitter(),
- STraits(std::begin(points))) {
- // Build the tree now (we don't want to wait for the first query)
- m_tree.build();
- }
-
- /// \brief Constructor
- /// @param[in] points Const reference to the point range. This range
- /// is not copied, so it should not be destroyed or modified afterwards.
- /// @param[in] only_these_points Specifies the indices of the points that
- /// should be actually inserted into the tree. The other points are ignored.
- template <typename Point_indices_range>
- Kd_tree_search(
- Point_range const& points,
- Point_indices_range const& only_these_points)
- : m_points(points),
- m_tree(
- only_these_points.begin(), only_these_points.end(),
- typename Tree::Splitter(),
- STraits(std::begin(points))) {
- // Build the tree now (we don't want to wait for the first query)
- m_tree.build();
- }
-
- /// \brief Constructor
- /// @param[in] points Const reference to the point range. This range
- /// is not copied, so it should not be destroyed or modified afterwards.
- /// @param[in] begin_idx, past_the_end_idx Define the subset of the points that
- /// should be actually inserted into the tree. The other points are ignored.
- Kd_tree_search(
- Point_range const& points,
- std::size_t begin_idx, std::size_t past_the_end_idx)
- : m_points(points),
- m_tree(
- boost::counting_iterator<std::ptrdiff_t>(begin_idx),
- boost::counting_iterator<std::ptrdiff_t>(past_the_end_idx),
- typename Tree::Splitter(),
- STraits(std::begin(points))) {
- // Build the tree now (we don't want to wait for the first query)
- m_tree.build();
- }
-
- // Be careful, this function invalidates the tree,
- // which will be recomputed at the next query
- void insert(std::ptrdiff_t point_idx) {
- m_tree.insert(point_idx);
- }
-
- /// \brief Search for the k-nearest neighbors from a query point.
- /// @param[in] p The query point.
- /// @param[in] k Number of nearest points to search.
- /// @param[in] sorted Indicates if the computed sequence of k-nearest neighbors needs to be sorted.
- /// @param[in] eps Approximation factor.
- /// @return A range (whose `value_type` is `std::size_t`) containing the k-nearest neighbors.
- KNS_range k_nearest_neighbors(
- Point const& p,
- unsigned int k,
- bool sorted = true,
- FT eps = FT(0)) const {
- // Initialize the search structure, and search all N points
- // Note that we need to pass the Distance explicitly since it needs to
- // know the property map
- K_neighbor_search search(
- m_tree,
- p,
- k,
- eps,
- true,
- Orthogonal_distance(std::begin(m_points)), sorted);
-
- return search;
- }
-
- /// \brief Search incrementally for the nearest neighbors from a query point.
- /// @param[in] p The query point.
- /// @param[in] eps Approximation factor.
- /// @return A range (whose `value_type` is `std::size_t`) containing the
- /// neighbors sorted by their distance to p.
- /// All the neighbors are not computed by this function, but they will be
- /// computed incrementally when the iterator on the range is incremented.
- INS_range incremental_nearest_neighbors(Point const& p, FT eps = FT(0)) const {
- // Initialize the search structure, and search all N points
- // Note that we need to pass the Distance explicitly since it needs to
- // know the property map
- Incremental_neighbor_search search(
- m_tree,
- p,
- eps,
- true,
- Orthogonal_distance(std::begin(m_points)) );
-
- return search;
- }
-
- /// \brief Search for the k-furthest points from a query point.
- /// @param[in] p The query point.
- /// @param[in] k Number of furthest points to search.
- /// @param[in] sorted Indicates if the computed sequence of k-furthest neighbors needs to be sorted.
- /// @param[in] eps Approximation factor.
- /// @return A range (whose `value_type` is `std::size_t`) containing the k-furthest neighbors.
- KNS_range k_furthest_neighbors(
- Point const& p,
- unsigned int k,
- bool sorted = true,
- FT eps = FT(0)) const {
- // Initialize the search structure, and search all N points
- // Note that we need to pass the Distance explicitly since it needs to
- // know the property map
- K_neighbor_search search(
- m_tree,
- p,
- k,
- eps,
- false,
- Orthogonal_distance(std::begin(m_points)), sorted);
-
- return search;
- }
-
- /// \brief Search incrementally for the furthest neighbors from a query point.
- /// @param[in] p The query point.
- /// @param[in] eps Approximation factor.
- /// @return A range (whose `value_type` is `std::size_t`)
- /// containing the neighbors sorted by their distance to p.
- /// All the neighbors are not computed by this function, but they will be
- /// computed incrementally when the iterator on the range is incremented.
- INS_range incremental_furthest_neighbors(Point const& p, FT eps = FT(0)) const {
- // Initialize the search structure, and search all N points
- // Note that we need to pass the Distance explicitly since it needs to
- // know the property map
- Incremental_neighbor_search search(
- m_tree,
- p,
- eps,
- false,
- Orthogonal_distance(std::begin(m_points)) );
-
- return search;
- }
-
- /// \brief Search for all the neighbors in a ball.
- /// @param[in] p The query point.
- /// @param[in] radius The search radius
- /// @param[out] it The points that lie inside the sphere of center `p` and radius `radius`.
- /// Note: `it` is used this way: `*it++ = each_point`.
- /// @param[in] eps Approximation factor.
- template <typename OutputIterator>
- void all_near_neighbors(Point const& p,
- FT radius,
- OutputIterator it,
- FT eps = FT(0)) const {
- m_tree.search(it, Fuzzy_sphere(p, radius, eps, m_tree.traits()));
- }
-
- int tree_depth() const {
- return m_tree.root()->depth();
- }
-
- private:
- Point_range const& m_points;
- Tree m_tree;
-};
-
-} // namespace spatial_searching
-} // namespace Gudhi
-
-#endif // KD_TREE_SEARCH_H_
diff --git a/include/gudhi/Miniball.COPYRIGHT b/include/gudhi/Miniball.COPYRIGHT
deleted file mode 100644
index dbe4c553..00000000
--- a/include/gudhi/Miniball.COPYRIGHT
+++ /dev/null
@@ -1,4 +0,0 @@
-The miniball software is available under the GNU General Public License (GPLv3 - https://www.gnu.org/copyleft/gpl.html).
-If your intended use is not compliant with this license, please buy a commercial license (EUR 500 - https://people.inf.ethz.ch/gaertner/subdir/software/miniball/license.html).
-You need a license if the software that you develop using Miniball V3.0 is not open source.
-
diff --git a/include/gudhi/Miniball.README b/include/gudhi/Miniball.README
deleted file mode 100644
index 033d8953..00000000
--- a/include/gudhi/Miniball.README
+++ /dev/null
@@ -1,26 +0,0 @@
-https://people.inf.ethz.ch/gaertner/subdir/software/miniball.html
-
-Smallest Enclosing Balls of Points - Fast and Robust in C++.
-(high-quality software for smallest enclosing balls of balls is available in the computational geometry algorithms library CGAL)
-
-
-This is the miniball software (V3.0) for computing smallest enclosing balls of points in arbitrary dimensions. It consists of a C++ header file Miniball.hpp (around 500 lines of code) and two example programs miniball_example.cpp and miniball_example_containers.cpp that demonstrate the usage. The first example stores the coordinates of the input points in a two-dimensional array, the second example uses a list of vectors to show how generic containers can be used.
-
-Credits: Aditya Gupta and Alexandros Konstantinakis-Karmis have significantly contributed to this version of the software.
-
-Changes - https://people.inf.ethz.ch/gaertner/subdir/software/miniball/changes.txt - from previous versions.
-
-The theory - https://people.inf.ethz.ch/gaertner/subdir/texts/own_work/esa99_final.pdf - behind the miniball software (Proc. 7th Annual European Symposium on Algorithms (ESA), Lecture Notes in Computer Science 1643, Springer-Verlag, pp.325-338, 1999).
-
-Main Features:
-
- Very fast in low dimensions. 1 million points in 5-space are processed within 0.05 seconds on any recent machine.
-
- High numerical stability. Almost all input degeneracies (cospherical points, multiple points, points very close together) are routinely handled.
-
- Easily integrates into your code. You can freely choose the coordinate type of your points and the container to store the points. If you still need to adapt the code, the header is small and readable and contains documentation for all major methods.
-
-
-Changes done for the GUDHI version of MiniBall:
- - Add include guard
- - Move Miniball namespace inside a new Gudhi namespace
diff --git a/include/gudhi/Miniball.hpp b/include/gudhi/Miniball.hpp
deleted file mode 100644
index ce6cbb5b..00000000
--- a/include/gudhi/Miniball.hpp
+++ /dev/null
@@ -1,523 +0,0 @@
-// Copright (C) 1999-2013, Bernd Gaertner
-// $Rev: 3581 $
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-// Contact:
-// --------
-// Bernd Gaertner
-// Institute of Theoretical Computer Science
-// ETH Zuerich
-// CAB G31.1
-// CH-8092 Zuerich, Switzerland
-// http://www.inf.ethz.ch/personal/gaertner
-
-#ifndef MINIBALL_HPP_
-#define MINIBALL_HPP_
-
-#include <cassert>
-#include <algorithm>
-#include <list>
-#include <ctime>
-#include <limits>
-
-namespace Gudhi {
-
-namespace Miniball {
-
- // Global Functions
- // ================
- template <typename NT>
- inline NT mb_sqr (NT r) {return r*r;}
-
- // Functors
- // ========
-
- // functor to map a point iterator to the corresponding coordinate iterator;
- // generic version for points whose coordinate containers have begin()
- template < typename Pit_, typename Cit_ >
- struct CoordAccessor {
- typedef Pit_ Pit;
- typedef Cit_ Cit;
- inline Cit operator() (Pit it) const { return (*it).begin(); }
- };
-
- // partial specialization for points whose coordinate containers are arrays
- template < typename Pit_, typename Cit_ >
- struct CoordAccessor<Pit_, Cit_*> {
- typedef Pit_ Pit;
- typedef Cit_* Cit;
- inline Cit operator() (Pit it) const { return *it; }
- };
-
- // Class Declaration
- // =================
-
- template <typename CoordAccessor>
- class Miniball {
- private:
- // types
- // The iterator type to go through the input points
- typedef typename CoordAccessor::Pit Pit;
- // The iterator type to go through the coordinates of a single point.
- typedef typename CoordAccessor::Cit Cit;
- // The coordinate type
- typedef typename std::iterator_traits<Cit>::value_type NT;
- // The iterator to go through the support points
- typedef typename std::list<Pit>::iterator Sit;
-
- // data members...
- const int d; // dimension
- Pit points_begin;
- Pit points_end;
- CoordAccessor coord_accessor;
- double time;
- const NT nt0; // NT(0)
-
- //...for the algorithms
- std::list<Pit> L;
- Sit support_end;
- int fsize; // number of forced points
- int ssize; // number of support points
-
- // ...for the ball updates
- NT* current_c;
- NT current_sqr_r;
- NT** c;
- NT* sqr_r;
-
- // helper arrays
- NT* q0;
- NT* z;
- NT* f;
- NT** v;
- NT** a;
-
- public:
- // The iterator type to go through the support points
- typedef typename std::list<Pit>::const_iterator SupportPointIterator;
-
- // PRE: [begin, end) is a nonempty range
- // POST: computes the smallest enclosing ball of the points in the range
- // [begin, end); the functor a maps a point iterator to an iterator
- // through the d coordinates of the point
- Miniball (int d_, Pit begin, Pit end, CoordAccessor ca = CoordAccessor());
-
- // POST: returns a pointer to the first element of an array that holds
- // the d coordinates of the center of the computed ball
- const NT* center () const;
-
- // POST: returns the squared radius of the computed ball
- NT squared_radius () const;
-
- // POST: returns the number of support points of the computed ball;
- // the support points form a minimal set with the same smallest
- // enclosing ball as the input set; in particular, the support
- // points are on the boundary of the computed ball, and their
- // number is at most d+1
- int nr_support_points () const;
-
- // POST: returns an iterator to the first support point
- SupportPointIterator support_points_begin () const;
-
- // POST: returns a past-the-end iterator for the range of support points
- SupportPointIterator support_points_end () const;
-
- // POST: returns the maximum excess of any input point w.r.t. the computed
- // ball, divided by the squared radius of the computed ball. The
- // excess of a point is the difference between its squared distance
- // from the center and the squared radius; Ideally, the return value
- // is 0. subopt is set to the absolute value of the most negative
- // coefficient in the affine combination of the support points that
- // yields the center. Ideally, this is a convex combination, and there
- // is no negative coefficient in which case subopt is set to 0.
- NT relative_error (NT& subopt) const;
-
- // POST: return true if the relative error is at most tol, and the
- // suboptimality is 0; the default tolerance is 10 times the
- // coordinate type's machine epsilon
- bool is_valid (NT tol = NT(10) * std::numeric_limits<NT>::epsilon()) const;
-
- // POST: returns the time in seconds taken by the constructor call for
- // computing the smallest enclosing ball
- double get_time() const;
-
- // POST: deletes dynamically allocated arrays
- ~Miniball();
-
- private:
- void mtf_mb (Sit n);
- void mtf_move_to_front (Sit j);
- void pivot_mb (Pit n);
- void pivot_move_to_front (Pit j);
- NT excess (Pit pit) const;
- void pop ();
- bool push (Pit pit);
- NT suboptimality () const;
- void create_arrays();
- void delete_arrays();
- };
-
- // Class Definition
- // ================
- template <typename CoordAccessor>
- Miniball<CoordAccessor>::Miniball (int d_, Pit begin, Pit end,
- CoordAccessor ca)
- : d (d_),
- points_begin (begin),
- points_end (end),
- coord_accessor (ca),
- time (clock()),
- nt0 (NT(0)),
- L(),
- support_end (L.begin()),
- fsize(0),
- ssize(0),
- current_c (NULL),
- current_sqr_r (NT(-1)),
- c (NULL),
- sqr_r (NULL),
- q0 (NULL),
- z (NULL),
- f (NULL),
- v (NULL),
- a (NULL)
- {
- assert (points_begin != points_end);
- create_arrays();
-
- // set initial center
- for (int j=0; j<d; ++j) c[0][j] = nt0;
- current_c = c[0];
-
- // compute miniball
- pivot_mb (points_end);
-
- // update time
- time = (clock() - time) / CLOCKS_PER_SEC;
- }
-
- template <typename CoordAccessor>
- Miniball<CoordAccessor>::~Miniball()
- {
- delete_arrays();
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::create_arrays()
- {
- c = new NT*[d+1];
- v = new NT*[d+1];
- a = new NT*[d+1];
- for (int i=0; i<d+1; ++i) {
- c[i] = new NT[d];
- v[i] = new NT[d];
- a[i] = new NT[d];
- }
- sqr_r = new NT[d+1];
- q0 = new NT[d];
- z = new NT[d+1];
- f = new NT[d+1];
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::delete_arrays()
- {
- delete[] f;
- delete[] z;
- delete[] q0;
- delete[] sqr_r;
- for (int i=0; i<d+1; ++i) {
- delete[] a[i];
- delete[] v[i];
- delete[] c[i];
- }
- delete[] a;
- delete[] v;
- delete[] c;
- }
-
- template <typename CoordAccessor>
- const typename Miniball<CoordAccessor>::NT*
- Miniball<CoordAccessor>::center () const
- {
- return current_c;
- }
-
- template <typename CoordAccessor>
- typename Miniball<CoordAccessor>::NT
- Miniball<CoordAccessor>::squared_radius () const
- {
- return current_sqr_r;
- }
-
- template <typename CoordAccessor>
- int Miniball<CoordAccessor>::nr_support_points () const
- {
- assert (ssize < d+2);
- return ssize;
- }
-
- template <typename CoordAccessor>
- typename Miniball<CoordAccessor>::SupportPointIterator
- Miniball<CoordAccessor>::support_points_begin () const
- {
- return L.begin();
- }
-
- template <typename CoordAccessor>
- typename Miniball<CoordAccessor>::SupportPointIterator
- Miniball<CoordAccessor>::support_points_end () const
- {
- return support_end;
- }
-
- template <typename CoordAccessor>
- typename Miniball<CoordAccessor>::NT
- Miniball<CoordAccessor>::relative_error (NT& subopt) const
- {
- NT e, max_e = nt0;
- // compute maximum absolute excess of support points
- for (SupportPointIterator it = support_points_begin();
- it != support_points_end(); ++it) {
- e = excess (*it);
- if (e < nt0) e = -e;
- if (e > max_e) {
- max_e = e;
- }
- }
- // compute maximum excess of any point
- for (Pit i = points_begin; i != points_end; ++i)
- if ((e = excess (i)) > max_e)
- max_e = e;
-
- subopt = suboptimality();
- assert (current_sqr_r > nt0 || max_e == nt0);
- return (current_sqr_r == nt0 ? nt0 : max_e / current_sqr_r);
- }
-
- template <typename CoordAccessor>
- bool Miniball<CoordAccessor>::is_valid (NT tol) const
- {
- NT suboptimality;
- return ( (relative_error (suboptimality) <= tol) && (suboptimality == 0) );
- }
-
- template <typename CoordAccessor>
- double Miniball<CoordAccessor>::get_time() const
- {
- return time;
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::mtf_mb (Sit n)
- {
- // Algorithm 1: mtf_mb (L_{n-1}, B), where L_{n-1} = [L.begin, n)
- // B: the set of forced points, defining the current ball
- // S: the superset of support points computed by the algorithm
- // --------------------------------------------------------------
- // from B. Gaertner, Fast and Robust Smallest Enclosing Balls, ESA 1999,
- // http://www.inf.ethz.ch/personal/gaertner/texts/own_work/esa99_final.pdf
-
- // PRE: B = S
- assert (fsize == ssize);
-
- support_end = L.begin();
- if ((fsize) == d+1) return;
-
- // incremental construction
- for (Sit i = L.begin(); i != n;)
- {
- // INV: (support_end - L.begin() == |S|-|B|)
- assert (std::distance (L.begin(), support_end) == ssize - fsize);
-
- Sit j = i++;
- if (excess(*j) > nt0)
- if (push(*j)) { // B := B + p_i
- mtf_mb (j); // mtf_mb (L_{i-1}, B + p_i)
- pop(); // B := B - p_i
- mtf_move_to_front(j);
- }
- }
- // POST: the range [L.begin(), support_end) stores the set S\B
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::mtf_move_to_front (Sit j)
- {
- if (support_end == j)
- support_end++;
- L.splice (L.begin(), L, j);
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::pivot_mb (Pit n)
- {
- // Algorithm 2: pivot_mb (L_{n-1}), where L_{n-1} = [L.begin, n)
- // --------------------------------------------------------------
- // from B. Gaertner, Fast and Robust Smallest Enclosing Balls, ESA 1999,
- // http://www.inf.ethz.ch/personal/gaertner/texts/own_work/esa99_final.pdf
- NT old_sqr_r;
- const NT* c;
- Pit pivot, k;
- NT e, max_e, sqr_r;
- Cit p;
- do {
- old_sqr_r = current_sqr_r;
- sqr_r = current_sqr_r;
-
- pivot = points_begin;
- max_e = nt0;
- for (k = points_begin; k != n; ++k) {
- p = coord_accessor(k);
- e = -sqr_r;
- c = current_c;
- for (int j=0; j<d; ++j)
- e += mb_sqr<NT>(*p++-*c++);
- if (e > max_e) {
- max_e = e;
- pivot = k;
- }
- }
-
- if (max_e > nt0) {
- // check if the pivot is already contained in the support set
- if (std::find(L.begin(), support_end, pivot) == support_end) {
- assert (fsize == 0);
- if (push (pivot)) {
- mtf_mb(support_end);
- pop();
- pivot_move_to_front(pivot);
- }
- }
- }
- } while (old_sqr_r < current_sqr_r);
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::pivot_move_to_front (Pit j)
- {
- L.push_front(j);
- if (std::distance(L.begin(), support_end) == d+2)
- support_end--;
- }
-
- template <typename CoordAccessor>
- inline typename Miniball<CoordAccessor>::NT
- Miniball<CoordAccessor>::excess (Pit pit) const
- {
- Cit p = coord_accessor(pit);
- NT e = -current_sqr_r;
- NT* c = current_c;
- for (int k=0; k<d; ++k){
- e += mb_sqr<NT>(*p++-*c++);
- }
- return e;
- }
-
- template <typename CoordAccessor>
- void Miniball<CoordAccessor>::pop ()
- {
- --fsize;
- }
-
- template <typename CoordAccessor>
- bool Miniball<CoordAccessor>::push (Pit pit)
- {
- int i, j;
- NT eps = mb_sqr<NT>(std::numeric_limits<NT>::epsilon());
-
- Cit cit = coord_accessor(pit);
- Cit p = cit;
-
- if (fsize==0) {
- for (i=0; i<d; ++i)
- q0[i] = *p++;
- for (i=0; i<d; ++i)
- c[0][i] = q0[i];
- sqr_r[0] = nt0;
- }
- else {
- // set v_fsize to Q_fsize
- for (i=0; i<d; ++i)
- //v[fsize][i] = p[i]-q0[i];
- v[fsize][i] = *p++-q0[i];
-
- // compute the a_{fsize,i}, i< fsize
- for (i=1; i<fsize; ++i) {
- a[fsize][i] = nt0;
- for (j=0; j<d; ++j)
- a[fsize][i] += v[i][j] * v[fsize][j];
- a[fsize][i]*=(2/z[i]);
- }
-
- // update v_fsize to Q_fsize-\bar{Q}_fsize
- for (i=1; i<fsize; ++i) {
- for (j=0; j<d; ++j)
- v[fsize][j] -= a[fsize][i]*v[i][j];
- }
-
- // compute z_fsize
- z[fsize]=nt0;
- for (j=0; j<d; ++j)
- z[fsize] += mb_sqr<NT>(v[fsize][j]);
- z[fsize]*=2;
-
- // reject push if z_fsize too small
- if (z[fsize]<eps*current_sqr_r) {
- return false;
- }
-
- // update c, sqr_r
- p=cit;
- NT e = -sqr_r[fsize-1];
- for (i=0; i<d; ++i)
- e += mb_sqr<NT>(*p++-c[fsize-1][i]);
- f[fsize]=e/z[fsize];
-
- for (i=0; i<d; ++i)
- c[fsize][i] = c[fsize-1][i]+f[fsize]*v[fsize][i];
- sqr_r[fsize] = sqr_r[fsize-1] + e*f[fsize]/2;
- }
- current_c = c[fsize];
- current_sqr_r = sqr_r[fsize];
- ssize = ++fsize;
- return true;
- }
-
- template <typename CoordAccessor>
- typename Miniball<CoordAccessor>::NT
- Miniball<CoordAccessor>::suboptimality () const
- {
- NT* l = new NT[d+1];
- NT min_l = nt0;
- l[0] = NT(1);
- for (int i=ssize-1; i>0; --i) {
- l[i] = f[i];
- for (int k=ssize-1; k>i; --k)
- l[i]-=a[k][i]*l[k];
- if (l[i] < min_l) min_l = l[i];
- l[0] -= l[i];
- }
- if (l[0] < min_l) min_l = l[0];
- delete[] l;
- if (min_l < nt0)
- return -min_l;
- return nt0;
- }
-} // namespace Miniball
-
-} // namespace Gudhi
-
-#endif // MINIBALL_HPP_
diff --git a/include/gudhi/Neighbors_finder.h b/include/gudhi/Neighbors_finder.h
deleted file mode 100644
index 36a63ea0..00000000
--- a/include/gudhi/Neighbors_finder.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Francois Godi
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NEIGHBORS_FINDER_H_
-#define NEIGHBORS_FINDER_H_
-
-// Inclusion order is important for CGAL patch
-#include <CGAL/Kd_tree.h>
-#include <CGAL/Search_traits.h>
-
-#include <gudhi/Persistence_graph.h>
-#include <gudhi/Internal_point.h>
-
-#include <unordered_set>
-#include <vector>
-#include <algorithm> // for std::max
-
-namespace Gudhi {
-
-namespace persistence_diagram {
-
-/** \internal \brief Variant of CGAL::Fuzzy_iso_box to ensure that the box ic closed. It isn't clear how necessary that is.
- */
-struct Square_query {
- typedef CGAL::Dimension_tag<2> D;
- typedef Internal_point Point_d;
- typedef double FT;
- bool contains(Point_d p) const {
- return std::max(std::abs(p.x()-c.x()), std::abs(p.y()-c.y())) <= size;
- }
- bool inner_range_intersects(CGAL::Kd_tree_rectangle<FT, D> const&r) const {
- return
- r.max_coord(0) >= c.x() - size &&
- r.min_coord(0) <= c.x() + size &&
- r.max_coord(1) >= c.y() - size &&
- r.min_coord(1) <= c.y() + size;
- }
- bool outer_range_contains(CGAL::Kd_tree_rectangle<FT, D> const&r) const {
- return
- r.min_coord(0) >= c.x() - size &&
- r.max_coord(0) <= c.x() + size &&
- r.min_coord(1) >= c.y() - size &&
- r.max_coord(1) <= c.y() + size;
- }
- Point_d c;
- FT size;
-};
-
-/** \internal \brief data structure used to find any point (including projections) in V near to a query point from U
- * (which can be a projection).
- *
- * V points have to be added manually using their index and before the first pull. A neighbor pulled is automatically
- * removed.
- *
- * \ingroup bottleneck_distance
- */
-class Neighbors_finder {
- typedef CGAL::Dimension_tag<2> D;
- typedef CGAL::Search_traits<double, Internal_point, const double*, Construct_coord_iterator, D> Traits;
- typedef CGAL::Kd_tree<Traits> Kd_tree;
-
- public:
- /** \internal \brief Constructor taking the near distance definition as parameter. */
- Neighbors_finder(const Persistence_graph& g, double r);
- /** \internal \brief A point added will be possibly pulled. */
- void add(int v_point_index);
- /** \internal \brief Returns and remove a V point near to the U point given as parameter, null_point_index() if
- * there isn't such a point. */
- int pull_near(int u_point_index);
- /** \internal \brief Returns and remove all the V points near to the U point given as parameter. */
- std::vector<int> pull_all_near(int u_point_index);
-
- private:
- const Persistence_graph& g;
- const double r;
- Kd_tree kd_t;
- std::unordered_set<int> projections_f;
-};
-
-/** \internal \brief data structure used to find any point (including projections) in V near to a query point from U
- * (which can be a projection) in a layered graph layer given as parmeter.
- *
- * V points have to be added manually using their index and before the first pull. A neighbor pulled is automatically
- * removed.
- *
- * \ingroup bottleneck_distance
- */
-class Layered_neighbors_finder {
- public:
- /** \internal \brief Constructor taking the near distance definition as parameter. */
- Layered_neighbors_finder(const Persistence_graph& g, double r);
- /** \internal \brief A point added will be possibly pulled. */
- void add(int v_point_index, int vlayer);
- /** \internal \brief Returns and remove a V point near to the U point given as parameter, null_point_index() if
- * there isn't such a point. */
- int pull_near(int u_point_index, int vlayer);
- /** \internal \brief Returns the number of layers. */
- int vlayers_number() const;
-
- private:
- const Persistence_graph& g;
- const double r;
- std::vector<std::unique_ptr<Neighbors_finder>> neighbors_finder;
-};
-
-inline Neighbors_finder::Neighbors_finder(const Persistence_graph& g, double r) :
- g(g), r(r), kd_t(), projections_f() { }
-
-inline void Neighbors_finder::add(int v_point_index) {
- if (g.on_the_v_diagonal(v_point_index))
- projections_f.emplace(v_point_index);
- else
- kd_t.insert(g.get_v_point(v_point_index));
-}
-
-inline int Neighbors_finder::pull_near(int u_point_index) {
- int tmp;
- int c = g.corresponding_point_in_v(u_point_index);
- if (g.on_the_u_diagonal(u_point_index) && !projections_f.empty()) {
- // Any pair of projection is at distance 0
- tmp = *projections_f.cbegin();
- projections_f.erase(tmp);
- } else if (projections_f.count(c) && (g.distance(u_point_index, c) <= r)) {
- // Is the query point near to its projection ?
- tmp = c;
- projections_f.erase(tmp);
- } else {
- // Is the query point near to a V point in the plane ?
- Internal_point u_point = g.get_u_point(u_point_index);
- auto neighbor = kd_t.search_any_point(Square_query{u_point, r});
- if (!neighbor)
- return null_point_index();
- tmp = neighbor->point_index;
- auto point = g.get_v_point(tmp);
- int idx = point.point_index;
- kd_t.remove(point, [idx](Internal_point const&p){return p.point_index == idx;});
- }
- return tmp;
-}
-
-inline std::vector<int> Neighbors_finder::pull_all_near(int u_point_index) {
- std::vector<int> all_pull;
- int last_pull = pull_near(u_point_index);
- while (last_pull != null_point_index()) {
- all_pull.emplace_back(last_pull);
- last_pull = pull_near(u_point_index);
- }
- return all_pull;
-}
-
-inline Layered_neighbors_finder::Layered_neighbors_finder(const Persistence_graph& g, double r) :
- g(g), r(r), neighbors_finder() { }
-
-inline void Layered_neighbors_finder::add(int v_point_index, int vlayer) {
- for (int l = neighbors_finder.size(); l <= vlayer; l++)
- neighbors_finder.emplace_back(std::unique_ptr<Neighbors_finder>(new Neighbors_finder(g, r)));
- neighbors_finder.at(vlayer)->add(v_point_index);
-}
-
-inline int Layered_neighbors_finder::pull_near(int u_point_index, int vlayer) {
- if (static_cast<int> (neighbors_finder.size()) <= vlayer)
- return null_point_index();
- return neighbors_finder.at(vlayer)->pull_near(u_point_index);
-}
-
-inline int Layered_neighbors_finder::vlayers_number() const {
- return static_cast<int> (neighbors_finder.size());
-}
-
-} // namespace persistence_diagram
-
-} // namespace Gudhi
-
-#endif // NEIGHBORS_FINDER_H_
diff --git a/include/gudhi/Null_output_iterator.h b/include/gudhi/Null_output_iterator.h
deleted file mode 100644
index c700af5f..00000000
--- a/include/gudhi/Null_output_iterator.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Marc Glisse
- *
- * Copyright (C) 2017 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NULL_OUTPUT_ITERATOR_H_
-#define NULL_OUTPUT_ITERATOR_H_
-
-#include <iterator>
-
-namespace Gudhi {
-
-/** An output iterator that ignores whatever it is given. */
-struct Null_output_iterator {
- typedef std::output_iterator_tag iterator_category;
- typedef void value_type;
- typedef void difference_type;
- typedef void pointer;
- typedef void reference;
-
- Null_output_iterator& operator++() {return *this;}
- Null_output_iterator operator++(int) {return *this;}
- struct proxy {
- template<class T>
- proxy& operator=(T&&){return *this;}
- };
- proxy operator*()const{return {};}
-};
-} // namespace Gudhi
-
-#endif // NULL_OUTPUT_ITERATOR_H_
diff --git a/include/gudhi/Off_reader.h b/include/gudhi/Off_reader.h
deleted file mode 100644
index 05a1e145..00000000
--- a/include/gudhi/Off_reader.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#ifndef OFF_READER_H_
-#define OFF_READER_H_
-
-
-#include <sstream>
-#include <iostream>
-#include <iterator>
-#include <string>
-#include <vector>
-#include <fstream>
-
-namespace Gudhi {
-
-/** \brief OFF file reader top class visitor.
- *
- * OFF file must be conform to format described here :
- * http://www.geomview.org/docs/html/OFF.html
- */
-class Off_reader {
- public:
- Off_reader(std::ifstream& stream) : stream_(stream) { }
-
- ~Off_reader() {
- stream_.close();
- }
-
- /** \brief
- * Read an OFF file and calls the following methods :
- *
- * <CODE>void init(int dim,int num_vertices,int num_faces,int num_edges); // from file header - num_edges may not be set
- *
- * void point(const std::vector<double>& point); // for each point read
- *
- * void maximal_face(const std::list<int>& face); // for each face read
- *
- * void done(); // upon file read is finished</CODE>
- *
- * of the visitor when reading a point or a maximal face. Edges are not taken into account.
- */
- template<typename OffVisitor>
- bool read(OffVisitor& off_visitor) {
- bool success_read_off_preambule = read_off_preambule(off_visitor);
- if (!success_read_off_preambule) {
- std::cerr << "could not read off preambule\n";
- return false;
- }
-
- bool success_read_off_points = read_off_points(off_visitor);
- if (!success_read_off_points) {
- std::cerr << "could not read off points\n";
- return false;
- }
-
- bool success_read_off_faces = read_off_faces(off_visitor);
- if (!success_read_off_faces) {
- std::cerr << "could not read off faces\n";
- return false;
- }
-
- off_visitor.done();
- return success_read_off_preambule && success_read_off_points && success_read_off_faces;
- }
-
- private:
- std::ifstream& stream_;
-
- struct Off_info {
- int dim;
- int num_vertices;
- int num_edges;
- int num_faces;
- };
-
- Off_info off_info_;
-
- template<typename OffVisitor>
- bool read_off_preambule(OffVisitor& off_visitor) {
- std::string line;
- if (!goto_next_uncomment_line(line)) return false;
-
- bool is_off_file = (line.find("OFF") != std::string::npos);
- bool is_noff_file = (line.find("nOFF") != std::string::npos);
-
-
-
- if (!is_off_file && !is_noff_file) {
- std::cerr << line << std::endl;
- std::cerr << "missing off header\n";
- return false;
- }
-
- if (is_noff_file) {
- // Should be on a separate line, but we accept it on the same line as the number of vertices
- stream_ >> off_info_.dim;
- } else {
- off_info_.dim = 3;
- }
-
- if (!goto_next_uncomment_line(line)) return false;
- std::istringstream iss(line);
- if (!(iss >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) {
- std::cerr << "incorrect number of vertices/faces/edges\n";
- return false;
- }
- off_visitor.init(off_info_.dim, off_info_.num_vertices, off_info_.num_faces, off_info_.num_edges);
-
- return true;
- }
-
- bool goto_next_uncomment_line(std::string& uncomment_line) {
- do {
- // skip whitespace, including empty lines
- if (!std::ifstream::sentry(stream_)) return false;
- std::getline(stream_, uncomment_line);
- } while (uncomment_line[0] == '#');
- return static_cast<bool>(stream_);
- }
-
- template<typename OffVisitor>
- bool read_off_points(OffVisitor& visitor) {
- int num_vertices_to_read = off_info_.num_vertices;
- while (num_vertices_to_read--) {
- std::string line;
- if (!goto_next_uncomment_line(line)) return false;
- std::vector<double> point;
- std::istringstream iss(line);
- point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>());
- // if(point.size() != off_info_.dim) return false;
- visitor.point(point);
- }
- return true;
- }
-
- template<typename OffVisitor>
- bool read_off_faces(OffVisitor& visitor) {
- std::string line;
- while (goto_next_uncomment_line(line)) {
- std::istringstream iss(line);
- int num_face_vertices;
- iss >> num_face_vertices;
- std::vector<int> face;
- face.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>());
- // if (face.size() != (off_info_.dim + 1)) return false;
- visitor.maximal_face(face);
- }
- return true;
- }
-};
-
-template<typename OFFVisitor>
-void read_off(const std::string& name_file_off, OFFVisitor& vis) {
- std::ifstream stream(name_file_off);
- if (!stream.is_open()) {
- std::cerr << "could not open file \n";
- } else {
- Off_reader off_reader(stream);
- off_reader.read(vis);
- }
-}
-
-} // namespace Gudhi
-
-#endif // OFF_READER_H_
diff --git a/include/gudhi/PSSK.h b/include/gudhi/PSSK.h
deleted file mode 100644
index e1174455..00000000
--- a/include/gudhi/PSSK.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PSSK_H_
-#define PSSK_H_
-
-// gudhi include
-#include <gudhi/Persistence_heat_maps.h>
-
-#include <limits>
-#include <utility>
-#include <vector>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-/**
-* This is a version of a representation presented in https://arxiv.org/abs/1412.6821
-* In that paper the authors are using the representation just to compute kernel. Over here, we extend the usability by
-*far.
-* Note that the version presented here is not exact, since we are discretizing the kernel.
-* The only difference with respect to the original class is the method of creation. We have full (square) image, and for
-*every point (p,q), we add a kernel at (p,q) and the negative kernel
-* at (q,p)
-**/
-
-class PSSK : public Persistence_heat_maps<constant_scaling_function> {
- public:
- PSSK() : Persistence_heat_maps() {}
-
- PSSK(const std::vector<std::pair<double, double> >& interval,
- std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1), size_t number_of_pixels = 1000,
- double min_ = -1, double max_ = -1)
- : Persistence_heat_maps() {
- this->construct(interval, filter, number_of_pixels, min_, max_);
- }
-
- PSSK(const char* filename, std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1),
- size_t number_of_pixels = 1000, double min_ = -1, double max_ = -1,
- unsigned dimension = std::numeric_limits<unsigned>::max())
- : Persistence_heat_maps() {
- std::vector<std::pair<double, double> > intervals_;
- if (dimension == std::numeric_limits<unsigned>::max()) {
- intervals_ = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- intervals_ = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->construct(intervals_, filter, number_of_pixels, min_, max_);
- }
-
- protected:
- void construct(const std::vector<std::pair<double, double> >& intervals_,
- std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1),
- size_t number_of_pixels = 1000, double min_ = -1, double max_ = -1);
-};
-
-// if min_ == max_, then the program is requested to set up the values itself based on persistence intervals
-void PSSK::construct(const std::vector<std::pair<double, double> >& intervals_,
- std::vector<std::vector<double> > filter, size_t number_of_pixels, double min_, double max_) {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Entering construct procedure \n";
- getchar();
- }
-
- if (min_ == max_) {
- // in this case, we want the program to set up the min_ and max_ values by itself.
- min_ = std::numeric_limits<int>::max();
- max_ = -std::numeric_limits<int>::max();
-
- for (size_t i = 0; i != intervals_.size(); ++i) {
- if (intervals_[i].first < min_) min_ = intervals_[i].first;
- if (intervals_[i].second > max_) max_ = intervals_[i].second;
- }
- // now we have the structure filled in, and moreover we know min_ and max_ values of the interval, so we know the
- // range.
-
- // add some more space:
- min_ -= fabs(max_ - min_) / 100;
- max_ += fabs(max_ - min_) / 100;
- }
-
- if (dbg) {
- std::cerr << "min_ : " << min_ << std::endl;
- std::cerr << "max_ : " << max_ << std::endl;
- std::cerr << "number_of_pixels : " << number_of_pixels << std::endl;
- getchar();
- }
-
- this->min_ = min_;
- this->max_ = max_;
-
- // initialization of the structure heat_map
- std::vector<std::vector<double> > heat_map_;
- for (size_t i = 0; i != number_of_pixels; ++i) {
- std::vector<double> v(number_of_pixels, 0);
- heat_map_.push_back(v);
- }
- this->heat_map = heat_map_;
-
- if (dbg) std::cerr << "Done creating of the heat map, now we will fill in the structure \n";
-
- for (size_t pt_nr = 0; pt_nr != intervals_.size(); ++pt_nr) {
- // compute the value of intervals_[pt_nr] in the grid:
- int x_grid =
- static_cast<int>((intervals_[pt_nr].first - this->min_) / (this->max_ - this->min_) * number_of_pixels);
- int y_grid =
- static_cast<int>((intervals_[pt_nr].second - this->min_) / (this->max_ - this->min_) * number_of_pixels);
-
- if (dbg) {
- std::cerr << "point : " << intervals_[pt_nr].first << " , " << intervals_[pt_nr].second << std::endl;
- std::cerr << "x_grid : " << x_grid << std::endl;
- std::cerr << "y_grid : " << y_grid << std::endl;
- }
-
- // x_grid and y_grid gives a center of the kernel. We want to have its lower left corner. To get this, we need to
- // shift x_grid and y_grid by a grid diameter.
- x_grid -= filter.size() / 2;
- y_grid -= filter.size() / 2;
- // note that the numbers x_grid and y_grid may be negative.
-
- if (dbg) {
- std::cerr << "After shift : \n";
- std::cerr << "x_grid : " << x_grid << std::endl;
- std::cerr << "y_grid : " << y_grid << std::endl;
- std::cerr << "filter.size() : " << filter.size() << std::endl;
- getchar();
- }
-
- for (size_t i = 0; i != filter.size(); ++i) {
- for (size_t j = 0; j != filter.size(); ++j) {
- // if the point (x_grid+i,y_grid+j) is the correct point in the grid.
- if (((x_grid + i) >= 0) && (x_grid + i < this->heat_map.size()) && ((y_grid + j) >= 0) &&
- (y_grid + j < this->heat_map.size())) {
- if (dbg) {
- std::cerr << y_grid + j << " " << x_grid + i << std::endl;
- }
- this->heat_map[y_grid + j][x_grid + i] += filter[i][j];
- this->heat_map[x_grid + i][y_grid + j] += -filter[i][j];
- }
- }
- }
- }
-} // construct
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PSSK_H_
diff --git a/include/gudhi/Persistence_graph.h b/include/gudhi/Persistence_graph.h
deleted file mode 100644
index cb163623..00000000
--- a/include/gudhi/Persistence_graph.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author: Francois Godi
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_GRAPH_H_
-#define PERSISTENCE_GRAPH_H_
-
-#include <gudhi/Internal_point.h>
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_sort.h>
-#endif
-
-#include <vector>
-#include <algorithm>
-#include <limits> // for numeric_limits
-
-namespace Gudhi {
-
-namespace persistence_diagram {
-
-/** \internal \brief Structure representing an euclidean bipartite graph containing
- * the points from the two persistence diagrams (including the projections).
- *
- * \ingroup bottleneck_distance
- */
-class Persistence_graph {
- public:
- /** \internal \brief Constructor taking 2 PersistenceDiagrams (concept) as parameters. */
- template<typename Persistence_diagram1, typename Persistence_diagram2>
- Persistence_graph(const Persistence_diagram1& diag1, const Persistence_diagram2& diag2, double e);
- /** \internal \brief Is the given point from U the projection of a point in V ? */
- bool on_the_u_diagonal(int u_point_index) const;
- /** \internal \brief Is the given point from V the projection of a point in U ? */
- bool on_the_v_diagonal(int v_point_index) const;
- /** \internal \brief Given a point from V, returns the corresponding (projection or projector) point in U. */
- int corresponding_point_in_u(int v_point_index) const;
- /** \internal \brief Given a point from U, returns the corresponding (projection or projector) point in V. */
- int corresponding_point_in_v(int u_point_index) const;
- /** \internal \brief Given a point from U and a point from V, returns the distance between those points. */
- double distance(int u_point_index, int v_point_index) const;
- /** \internal \brief Returns size = |U| = |V|. */
- int size() const;
- /** \internal \brief Is there as many infinite points (alive components) in both diagrams ? */
- double bottleneck_alive() const;
- /** \internal \brief Returns the O(n^2) sorted distances between the points. */
- std::vector<double> sorted_distances() const;
- /** \internal \brief Returns an upper bound for the diameter of the convex hull of all non infinite points */
- double diameter_bound() const;
- /** \internal \brief Returns the corresponding internal point */
- Internal_point get_u_point(int u_point_index) const;
- /** \internal \brief Returns the corresponding internal point */
- Internal_point get_v_point(int v_point_index) const;
-
- private:
- std::vector<Internal_point> u;
- std::vector<Internal_point> v;
- double b_alive;
-};
-
-template<typename Persistence_diagram1, typename Persistence_diagram2>
-Persistence_graph::Persistence_graph(const Persistence_diagram1 &diag1,
- const Persistence_diagram2 &diag2, double e)
- : u(), v(), b_alive(0.) {
- std::vector<double> u_alive;
- std::vector<double> v_alive;
- for (auto it = std::begin(diag1); it != std::end(diag1); ++it) {
- if (std::get<1>(*it) == std::numeric_limits<double>::infinity())
- u_alive.push_back(std::get<0>(*it));
- else if (std::get<1>(*it) - std::get<0>(*it) > e)
- u.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), u.size()));
- }
- for (auto it = std::begin(diag2); it != std::end(diag2); ++it) {
- if (std::get<1>(*it) == std::numeric_limits<double>::infinity())
- v_alive.push_back(std::get<0>(*it));
- else if (std::get<1>(*it) - std::get<0>(*it) > e)
- v.push_back(Internal_point(std::get<0>(*it), std::get<1>(*it), v.size()));
- }
- if (u.size() < v.size())
- swap(u, v);
- std::sort(u_alive.begin(), u_alive.end());
- std::sort(v_alive.begin(), v_alive.end());
- if (u_alive.size() != v_alive.size()) {
- b_alive = std::numeric_limits<double>::infinity();
- } else {
- for (auto it_u = u_alive.cbegin(), it_v = v_alive.cbegin(); it_u != u_alive.cend(); ++it_u, ++it_v)
- b_alive = (std::max)(b_alive, std::fabs(*it_u - *it_v));
- }
-}
-
-inline bool Persistence_graph::on_the_u_diagonal(int u_point_index) const {
- return u_point_index >= static_cast<int> (u.size());
-}
-
-inline bool Persistence_graph::on_the_v_diagonal(int v_point_index) const {
- return v_point_index >= static_cast<int> (v.size());
-}
-
-inline int Persistence_graph::corresponding_point_in_u(int v_point_index) const {
- return on_the_v_diagonal(v_point_index) ?
- v_point_index - static_cast<int> (v.size()) : v_point_index + static_cast<int> (u.size());
-}
-
-inline int Persistence_graph::corresponding_point_in_v(int u_point_index) const {
- return on_the_u_diagonal(u_point_index) ?
- u_point_index - static_cast<int> (u.size()) : u_point_index + static_cast<int> (v.size());
-}
-
-inline double Persistence_graph::distance(int u_point_index, int v_point_index) const {
- if (on_the_u_diagonal(u_point_index) && on_the_v_diagonal(v_point_index))
- return 0.;
- Internal_point p_u = get_u_point(u_point_index);
- Internal_point p_v = get_v_point(v_point_index);
- return (std::max)(std::fabs(p_u.x() - p_v.x()), std::fabs(p_u.y() - p_v.y()));
-}
-
-inline int Persistence_graph::size() const {
- return static_cast<int> (u.size() + v.size());
-}
-
-inline double Persistence_graph::bottleneck_alive() const {
- return b_alive;
-}
-
-inline std::vector<double> Persistence_graph::sorted_distances() const {
- std::vector<double> distances;
- distances.push_back(0.); // for empty diagrams
- for (int u_point_index = 0; u_point_index < size(); ++u_point_index) {
- distances.push_back(distance(u_point_index, corresponding_point_in_v(u_point_index)));
- for (int v_point_index = 0; v_point_index < size(); ++v_point_index)
- distances.push_back(distance(u_point_index, v_point_index));
- }
-#ifdef GUDHI_USE_TBB
- tbb::parallel_sort(distances.begin(), distances.end());
-#else
- std::sort(distances.begin(), distances.end());
-#endif
- return distances;
-}
-
-inline Internal_point Persistence_graph::get_u_point(int u_point_index) const {
- if (!on_the_u_diagonal(u_point_index))
- return u.at(u_point_index);
- Internal_point projector = v.at(corresponding_point_in_v(u_point_index));
- double m = (projector.x() + projector.y()) / 2.;
- return Internal_point(m, m, u_point_index);
-}
-
-inline Internal_point Persistence_graph::get_v_point(int v_point_index) const {
- if (!on_the_v_diagonal(v_point_index))
- return v.at(v_point_index);
- Internal_point projector = u.at(corresponding_point_in_u(v_point_index));
- double m = (projector.x() + projector.y()) / 2.;
- return Internal_point(m, m, v_point_index);
-}
-
-inline double Persistence_graph::diameter_bound() const {
- double max = 0.;
- for (auto it = u.cbegin(); it != u.cend(); it++)
- max = (std::max)(max, it->y());
- for (auto it = v.cbegin(); it != v.cend(); it++)
- max = (std::max)(max, it->y());
- return max;
-}
-
-} // namespace persistence_diagram
-
-} // namespace Gudhi
-
-#endif // PERSISTENCE_GRAPH_H_
diff --git a/include/gudhi/Persistence_heat_maps.h b/include/gudhi/Persistence_heat_maps.h
deleted file mode 100644
index 35e51e63..00000000
--- a/include/gudhi/Persistence_heat_maps.h
+++ /dev/null
@@ -1,919 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_HEAT_MAPS_H_
-#define PERSISTENCE_HEAT_MAPS_H_
-
-// gudhi include
-#include <gudhi/read_persistence_from_file.h>
-#include <gudhi/common_persistence_representations.h>
-
-// standard include
-#include <vector>
-#include <sstream>
-#include <iostream>
-#include <cmath>
-#include <limits>
-#include <algorithm>
-#include <utility>
-#include <string>
-#include <functional>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-/**
- * This is a simple procedure to create n by n (or 2*pixel_radius times 2*pixel_radius cubical approximation of a
- *Gaussian kernel.
-**/
-std::vector<std::vector<double> > create_Gaussian_filter(size_t pixel_radius, double sigma) {
- bool dbg = false;
- // we are computing the kernel mask to 2 standard deviations away from the center. We discretize it in a grid of a
- // size 2*pixel_radius times 2*pixel_radius.
-
- double r = 0;
- double sigma_sqr = sigma * sigma;
-
- // sum is for normalization
- double sum = 0;
-
- // initialization of a kernel:
- std::vector<std::vector<double> > kernel(2 * pixel_radius + 1);
- for (size_t i = 0; i != kernel.size(); ++i) {
- std::vector<double> v(2 * pixel_radius + 1, 0);
- kernel[i] = v;
- }
-
- if (dbg) {
- std::cerr << "Kernel initialize \n";
- std::cerr << "pixel_radius : " << pixel_radius << std::endl;
- std::cerr << "kernel.size() : " << kernel.size() << std::endl;
- getchar();
- }
-
- for (int x = -pixel_radius; x <= static_cast<int>(pixel_radius); x++) {
- for (int y = -pixel_radius; y <= static_cast<int>(pixel_radius); y++) {
- double real_x = 2 * sigma * x / pixel_radius;
- double real_y = 2 * sigma * y / pixel_radius;
- r = sqrt(real_x * real_x + real_y * real_y);
- kernel[x + pixel_radius][y + pixel_radius] = (exp(-(r * r) / sigma_sqr)) / (3.141592 * sigma_sqr);
- sum += kernel[x + pixel_radius][y + pixel_radius];
- }
- }
-
- // normalize the kernel
- for (size_t i = 0; i != kernel.size(); ++i) {
- for (size_t j = 0; j != kernel[i].size(); ++j) {
- kernel[i][j] /= sum;
- }
- }
-
- if (dbg) {
- std::cerr << "Here is the kernel : \n";
- for (size_t i = 0; i != kernel.size(); ++i) {
- for (size_t j = 0; j != kernel[i].size(); ++j) {
- std::cerr << kernel[i][j] << " ";
- }
- std::cerr << std::endl;
- }
- }
- return kernel;
-}
-
-/*
-* There are various options to scale the points depending on their location. One can for instance:
-* (1) do nothing (scale all of them with the weight 1), as in the function constant_function
-* (2) Scale them by the distance to the diagonal. This is implemented in function
-* (3) Scale them with the square of their distance to diagonal. This is implemented in function
-* (4) Scale them with
-*/
-
-/**
- * This is one of a scaling functions used to weight points depending on their persistence and/or location in the
- *diagram.
- * This particular functionality is a function which always assign value 1 to a point in the diagram.
-**/
-class constant_scaling_function {
- public:
- double operator()(const std::pair<double, double>& point_in_diagram) { return 1; }
-};
-
-/**
- * This is one of a scaling functions used to weight points depending on their persistence and/or location in the
- *diagram.
- * The scaling given by this function to a point (b,d) is Euclidean distance of (b,d) from diagonal.
-**/
-class distance_from_diagonal_scaling {
- public:
- double operator()(const std::pair<double, double>& point_in_diagram) {
- // (point_in_diagram.first+point_in_diagram.second)/2.0
- return sqrt(pow((point_in_diagram.first - (point_in_diagram.first + point_in_diagram.second) / 2.0), 2) +
- pow((point_in_diagram.second - (point_in_diagram.first + point_in_diagram.second) / 2.0), 2));
- }
-};
-
-/**
- * This is one of a scaling functions used to weight points depending on their persistence and/or location in the
- *diagram.
- * The scaling given by this function to a point (b,d) is a square of Euclidean distance of (b,d) from diagonal.
-**/
-class squared_distance_from_diagonal_scaling {
- public:
- double operator()(const std::pair<double, double>& point_in_diagram) {
- return pow((point_in_diagram.first - (point_in_diagram.first + point_in_diagram.second) / 2.0), 2) +
- pow((point_in_diagram.second - (point_in_diagram.first + point_in_diagram.second) / 2.0), 2);
- }
-};
-
-/**
- * This is one of a scaling functions used to weight points depending on their persistence and/or location in the
- *diagram.
- * The scaling given by this function to a point (b,d) is an arctan of a persistence of a point (i.e. arctan( b-d ).
-**/
-class arc_tan_of_persistence_of_point {
- public:
- double operator()(const std::pair<double, double>& point_in_diagram) {
- return atan(point_in_diagram.second - point_in_diagram.first);
- }
-};
-
-/**
- * This is one of a scaling functions used to weight points depending on their persistence and/or location in the
- *diagram.
- * This scaling function do not only depend on a point (p,d) in the diagram, but it depends on the whole diagram.
- * The longest persistence pair get a scaling 1. Any other pair get a scaling belong to [0,1], which is proportional
- * to the persistence of that pair.
-**/
-class weight_by_setting_maximal_interval_to_have_length_one {
- public:
- weight_by_setting_maximal_interval_to_have_length_one(double len) : letngth_of_maximal_interval(len) {}
- double operator()(const std::pair<double, double>& point_in_diagram) {
- return (point_in_diagram.second - point_in_diagram.first) / this->letngth_of_maximal_interval;
- }
-
- private:
- double letngth_of_maximal_interval;
-};
-
-/**
- * \class Persistence_heat_maps Persistence_heat_maps.h gudhi/Persistence_heat_maps.h
- * \brief A class implementing persistence heat maps.
- *
- * \ingroup Persistence_representations
-**/
-
-// This class implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
-// Real_valued_topological_data, Topological_data_with_averages, Topological_data_with_scalar_product
-template <typename Scalling_of_kernels = constant_scaling_function>
-class Persistence_heat_maps {
- public:
- /**
- * The default constructor. A scaling function from the diagonal is set up to a constant function. The image is not
- *erased below the diagonal. The Gaussian have diameter 5.
- **/
- Persistence_heat_maps() {
- Scalling_of_kernels f;
- this->f = f;
- this->erase_below_diagonal = false;
- this->min_ = this->max_ = 0;
- this->set_up_parameters_for_basic_classes();
- }
-
- /**
- * Construction that takes at the input the following parameters:
- * (1) A vector of pairs of doubles (representing persistence intervals). All other parameters are optional. They are:
- * (2) a Gaussian filter generated by create_Gaussian_filter filter (the default value of this variable is a Gaussian
- *filter of a radius 5),
- * (3) a boolean value which determines if the area of image below diagonal should, or should not be erased (it will
- *be erased by default).
- * (4) a number of pixels in each direction (set to 1000 by default).
- * (5) a min x and y value of points that are to be taken into account. By default it is set to
- *std::numeric_limits<double>::max(), in which case the program compute the values based on the data,
- * (6) a max x and y value of points that are to be taken into account. By default it is set to
- *std::numeric_limits<double>::max(), in which case the program compute the values based on the data.
- **/
- Persistence_heat_maps(const std::vector<std::pair<double, double> >& interval,
- std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1),
- bool erase_below_diagonal = false, size_t number_of_pixels = 1000,
- double min_ = std::numeric_limits<double>::max(),
- double max_ = std::numeric_limits<double>::max());
-
- /**
- * Construction that takes at the input a name of a file with persistence intervals, a filter (radius 5 by
- *default), a scaling function (constant by default), a boolean value which determines if the area of image below
- *diagonal should, or should not be erased (should by default). The next parameter is the number of pixels in each
- *direction (set to 1000 by default) and min and max values of images (both set to std::numeric_limits<double>::max()
- *by default. If this is the case, the program will pick the right values based on the data).
- **/
- /**
- * Construction that takes at the input the following parameters:
- * (1) A name of a file with persistence intervals. The file should be readable by the function
- *read_persistence_intervals_in_one_dimension_from_file. All other parameters are optional. They are:
- * (2) a Gaussian filter generated by create_Gaussian_filter filter (the default value of this variable is a Gaussian
- *filter of a radius 5),
- * (3) a boolean value which determines if the area of image below diagonal should, or should not be erased (it will
- *be erased by default).
- * (4) a number of pixels in each direction (set to 1000 by default).
- * (5) a min x and y value of points that are to be taken into account. By default it is set to
- *std::numeric_limits<double>::max(), in which case the program compute the values based on the data,
- * (6) a max x and y value of points that are to be taken into account. By default it is set to
- *std::numeric_limits<double>::max(), in which case the program compute the values based on the data.
- **/
- Persistence_heat_maps(const char* filename, std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1),
- bool erase_below_diagonal = false, size_t number_of_pixels = 1000,
- double min_ = std::numeric_limits<double>::max(),
- double max_ = std::numeric_limits<double>::max(),
- unsigned dimension = std::numeric_limits<unsigned>::max());
-
- /**
- * Compute a mean value of a collection of heat maps and store it in the current object. Note that all the persistence
- *maps send in a vector to this procedure need to have the same parameters.
- * If this is not the case, the program will throw an exception.
- **/
- void compute_mean(const std::vector<Persistence_heat_maps*>& maps);
-
- /**
- * Compute a median value of a collection of heat maps and store it in the current object. Note that all the
- *persistence maps send in a vector to this procedure need to have the same parameters.
- * If this is not the case, the program will throw an exception.
- **/
- void compute_median(const std::vector<Persistence_heat_maps*>& maps);
-
- /**
- * Compute a percentage of active (i.e) values above the cutoff of a collection of heat maps.
- **/
- void compute_percentage_of_active(const std::vector<Persistence_heat_maps*>& maps, size_t cutoff = 1);
-
- // put to file subroutine
- /**
- * The function outputs the persistence image to a text file. The format as follow:
- * In the first line, the values min and max of the image are stored
- * In the next lines, we have the persistence images in a form of a bitmap image.
- **/
- void print_to_file(const char* filename) const;
-
- /**
- * A function that load a heat map from file to the current object (and erase whatever was stored in the current
- *object before).
- **/
- void load_from_file(const char* filename);
-
- /**
- * The procedure checks if min_, max_ and this->heat_maps sizes are the same.
- **/
- inline bool check_if_the_same(const Persistence_heat_maps& second) const {
- bool dbg = false;
- if (this->heat_map.size() != second.heat_map.size()) {
- if (dbg)
- std::cerr << "this->heat_map.size() : " << this->heat_map.size()
- << " \n second.heat_map.size() : " << second.heat_map.size() << std::endl;
- return false;
- }
- if (this->min_ != second.min_) {
- if (dbg) std::cerr << "this->min_ : " << this->min_ << ", second.min_ : " << second.min_ << std::endl;
- return false;
- }
- if (this->max_ != second.max_) {
- if (dbg) std::cerr << "this->max_ : " << this->max_ << ", second.max_ : " << second.max_ << std::endl;
- return false;
- }
- // in the other case we may assume that the persistence images are defined on the same domain.
- return true;
- }
-
- /**
- * Return minimal range value of persistent image.
- **/
- inline double get_min() const { return this->min_; }
-
- /**
- * Return maximal range value of persistent image.
- **/
- inline double get_max() const { return this->max_; }
-
- /**
- * Operator == to check if to persistence heat maps are the same.
- **/
- bool operator==(const Persistence_heat_maps& rhs) const {
- bool dbg = false;
- if (!this->check_if_the_same(rhs)) {
- if (dbg) std::cerr << "The domains are not the same \n";
- return false; // in this case, the domains are not the same, so the maps cannot be the same.
- }
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- if (!almost_equal(this->heat_map[i][j], rhs.heat_map[i][j])) {
- if (dbg) {
- std::cerr << "this->heat_map[" << i << "][" << j << "] = " << this->heat_map[i][j] << std::endl;
- std::cerr << "rhs.heat_map[" << i << "][" << j << "] = " << rhs.heat_map[i][j] << std::endl;
- }
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Operator != to check if to persistence heat maps are different.
- **/
- bool operator!=(const Persistence_heat_maps& rhs) const { return !((*this) == rhs); }
-
- /**
- * A function to generate a gnuplot script to visualize the persistent image.
- **/
- void plot(const char* filename) const;
-
- template <typename Operation_type>
- friend Persistence_heat_maps operation_on_pair_of_heat_maps(const Persistence_heat_maps& first,
- const Persistence_heat_maps& second,
- Operation_type operation) {
- // first check if the heat maps are compatible
- if (!first.check_if_the_same(second)) {
- std::cerr << "Sizes of the heat maps are not compatible. The program will now terminate \n";
- throw "Sizes of the heat maps are not compatible. The program will now terminate \n";
- }
- Persistence_heat_maps result;
- result.min_ = first.min_;
- result.max_ = first.max_;
- result.heat_map.reserve(first.heat_map.size());
- for (size_t i = 0; i != first.heat_map.size(); ++i) {
- std::vector<double> v;
- v.reserve(first.heat_map[i].size());
- for (size_t j = 0; j != first.heat_map[i].size(); ++j) {
- v.push_back(operation(first.heat_map[i][j], second.heat_map[i][j]));
- }
- result.heat_map.push_back(v);
- }
- return result;
- } // operation_on_pair_of_heat_maps
-
- /**
- * Multiplication of Persistence_heat_maps by scalar (so that all values of the heat map gets multiplied by that
- *scalar).
- **/
- Persistence_heat_maps multiply_by_scalar(double scalar) const {
- Persistence_heat_maps result;
- result.min_ = this->min_;
- result.max_ = this->max_;
- result.heat_map.reserve(this->heat_map.size());
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- std::vector<double> v;
- v.reserve(this->heat_map[i].size());
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- v.push_back(this->heat_map[i][j] * scalar);
- }
- result.heat_map.push_back(v);
- }
- return result;
- }
-
- /**
- * This function computes a sum of two objects of a type Persistence_heat_maps.
- **/
- friend Persistence_heat_maps operator+(const Persistence_heat_maps& first, const Persistence_heat_maps& second) {
- return operation_on_pair_of_heat_maps(first, second, std::plus<double>());
- }
- /**
-* This function computes a difference of two objects of a type Persistence_heat_maps.
-**/
- friend Persistence_heat_maps operator-(const Persistence_heat_maps& first, const Persistence_heat_maps& second) {
- return operation_on_pair_of_heat_maps(first, second, std::minus<double>());
- }
- /**
-* This function computes a product of an object of a type Persistence_heat_maps with real number.
-**/
- friend Persistence_heat_maps operator*(double scalar, const Persistence_heat_maps& A) {
- return A.multiply_by_scalar(scalar);
- }
- /**
-* This function computes a product of an object of a type Persistence_heat_maps with real number.
-**/
- friend Persistence_heat_maps operator*(const Persistence_heat_maps& A, double scalar) {
- return A.multiply_by_scalar(scalar);
- }
- /**
-* This function computes a product of an object of a type Persistence_heat_maps with real number.
-**/
- Persistence_heat_maps operator*(double scalar) { return this->multiply_by_scalar(scalar); }
- /**
- * += operator for Persistence_heat_maps.
- **/
- Persistence_heat_maps operator+=(const Persistence_heat_maps& rhs) {
- *this = *this + rhs;
- return *this;
- }
- /**
- * -= operator for Persistence_heat_maps.
- **/
- Persistence_heat_maps operator-=(const Persistence_heat_maps& rhs) {
- *this = *this - rhs;
- return *this;
- }
- /**
- * *= operator for Persistence_heat_maps.
- **/
- Persistence_heat_maps operator*=(double x) {
- *this = *this * x;
- return *this;
- }
- /**
- * /= operator for Persistence_heat_maps.
- **/
- Persistence_heat_maps operator/=(double x) {
- if (x == 0) throw("In operator /=, division by 0. Program terminated.");
- *this = *this * (1 / x);
- return *this;
- }
-
- // Implementations of functions for various concepts.
-
- /**
- * This function produce a vector of doubles based on a persistence heat map. It is required in a concept
- * Vectorized_topological_data
- */
- std::vector<double> vectorize(int number_of_function) const;
- /**
- * This function return the number of functions that allows vectorization of persistence heat map. It is required
- *in a concept Vectorized_topological_data.
- **/
- size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization; }
-
- /**
- * This function is required by the Real_valued_topological_data concept. It returns various projections on the
- *persistence heat map to a real line.
- * At the moment this function is not tested, since it is quite likely to be changed in the future. Given this, when
- *using it, keep in mind that it
- * will be most likely changed in the next versions.
- **/
- double project_to_R(int number_of_function) const;
- /**
- * The function gives the number of possible projections to R. This function is required by the
- *Real_valued_topological_data concept.
- **/
- size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals; }
-
- /**
- * A function to compute distance between persistence heat maps.
- * The parameter of this function is a const reference to an object of a class Persistence_heat_maps.
- * This function is required in Topological_data_with_distances concept.
-* For max norm distance, set power to std::numeric_limits<double>::max()
- **/
- double distance(const Persistence_heat_maps& second_, double power = 1) const;
-
- /**
- * A function to compute averaged persistence heat map, based on vector of persistence heat maps.
- * This function is required by Topological_data_with_averages concept.
- **/
- void compute_average(const std::vector<Persistence_heat_maps*>& to_average);
-
- /**
- * A function to compute scalar product of persistence heat maps.
- * The parameter of this function is a const reference to an object of a class Persistence_heat_maps.
- * This function is required in Topological_data_with_scalar_product concept.
- **/
- double compute_scalar_product(const Persistence_heat_maps& second_) const;
-
- // end of implementation of functions needed for concepts.
-
- /**
- * The x-range of the persistence heat map.
- **/
- std::pair<double, double> get_x_range() const { return std::make_pair(this->min_, this->max_); }
-
- /**
- * The y-range of the persistence heat map.
- **/
- std::pair<double, double> get_y_range() const { return this->get_x_range(); }
-
- protected:
- // private methods
- std::vector<std::vector<double> > check_and_initialize_maps(const std::vector<Persistence_heat_maps*>& maps);
- size_t number_of_functions_for_vectorization;
- size_t number_of_functions_for_projections_to_reals;
- void construct(const std::vector<std::pair<double, double> >& intervals_,
- std::vector<std::vector<double> > filter = create_Gaussian_filter(5, 1),
-
- bool erase_below_diagonal = false, size_t number_of_pixels = 1000,
- double min_ = std::numeric_limits<double>::max(), double max_ = std::numeric_limits<double>::max());
-
- void set_up_parameters_for_basic_classes() {
- this->number_of_functions_for_vectorization = 1;
- this->number_of_functions_for_projections_to_reals = 1;
- }
-
- // data
- Scalling_of_kernels f;
- bool erase_below_diagonal;
- double min_;
- double max_;
- std::vector<std::vector<double> > heat_map;
-};
-
-// if min_ == max_, then the program is requested to set up the values itself based on persistence intervals
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::construct(const std::vector<std::pair<double, double> >& intervals_,
- std::vector<std::vector<double> > filter,
- bool erase_below_diagonal, size_t number_of_pixels,
- double min_, double max_) {
- bool dbg = false;
- if (dbg) std::cerr << "Entering construct procedure \n";
- Scalling_of_kernels f;
- this->f = f;
-
- if (dbg) std::cerr << "min and max passed to construct() procedure: " << min_ << " " << max_ << std::endl;
-
- if (min_ == max_) {
- if (dbg) std::cerr << "min and max parameters will be determined based on intervals \n";
- // in this case, we want the program to set up the min_ and max_ values by itself.
- min_ = std::numeric_limits<int>::max();
- max_ = -std::numeric_limits<int>::max();
-
- for (size_t i = 0; i != intervals_.size(); ++i) {
- if (intervals_[i].first < min_) min_ = intervals_[i].first;
- if (intervals_[i].second > max_) max_ = intervals_[i].second;
- }
- // now we have the structure filled in, and moreover we know min_ and max_ values of the interval, so we know the
- // range.
-
- // add some more space:
- min_ -= fabs(max_ - min_) / 100;
- max_ += fabs(max_ - min_) / 100;
- }
-
- if (dbg) {
- std::cerr << "min_ : " << min_ << std::endl;
- std::cerr << "max_ : " << max_ << std::endl;
- std::cerr << "number_of_pixels : " << number_of_pixels << std::endl;
- getchar();
- }
-
- this->min_ = min_;
- this->max_ = max_;
-
- // initialization of the structure heat_map
- std::vector<std::vector<double> > heat_map_;
- for (size_t i = 0; i != number_of_pixels; ++i) {
- std::vector<double> v(number_of_pixels, 0);
- heat_map_.push_back(v);
- }
- this->heat_map = heat_map_;
-
- if (dbg) std::cerr << "Done creating of the heat map, now we will fill in the structure \n";
-
- for (size_t pt_nr = 0; pt_nr != intervals_.size(); ++pt_nr) {
- // compute the value of intervals_[pt_nr] in the grid:
- int x_grid =
- static_cast<int>((intervals_[pt_nr].first - this->min_) / (this->max_ - this->min_) * number_of_pixels);
- int y_grid =
- static_cast<int>((intervals_[pt_nr].second - this->min_) / (this->max_ - this->min_) * number_of_pixels);
-
- if (dbg) {
- std::cerr << "point : " << intervals_[pt_nr].first << " , " << intervals_[pt_nr].second << std::endl;
- std::cerr << "x_grid : " << x_grid << std::endl;
- std::cerr << "y_grid : " << y_grid << std::endl;
- }
-
- // x_grid and y_grid gives a center of the kernel. We want to have its lower left corner. To get this, we need to
- // shift x_grid and y_grid by a grid diameter.
- x_grid -= filter.size() / 2;
- y_grid -= filter.size() / 2;
- // note that the numbers x_grid and y_grid may be negative.
-
- if (dbg) {
- std::cerr << "After shift : \n";
- std::cerr << "x_grid : " << x_grid << std::endl;
- std::cerr << "y_grid : " << y_grid << std::endl;
- }
-
- double scaling_value = this->f(intervals_[pt_nr]);
-
- for (size_t i = 0; i != filter.size(); ++i) {
- for (size_t j = 0; j != filter.size(); ++j) {
- // if the point (x_grid+i,y_grid+j) is the correct point in the grid.
- if (((x_grid + i) >= 0) && (x_grid + i < this->heat_map.size()) && ((y_grid + j) >= 0) &&
- (y_grid + j < this->heat_map.size())) {
- if (dbg) {
- std::cerr << y_grid + j << " " << x_grid + i << std::endl;
- }
- this->heat_map[y_grid + j][x_grid + i] += scaling_value * filter[i][j];
- if (dbg) {
- std::cerr << "Position : (" << x_grid + i << "," << y_grid + j
- << ") got increased by the value : " << filter[i][j] << std::endl;
- }
- }
- }
- }
- }
-
- // now it remains to cut everything below diagonal if the user wants us to.
- if (erase_below_diagonal) {
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = i; j != this->heat_map.size(); ++j) {
- this->heat_map[i][j] = 0;
- }
- }
- }
-} // construct
-
-template <typename Scalling_of_kernels>
-Persistence_heat_maps<Scalling_of_kernels>::Persistence_heat_maps(
- const std::vector<std::pair<double, double> >& interval, std::vector<std::vector<double> > filter,
- bool erase_below_diagonal, size_t number_of_pixels, double min_, double max_) {
- this->construct(interval, filter, erase_below_diagonal, number_of_pixels, min_, max_);
- this->set_up_parameters_for_basic_classes();
-}
-
-template <typename Scalling_of_kernels>
-Persistence_heat_maps<Scalling_of_kernels>::Persistence_heat_maps(const char* filename,
- std::vector<std::vector<double> > filter,
- bool erase_below_diagonal, size_t number_of_pixels,
- double min_, double max_, unsigned dimension) {
- std::vector<std::pair<double, double> > intervals_;
- if (dimension == std::numeric_limits<unsigned>::max()) {
- intervals_ = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- intervals_ = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->construct(intervals_, filter, erase_below_diagonal, number_of_pixels, min_, max_);
- this->set_up_parameters_for_basic_classes();
-}
-
-template <typename Scalling_of_kernels>
-std::vector<std::vector<double> > Persistence_heat_maps<Scalling_of_kernels>::check_and_initialize_maps(
- const std::vector<Persistence_heat_maps*>& maps) {
- // checking if all the heat maps are of the same size:
- for (size_t i = 0; i != maps.size(); ++i) {
- if (maps[i]->heat_map.size() != maps[0]->heat_map.size()) {
- std::cerr << "Sizes of Persistence_heat_maps are not compatible. The program will terminate now \n";
- throw "Sizes of Persistence_heat_maps are not compatible. The program will terminate now \n";
- }
- if (maps[i]->heat_map[0].size() != maps[0]->heat_map[0].size()) {
- std::cerr << "Sizes of Persistence_heat_maps are not compatible. The program will terminate now \n";
- throw "Sizes of Persistence_heat_maps are not compatible. The program will terminate now \n";
- }
- }
- std::vector<std::vector<double> > heat_maps(maps[0]->heat_map.size());
- for (size_t i = 0; i != maps[0]->heat_map.size(); ++i) {
- std::vector<double> v(maps[0]->heat_map[0].size(), 0);
- heat_maps[i] = v;
- }
- return heat_maps;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::compute_median(const std::vector<Persistence_heat_maps*>& maps) {
- std::vector<std::vector<double> > heat_maps = this->check_and_initialize_maps(maps);
-
- std::vector<double> to_compute_median(maps.size());
- for (size_t i = 0; i != heat_maps.size(); ++i) {
- for (size_t j = 0; j != heat_maps[i].size(); ++j) {
- for (size_t map_no = 0; map_no != maps.size(); ++map_no) {
- to_compute_median[map_no] = maps[map_no]->heat_map[i][j];
- }
- std::nth_element(to_compute_median.begin(), to_compute_median.begin() + to_compute_median.size() / 2,
- to_compute_median.end());
- heat_maps[i][j] = to_compute_median[to_compute_median.size() / 2];
- }
- }
- this->heat_map = heat_maps;
- this->min_ = maps[0]->min_;
- this->max_ = maps[0]->max_;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::compute_mean(const std::vector<Persistence_heat_maps*>& maps) {
- std::vector<std::vector<double> > heat_maps = this->check_and_initialize_maps(maps);
- for (size_t i = 0; i != heat_maps.size(); ++i) {
- for (size_t j = 0; j != heat_maps[i].size(); ++j) {
- double mean = 0;
- for (size_t map_no = 0; map_no != maps.size(); ++map_no) {
- mean += maps[map_no]->heat_map[i][j];
- }
- heat_maps[i][j] = mean / static_cast<double>(maps.size());
- }
- }
- this->heat_map = heat_maps;
- this->min_ = maps[0]->min_;
- this->max_ = maps[0]->max_;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::compute_percentage_of_active(
- const std::vector<Persistence_heat_maps*>& maps, size_t cutoff) {
- std::vector<std::vector<double> > heat_maps = this->check_and_initialize_maps(maps);
-
- for (size_t i = 0; i != heat_maps.size(); ++i) {
- for (size_t j = 0; j != heat_maps[i].size(); ++j) {
- size_t number_of_active_levels = 0;
- for (size_t map_no = 0; map_no != maps.size(); ++map_no) {
- if (maps[map_no]->heat_map[i][j]) number_of_active_levels++;
- }
- if (number_of_active_levels > cutoff) {
- heat_maps[i][j] = number_of_active_levels;
- } else {
- heat_maps[i][j] = 0;
- }
- }
- }
- this->heat_map = heat_maps;
- this->min_ = maps[0]->min_;
- this->max_ = maps[0]->max_;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::plot(const char* filename) const {
- std::ofstream out;
- std::stringstream gnuplot_script;
- gnuplot_script << filename << "_GnuplotScript";
-
- out.open(gnuplot_script.str().c_str());
- out << "plot '-' matrix with image" << std::endl;
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- out << this->heat_map[i][j] << " ";
- }
- out << std::endl;
- }
- out.close();
- std::cout << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
- << gnuplot_script.str().c_str() << "\'\"" << std::endl;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::print_to_file(const char* filename) const {
- std::ofstream out;
- out.open(filename);
-
- // First we store this->min_ and this->max_ values:
- out << this->min_ << " " << this->max_ << std::endl;
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- out << this->heat_map[i][j] << " ";
- }
- out << std::endl;
- }
- out.close();
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::load_from_file(const char* filename) {
- bool dbg = false;
-
- std::ifstream in;
- in.open(filename);
-
- // checking if the file exist / if it was open.
- if (!in.good()) {
- std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
- throw "The persistence landscape file do not exist. The program will now terminate \n";
- }
-
- // now we read the file one by one.
-
- in >> this->min_ >> this->max_;
- if (dbg) {
- std::cerr << "Reading the following values of min and max : " << this->min_ << " , " << this->max_ << std::endl;
- }
-
- std::string temp;
- std::getline(in, temp);
- while (in.good()) {
- std::getline(in, temp);
- std::stringstream lineSS;
- lineSS << temp;
-
- std::vector<double> line_of_heat_map;
- while (lineSS.good()) {
- double point;
-
- lineSS >> point;
- line_of_heat_map.push_back(point);
- if (dbg) {
- std::cout << point << " ";
- }
- }
- if (dbg) {
- std::cout << std::endl;
- getchar();
- }
-
- if (in.good()) this->heat_map.push_back(line_of_heat_map);
- }
- in.close();
- if (dbg) std::cout << "Done \n";
-}
-
-// Concretizations of virtual methods:
-template <typename Scalling_of_kernels>
-std::vector<double> Persistence_heat_maps<Scalling_of_kernels>::vectorize(int number_of_function) const {
- // convert this->heat_map into one large vector:
- size_t size_of_result = 0;
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- size_of_result += this->heat_map[i].size();
- }
-
- std::vector<double> result;
- result.reserve(size_of_result);
-
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- result.push_back(this->heat_map[i][j]);
- }
- }
-
- return result;
-}
-
-template <typename Scalling_of_kernels>
-double Persistence_heat_maps<Scalling_of_kernels>::distance(const Persistence_heat_maps& second, double power) const {
- // first we need to check if (*this) and second are defined on the same domain and have the same dimensions:
- if (!this->check_if_the_same(second)) {
- std::cerr << "The persistence images are of non compatible sizes. We cannot therefore compute distance between "
- "them. The program will now terminate";
- throw "The persistence images are of non compatible sizes. The program will now terminate";
- }
-
- // if we are here, we know that the two persistence images are defined on the same domain, so we can start computing
- // their distances:
-
- double distance = 0;
- if (power < std::numeric_limits<double>::max()) {
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- distance += pow(fabs(this->heat_map[i][j] - second.heat_map[i][j]), power);
- }
- }
- } else {
- // in this case, we compute max norm distance
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- if (distance < fabs(this->heat_map[i][j] - second.heat_map[i][j])) {
- distance = fabs(this->heat_map[i][j] - second.heat_map[i][j]);
- }
- }
- }
- }
- return distance;
-}
-
-template <typename Scalling_of_kernels>
-double Persistence_heat_maps<Scalling_of_kernels>::project_to_R(int number_of_function) const {
- double result = 0;
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- result += this->heat_map[i][j];
- }
- }
- return result;
-}
-
-template <typename Scalling_of_kernels>
-void Persistence_heat_maps<Scalling_of_kernels>::compute_average(
- const std::vector<Persistence_heat_maps*>& to_average) {
- this->compute_mean(to_average);
-}
-
-template <typename Scalling_of_kernels>
-double Persistence_heat_maps<Scalling_of_kernels>::compute_scalar_product(const Persistence_heat_maps& second) const {
- // first we need to check if (*this) and second are defined on the same domain and have the same dimensions:
- if (!this->check_if_the_same(second)) {
- std::cerr << "The persistence images are of non compatible sizes. We cannot therefore compute distance between "
- "them. The program will now terminate";
- throw "The persistence images are of non compatible sizes. The program will now terminate";
- }
-
- // if we are here, we know that the two persistence images are defined on the same domain, so we can start computing
- // their scalar product:
- double scalar_prod = 0;
- for (size_t i = 0; i != this->heat_map.size(); ++i) {
- for (size_t j = 0; j != this->heat_map[i].size(); ++j) {
- scalar_prod += this->heat_map[i][j] * second.heat_map[i][j];
- }
- }
- return scalar_prod;
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_HEAT_MAPS_H_
diff --git a/include/gudhi/Persistence_intervals.h b/include/gudhi/Persistence_intervals.h
deleted file mode 100644
index 76eac7d7..00000000
--- a/include/gudhi/Persistence_intervals.h
+++ /dev/null
@@ -1,570 +0,0 @@
-/* This file is part of the Gudhi hiLibrary. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_INTERVALS_H_
-#define PERSISTENCE_INTERVALS_H_
-
-// gudhi include
-#include <gudhi/read_persistence_from_file.h>
-
-// standard include
-#include <limits>
-#include <iostream>
-#include <fstream>
-#include <vector>
-#include <algorithm>
-#include <cmath>
-#include <functional>
-#include <utility>
-#include <string>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-/**
- * This class implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
- *Real_valued_topological_data
-**/
-class Persistence_intervals {
- public:
- /**
- * This is a constructor of a class Persistence_intervals from a text file. Each line of the input file is supposed to
- *contain two numbers of a type double (or convertible to double)
- * representing the birth and the death of the persistence interval. If the pairs are not sorted so that birth <=
- *death, then the constructor will sort then that way.
- * * The second parameter of a constructor is a dimension of intervals to be read from a file. If your file contains
- *only birth-death pairs, use the default value.
- **/
- Persistence_intervals(const char* filename, unsigned dimension = std::numeric_limits<unsigned>::max());
-
- /**
- * This is a constructor of a class Persistence_intervals from a vector of pairs. Each pair is assumed to represent a
- *persistence interval. We assume that the first elements of pairs
- * are smaller or equal the second elements of pairs.
- **/
- Persistence_intervals(const std::vector<std::pair<double, double> >& intervals);
-
- /**
- * This procedure returns x-range of a given persistence diagram.
- **/
- std::pair<double, double> get_x_range() const {
- double min_ = std::numeric_limits<int>::max();
- double max_ = -std::numeric_limits<int>::max();
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- if (this->intervals[i].first < min_) min_ = this->intervals[i].first;
- if (this->intervals[i].second > max_) max_ = this->intervals[i].second;
- }
- return std::make_pair(min_, max_);
- }
-
- /**
- * This procedure returns y-range of a given persistence diagram.
- **/
- std::pair<double, double> get_y_range() const {
- double min_ = std::numeric_limits<int>::max();
- double max_ = -std::numeric_limits<int>::max();
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- if (this->intervals[i].second < min_) min_ = this->intervals[i].second;
- if (this->intervals[i].second > max_) max_ = this->intervals[i].second;
- }
- return std::make_pair(min_, max_);
- }
-
- /**
- * Procedure that compute the vector of lengths of the dominant (i.e. the longest) persistence intervals. The list is
- *truncated at the parameter of the call where_to_cut (set by default to 100).
- **/
- std::vector<double> length_of_dominant_intervals(size_t where_to_cut = 100) const;
-
- /**
- * Procedure that compute the vector of the dominant (i.e. the longest) persistence intervals. The parameter of
- *the procedure (set by default to 100) is the number of dominant intervals returned by the procedure.
- **/
- std::vector<std::pair<double, double> > dominant_intervals(size_t where_to_cut = 100) const;
-
- /**
- * Procedure to compute a histogram of interval's length. A histogram is a block plot. The number of blocks is
- *determined by the first parameter of the function (set by default to 10).
- * For the sake of argument let us assume that the length of the longest interval is 1 and the number of bins is
- *10. In this case the i-th block correspond to a range between i-1/10 and i10.
- * The vale of a block supported at the interval is the number of persistence intervals of a length between x_0
- *and x_1.
- **/
- std::vector<size_t> histogram_of_lengths(size_t number_of_bins = 10) const;
-
- /**
- * Based on a histogram of intervals lengths computed by the function histogram_of_lengths H the procedure below
- *computes the cumulative histogram. The i-th position of the resulting histogram
- * is the sum of values of H for the positions from 0 to i.
- **/
- std::vector<size_t> cumulative_histogram_of_lengths(size_t number_of_bins = 10) const;
-
- /**
- * In this procedure we assume that each barcode is a characteristic function of a hight equal to its length. The
- *persistence diagram is a sum of such a functions. The procedure below construct a function being a
- * sum of the characteristic functions of persistence intervals. The first two parameters are the range in which the
- *function is to be computed and the last parameter is the number of bins in
- * the discretization of the interval [_min,_max].
- **/
- std::vector<double> characteristic_function_of_diagram(double x_min, double x_max, size_t number_of_bins = 10) const;
-
- /**
- * Cumulative version of the function characteristic_function_of_diagram
- **/
- std::vector<double> cumulative_characteristic_function_of_diagram(double x_min, double x_max,
- size_t number_of_bins = 10) const;
-
- /**
- * Compute the function of persistence Betti numbers. The returned value is a vector of pair. First element of each
- *pair is a place where persistence Betti numbers change.
- * Second element of each pair is the value of Persistence Betti numbers at that point.
- **/
- std::vector<std::pair<double, size_t> > compute_persistent_betti_numbers() const;
-
- /**
- *This is a non optimal procedure that compute vector of distances from each point of diagram to its k-th nearest
- *neighbor (k is a parameter of the program). The resulting vector is by default truncated to 10
- *elements (this value can be changed by using the second parameter of the program). The points are returned in order
- *from the ones which are farthest away from their k-th nearest neighbors.
- **/
- std::vector<double> k_n_n(size_t k, size_t where_to_cut = 10) const;
-
- /**
-* Operator that send the diagram to a stream.
-**/
- friend std::ostream& operator<<(std::ostream& out, const Persistence_intervals& intervals) {
- for (size_t i = 0; i != intervals.intervals.size(); ++i) {
- out << intervals.intervals[i].first << " " << intervals.intervals[i].second << std::endl;
- }
- return out;
- }
-
- /**
- * Generating gnuplot script to plot the interval.
- **/
- void plot(const char* filename, double min_x = std::numeric_limits<double>::max(),
- double max_x = std::numeric_limits<double>::max(), double min_y = std::numeric_limits<double>::max(),
- double max_y = std::numeric_limits<double>::max()) const {
- // this program create a gnuplot script file that allows to plot persistence diagram.
- std::ofstream out;
-
- std::stringstream gnuplot_script;
- gnuplot_script << filename << "_GnuplotScript";
-
- out.open(gnuplot_script.str().c_str());
-
- std::pair<double, double> min_max_values = this->get_x_range();
- if (min_x == max_x) {
- out << "set xrange [" << min_max_values.first - 0.1 * (min_max_values.second - min_max_values.first) << " : "
- << min_max_values.second + 0.1 * (min_max_values.second - min_max_values.first) << " ]" << std::endl;
- out << "set yrange [" << min_max_values.first - 0.1 * (min_max_values.second - min_max_values.first) << " : "
- << min_max_values.second + 0.1 * (min_max_values.second - min_max_values.first) << " ]" << std::endl;
- } else {
- out << "set xrange [" << min_x << " : " << max_x << " ]" << std::endl;
- out << "set yrange [" << min_y << " : " << max_y << " ]" << std::endl;
- }
- out << "plot '-' using 1:2 notitle \"" << filename << "\", \\" << std::endl;
- out << " '-' using 1:2 notitle with lp" << std::endl;
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- out << this->intervals[i].first << " " << this->intervals[i].second << std::endl;
- }
- out << "EOF" << std::endl;
- out << min_max_values.first - 0.1 * (min_max_values.second - min_max_values.first) << " "
- << min_max_values.first - 0.1 * (min_max_values.second - min_max_values.first) << std::endl;
- out << min_max_values.second + 0.1 * (min_max_values.second - min_max_values.first) << " "
- << min_max_values.second + 0.1 * (min_max_values.second - min_max_values.first) << std::endl;
-
- out.close();
-
- std::cout << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
- << gnuplot_script.str().c_str() << "\'\"" << std::endl;
- }
-
- /**
-* Return number of points in the diagram.
-**/
- size_t size() const { return this->intervals.size(); }
-
- /**
- * Return the persistence interval at the given position. Note that intervals are not sorted with respect to their
- *lengths.
- **/
- inline std::pair<double, double> operator[](size_t i) const {
- if (i >= this->intervals.size()) throw("Index out of range! Operator [], one_d_gaussians class\n");
- return this->intervals[i];
- }
-
- // Implementations of functions for various concepts.
- /**
- * This is a simple function projecting the persistence intervals to a real number. The function we use here is a sum
- *of squared lengths of intervals. It can be naturally interpreted as
- * sum of step function, where the step hight it equal to the length of the interval.
- * At the moment this function is not tested, since it is quite likely to be changed in the future. Given this, when
- *using it, keep in mind that it
- * will be most likely changed in the next versions.
- **/
- double project_to_R(int number_of_function) const;
- /**
- * The function gives the number of possible projections to R. This function is required by the
- *Real_valued_topological_data concept.
- **/
- size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals; }
-
- /**
- * Return a family of vectors obtained from the persistence diagram. The i-th vector consist of the length of i
- *dominant persistence intervals.
- **/
- std::vector<double> vectorize(int number_of_function) const {
- return this->length_of_dominant_intervals(number_of_function);
- }
- /**
- * This function return the number of functions that allows vectorization of a persistence diagram. It is required
- *in a concept Vectorized_topological_data.
- **/
- size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization; }
-
- // end of implementation of functions needed for concepts.
-
- // For visualization use output from vectorize and build histograms.
- std::vector<std::pair<double, double> > output_for_visualization() { return this->intervals; }
-
- protected:
- void set_up_numbers_of_functions_for_vectorization_and_projections_to_reals() {
- // warning, this function can be only called after filling in the intervals vector.
- this->number_of_functions_for_vectorization = this->intervals.size();
- this->number_of_functions_for_projections_to_reals = 1;
- }
-
- std::vector<std::pair<double, double> > intervals;
- size_t number_of_functions_for_vectorization;
- size_t number_of_functions_for_projections_to_reals;
-};
-
-Persistence_intervals::Persistence_intervals(const char* filename, unsigned dimension) {
- if (dimension == std::numeric_limits<unsigned>::max()) {
- this->intervals = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- this->intervals = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-} // Persistence_intervals
-
-Persistence_intervals::Persistence_intervals(const std::vector<std::pair<double, double> >& intervals_)
- : intervals(intervals_) {
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-}
-
-std::vector<double> Persistence_intervals::length_of_dominant_intervals(size_t where_to_cut) const {
- std::vector<double> result(this->intervals.size());
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- result[i] = this->intervals[i].second - this->intervals[i].first;
- }
- std::sort(result.begin(), result.end(), std::greater<double>());
-
- result.resize(std::min(where_to_cut, result.size()));
- return result;
-} // length_of_dominant_intervals
-
-bool compare(const std::pair<size_t, double>& first, const std::pair<size_t, double>& second) {
- return first.second > second.second;
-}
-
-std::vector<std::pair<double, double> > Persistence_intervals::dominant_intervals(size_t where_to_cut) const {
- bool dbg = false;
- std::vector<std::pair<size_t, double> > position_length_vector(this->intervals.size());
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- position_length_vector[i] = std::make_pair(i, this->intervals[i].second - this->intervals[i].first);
- }
-
- std::sort(position_length_vector.begin(), position_length_vector.end(), compare);
-
- std::vector<std::pair<double, double> > result;
- result.reserve(std::min(where_to_cut, position_length_vector.size()));
-
- for (size_t i = 0; i != std::min(where_to_cut, position_length_vector.size()); ++i) {
- result.push_back(this->intervals[position_length_vector[i].first]);
- if (dbg)
- std::cerr << "Position : " << position_length_vector[i].first << " length : " << position_length_vector[i].second
- << std::endl;
- }
-
- return result;
-} // dominant_intervals
-
-std::vector<size_t> Persistence_intervals::histogram_of_lengths(size_t number_of_bins) const {
- bool dbg = false;
-
- if (dbg) std::cerr << "this->intervals.size() : " << this->intervals.size() << std::endl;
- // first find the length of the longest interval:
- double lengthOfLongest = 0;
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- if ((this->intervals[i].second - this->intervals[i].first) > lengthOfLongest) {
- lengthOfLongest = this->intervals[i].second - this->intervals[i].first;
- }
- }
-
- if (dbg) {
- std::cerr << "lengthOfLongest : " << lengthOfLongest << std::endl;
- }
-
- // this is a container we will use to store the resulting histogram
- std::vector<size_t> result(number_of_bins + 1, 0);
-
- // for every persistence interval in our collection.
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- // compute its length relative to the length of the dominant interval:
- double relative_length_of_this_interval = (this->intervals[i].second - this->intervals[i].first) / lengthOfLongest;
-
- // given the relative length (between 0 and 1) compute to which bin should it contribute.
- size_t position = (size_t)(relative_length_of_this_interval * number_of_bins);
-
- ++result[position];
-
- if (dbg) {
- std::cerr << "i : " << i << std::endl;
- std::cerr << "Interval : [" << this->intervals[i].first << " , " << this->intervals[i].second << " ] \n";
- std::cerr << "relative_length_of_this_interval : " << relative_length_of_this_interval << std::endl;
- std::cerr << "position : " << position << std::endl;
- getchar();
- }
- }
-
- if (dbg) {
- for (size_t i = 0; i != result.size(); ++i) std::cerr << result[i] << std::endl;
- }
- return result;
-}
-
-std::vector<size_t> Persistence_intervals::cumulative_histogram_of_lengths(size_t number_of_bins) const {
- std::vector<size_t> histogram = this->histogram_of_lengths(number_of_bins);
- std::vector<size_t> result(histogram.size());
-
- size_t sum = 0;
- for (size_t i = 0; i != histogram.size(); ++i) {
- sum += histogram[i];
- result[i] = sum;
- }
- return result;
-}
-
-std::vector<double> Persistence_intervals::characteristic_function_of_diagram(double x_min, double x_max,
- size_t number_of_bins) const {
- bool dbg = false;
-
- std::vector<double> result(number_of_bins);
- std::fill(result.begin(), result.end(), 0);
-
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- if (dbg) {
- std::cerr << "Interval : " << this->intervals[i].first << " , " << this->intervals[i].second << std::endl;
- }
-
- size_t beginIt = 0;
- if (this->intervals[i].first < x_min) beginIt = 0;
- if (this->intervals[i].first >= x_max) beginIt = result.size();
- if ((this->intervals[i].first > x_min) && (this->intervals[i].first < x_max)) {
- beginIt = number_of_bins * (this->intervals[i].first - x_min) / (x_max - x_min);
- }
-
- size_t endIt = 0;
- if (this->intervals[i].second < x_min) endIt = 0;
- if (this->intervals[i].second >= x_max) endIt = result.size();
- if ((this->intervals[i].second > x_min) && (this->intervals[i].second < x_max)) {
- endIt = number_of_bins * (this->intervals[i].second - x_min) / (x_max - x_min);
- }
-
- if (beginIt > endIt) {
- beginIt = endIt;
- }
-
- if (dbg) {
- std::cerr << "beginIt : " << beginIt << std::endl;
- std::cerr << "endIt : " << endIt << std::endl;
- }
-
- for (size_t pos = beginIt; pos != endIt; ++pos) {
- result[pos] += ((x_max - x_min) / static_cast<double>(number_of_bins)) *
- (this->intervals[i].second - this->intervals[i].first);
- }
- if (dbg) {
- std::cerr << "Result at this stage \n";
- for (size_t aa = 0; aa != result.size(); ++aa) {
- std::cerr << result[aa] << " ";
- }
- std::cerr << std::endl;
- }
- }
- return result;
-} // characteristic_function_of_diagram
-
-std::vector<double> Persistence_intervals::cumulative_characteristic_function_of_diagram(double x_min, double x_max,
- size_t number_of_bins) const {
- std::vector<double> intsOfBars = this->characteristic_function_of_diagram(x_min, x_max, number_of_bins);
- std::vector<double> result(intsOfBars.size());
- double sum = 0;
- for (size_t i = 0; i != intsOfBars.size(); ++i) {
- sum += intsOfBars[i];
- result[i] = sum;
- }
- return result;
-} // cumulative_characteristic_function_of_diagram
-
-template <typename T>
-bool compare_first_element_of_pair(const std::pair<T, bool>& f, const std::pair<T, bool>& s) {
- return (f.first < s.first);
-}
-
-std::vector<std::pair<double, size_t> > Persistence_intervals::compute_persistent_betti_numbers() const {
- std::vector<std::pair<double, bool> > places_where_pbs_change(2 * this->intervals.size());
-
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- places_where_pbs_change[2 * i] = std::make_pair(this->intervals[i].first, true);
- places_where_pbs_change[2 * i + 1] = std::make_pair(this->intervals[i].second, false);
- }
-
- std::sort(places_where_pbs_change.begin(), places_where_pbs_change.end(), compare_first_element_of_pair<double>);
- size_t pbn = 0;
- std::vector<std::pair<double, size_t> > pbns(places_where_pbs_change.size());
- for (size_t i = 0; i != places_where_pbs_change.size(); ++i) {
- if (places_where_pbs_change[i].second == true) {
- ++pbn;
- } else {
- --pbn;
- }
- pbns[i] = std::make_pair(places_where_pbs_change[i].first, pbn);
- }
- return pbns;
-}
-
-inline double compute_euclidean_distance(const std::pair<double, double>& f, const std::pair<double, double>& s) {
- return sqrt((f.first - s.first) * (f.first - s.first) + (f.second - s.second) * (f.second - s.second));
-}
-
-std::vector<double> Persistence_intervals::k_n_n(size_t k, size_t where_to_cut) const {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Here are the intervals : \n";
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- std::cerr << "[ " << this->intervals[i].first << " , " << this->intervals[i].second << "] \n";
- }
- getchar();
- }
-
- std::vector<double> result;
- // compute all to all distance between point in the diagram. Also, consider points in the diagonal with the infinite
- // multiplicity.
- std::vector<std::vector<double> > distances(this->intervals.size());
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- std::vector<double> aa(this->intervals.size());
- std::fill(aa.begin(), aa.end(), 0);
- distances[i] = aa;
- }
- std::vector<double> distances_from_diagonal(this->intervals.size());
- std::fill(distances_from_diagonal.begin(), distances_from_diagonal.end(), 0);
-
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- std::vector<double> distancesFromI;
- for (size_t j = i + 1; j != this->intervals.size(); ++j) {
- distancesFromI.push_back(compute_euclidean_distance(this->intervals[i], this->intervals[j]));
- }
- // also add a distance from this guy to diagonal:
- double distanceToDiagonal = compute_euclidean_distance(
- this->intervals[i], std::make_pair(0.5 * (this->intervals[i].first + this->intervals[i].second),
- 0.5 * (this->intervals[i].first + this->intervals[i].second)));
- distances_from_diagonal[i] = distanceToDiagonal;
-
- if (dbg) {
- std::cerr << "Here are the distances form the point : [" << this->intervals[i].first << " , "
- << this->intervals[i].second << "] in the diagram \n";
- for (size_t aa = 0; aa != distancesFromI.size(); ++aa) {
- std::cerr << "To : " << i + aa << " : " << distancesFromI[aa] << " ";
- }
- std::cerr << std::endl;
- getchar();
- }
-
- // filling in the distances matrix:
- for (size_t j = i + 1; j != this->intervals.size(); ++j) {
- distances[i][j] = distancesFromI[j - i - 1];
- distances[j][i] = distancesFromI[j - i - 1];
- }
- }
- if (dbg) {
- std::cerr << "Here is the distance matrix : \n";
- for (size_t i = 0; i != distances.size(); ++i) {
- for (size_t j = 0; j != distances.size(); ++j) {
- std::cerr << distances[i][j] << " ";
- }
- std::cerr << std::endl;
- }
- std::cerr << std::endl << std::endl << "And here are the distances to the diagonal : " << std::endl;
- for (size_t i = 0; i != distances_from_diagonal.size(); ++i) {
- std::cerr << distances_from_diagonal[i] << " ";
- }
- std::cerr << std::endl << std::endl;
- getchar();
- }
-
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- std::vector<double> distancesFromI = distances[i];
- distancesFromI.push_back(distances_from_diagonal[i]);
-
- // sort it:
- std::sort(distancesFromI.begin(), distancesFromI.end(), std::greater<double>());
-
- if (k > distancesFromI.size()) {
- if (dbg) {
- std::cerr << "There are not enough neighbors in your set. We set the result to plus infty \n";
- }
- result.push_back(std::numeric_limits<double>::max());
- } else {
- if (distances_from_diagonal[i] > distancesFromI[k]) {
- if (dbg) {
- std::cerr << "The k-th n.n. is on a diagonal. Therefore we set up a distance to diagonal \n";
- }
- result.push_back(distances_from_diagonal[i]);
- } else {
- result.push_back(distancesFromI[k]);
- }
- }
- }
- std::sort(result.begin(), result.end(), std::greater<double>());
- result.resize(std::min(result.size(), where_to_cut));
-
- return result;
-}
-
-double Persistence_intervals::project_to_R(int number_of_function) const {
- double result = 0;
-
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- result +=
- (this->intervals[i].second - this->intervals[i].first) * (this->intervals[i].second - this->intervals[i].first);
- }
-
- return result;
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_INTERVALS_H_
diff --git a/include/gudhi/Persistence_intervals_with_distances.h b/include/gudhi/Persistence_intervals_with_distances.h
deleted file mode 100644
index f48d1a3b..00000000
--- a/include/gudhi/Persistence_intervals_with_distances.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* This file is part of the Gudhi hiLibrary. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_INTERVALS_WITH_DISTANCES_H_
-#define PERSISTENCE_INTERVALS_WITH_DISTANCES_H_
-
-#include <gudhi/Persistence_intervals.h>
-#include <gudhi/Bottleneck.h>
-
-#include <limits>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-class Persistence_intervals_with_distances : public Persistence_intervals {
- public:
- using Persistence_intervals::Persistence_intervals;
-
- /**
- *Computations of distance from the current persistnce diagram to the persistence diagram given as a parameter of this
- *function.
- *The last but one parameter, power, is here in case we would like to compute p=th Wasserstein distance. At the
- *moment, this method only implement Bottleneck distance,
- * which is infinity Wasserstein distance. Therefore any power which is not the default std::numeric_limits< double
- *>::max() will be ignored and an
- * exception will be thrown.
- * The last parameter, tolerance, it is an additiv error of the approimation, set by default to zero.
- **/
- double distance(const Persistence_intervals_with_distances& second, double power = std::numeric_limits<double>::max(),
- double tolerance = (std::numeric_limits<double>::min)()) const {
- if (power >= std::numeric_limits<double>::max()) {
- return Gudhi::persistence_diagram::bottleneck_distance(this->intervals, second.intervals, tolerance);
- } else {
- std::cerr << "At the moment Gudhi do not support Wasserstein distances. We only support Bottleneck distance."
- << std::endl;
- throw "At the moment Gudhi do not support Wasserstein distances. We only support Bottleneck distance.";
- }
- }
-};
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_INTERVALS_WITH_DISTANCES_H_
diff --git a/include/gudhi/Persistence_landscape.h b/include/gudhi/Persistence_landscape.h
deleted file mode 100644
index 9cab0166..00000000
--- a/include/gudhi/Persistence_landscape.h
+++ /dev/null
@@ -1,1383 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_LANDSCAPE_H_
-#define PERSISTENCE_LANDSCAPE_H_
-
-// gudhi include
-#include <gudhi/read_persistence_from_file.h>
-#include <gudhi/common_persistence_representations.h>
-
-// standard include
-#include <cmath>
-#include <iostream>
-#include <vector>
-#include <limits>
-#include <fstream>
-#include <sstream>
-#include <algorithm>
-#include <string>
-#include <utility>
-#include <functional>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-// pre declaration
-class Persistence_landscape;
-template <typename operation>
-Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
- const Persistence_landscape& land2);
-
-/**
- * \class Persistence_landscape Persistence_landscape.h gudhi/Persistence_landscape.h
- * \brief A class implementing persistence landscapes data structures.
- *
- * \ingroup Persistence_representations
- *
- * \details
- * For theoretical description, please consult <i>Statistical topological data analysis using persistence
- * landscapes</i>\cite bubenik_landscapes_2015 , and for details of algorithms,
- * <i>A persistence landscapes toolbox for topological statistics</i>\cite bubenik_dlotko_landscapes_2016.
- *
- * Persistence landscapes allow vectorization, computations of distances, computations of projections to Real,
- * computations of averages and scalar products. Therefore they implement suitable interfaces.
- * It implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
- * Real_valued_topological_data, Topological_data_with_averages, Topological_data_with_scalar_product
- *
- * Note that at the moment, due to rounding errors during the construction of persistence landscapes, elements which
- * are different by 0.000005 are considered the same. If the scale in your persistence diagrams is comparable to this
- * value, please rescale them before use this code.
- *
-**/
-class Persistence_landscape {
- public:
- /**
- * Default constructor.
- **/
- Persistence_landscape() { this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals(); }
-
- /**
- * Constructor that takes as an input a vector of birth-death pairs.
- **/
- Persistence_landscape(const std::vector<std::pair<double, double> >& p,
- size_t number_of_levels = std::numeric_limits<size_t>::max());
-
- /**
- * Constructor that reads persistence intervals from file and creates persistence landscape. The format of the
- *input file is the following: in each line we put birth-death pair. Last line is assumed
- * to be empty. Even if the points within a line are not ordered, they will be ordered while the input is read.
- **/
- Persistence_landscape(const char* filename, size_t dimension = std::numeric_limits<unsigned>::max(),
- size_t number_of_levels = std::numeric_limits<size_t>::max());
-
- /**
- * This procedure loads a landscape from file. It erase all the data that was previously stored in this landscape.
- **/
- void load_landscape_from_file(const char* filename);
-
- /**
- * The procedure stores a landscape to a file. The file can be later used by a procedure load_landscape_from_file.
- **/
- void print_to_file(const char* filename) const;
-
- /**
- * This function compute integral of the landscape (defined formally as sum of integrals on R of all landscape
- *functions)
- **/
- double compute_integral_of_landscape() const;
-
- /**
- * This function compute integral of the 'level'-level of a landscape.
- **/
- double compute_integral_of_a_level_of_a_landscape(size_t level) const;
-
- /**
- * This function compute integral of the landscape p-th power of a landscape (defined formally as sum of integrals
- *on R of p-th powers of all landscape functions)
- **/
- double compute_integral_of_landscape(double p) const; // this function compute integral of p-th power of landscape.
-
- /**
- * A function that computes the value of a landscape at a given point. The parameters of the function are: unsigned
- *level and double x.
- * The procedure will compute the value of the level-landscape at the point x.
- **/
- double compute_value_at_a_given_point(unsigned level, double x) const;
-
- /**
- * Writing landscape into a stream. A i-th level landscape starts with a string "lambda_i". Then the discontinuity
- *points of the landscapes follows.
- * Shall those points be joined with lines, we will obtain the i-th landscape function.
- **/
- friend std::ostream& operator<<(std::ostream& out, Persistence_landscape& land);
-
- template <typename operation>
- friend Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
- const Persistence_landscape& land2);
-
- /**
- *\private A function that compute sum of two landscapes.
- **/
- friend Persistence_landscape add_two_landscapes(const Persistence_landscape& land1,
- const Persistence_landscape& land2) {
- return operation_on_pair_of_landscapes<std::plus<double> >(land1, land2);
- }
-
- /**
- *\private A function that compute difference of two landscapes.
- **/
- friend Persistence_landscape subtract_two_landscapes(const Persistence_landscape& land1,
- const Persistence_landscape& land2) {
- return operation_on_pair_of_landscapes<std::minus<double> >(land1, land2);
- }
-
- /**
- * An operator +, that compute sum of two landscapes.
- **/
- friend Persistence_landscape operator+(const Persistence_landscape& first, const Persistence_landscape& second) {
- return add_two_landscapes(first, second);
- }
-
- /**
- * An operator -, that compute difference of two landscapes.
- **/
- friend Persistence_landscape operator-(const Persistence_landscape& first, const Persistence_landscape& second) {
- return subtract_two_landscapes(first, second);
- }
-
- /**
- * An operator * that allows multiplication of a landscape by a real number.
- **/
- friend Persistence_landscape operator*(const Persistence_landscape& first, double con) {
- return first.multiply_lanscape_by_real_number_not_overwrite(con);
- }
-
- /**
- * An operator * that allows multiplication of a landscape by a real number (order of parameters swapped).
- **/
- friend Persistence_landscape operator*(double con, const Persistence_landscape& first) {
- return first.multiply_lanscape_by_real_number_not_overwrite(con);
- }
-
- /**
- * Operator +=. The second parameter is persistence landscape.
- **/
- Persistence_landscape operator+=(const Persistence_landscape& rhs) {
- *this = *this + rhs;
- return *this;
- }
-
- /**
- * Operator -=. The second parameter is a persistence landscape.
- **/
- Persistence_landscape operator-=(const Persistence_landscape& rhs) {
- *this = *this - rhs;
- return *this;
- }
-
- /**
- * Operator *=. The second parameter is a real number by which the y values of all landscape functions are multiplied.
- *The x-values remain unchanged.
- **/
- Persistence_landscape operator*=(double x) {
- *this = *this * x;
- return *this;
- }
-
- /**
- * Operator /=. The second parameter is a real number.
- **/
- Persistence_landscape operator/=(double x) {
- if (x == 0) throw("In operator /=, division by 0. Program terminated.");
- *this = *this * (1 / x);
- return *this;
- }
-
- /**
- * An operator to compare two persistence landscapes.
- **/
- bool operator==(const Persistence_landscape& rhs) const;
-
- /**
- * An operator to compare two persistence landscapes.
- **/
- bool operator!=(const Persistence_landscape& rhs) const { return !((*this) == rhs); }
-
- /**
- * Computations of maximum (y) value of landscape.
- **/
- double compute_maximum() const {
- double maxValue = 0;
- if (this->land.size()) {
- maxValue = -std::numeric_limits<int>::max();
- for (size_t i = 0; i != this->land[0].size(); ++i) {
- if (this->land[0][i].second > maxValue) maxValue = this->land[0][i].second;
- }
- }
- return maxValue;
- }
-
- /**
- *\private Computations of minimum (y) value of landscape.
- **/
- double compute_minimum() const {
- double minValue = 0;
- if (this->land.size()) {
- minValue = std::numeric_limits<int>::max();
- for (size_t i = 0; i != this->land[0].size(); ++i) {
- if (this->land[0][i].second < minValue) minValue = this->land[0][i].second;
- }
- }
- return minValue;
- }
-
- /**
- *\private Computations of a \f$L^i\f$ norm of landscape, where i is the input parameter.
- **/
- double compute_norm_of_landscape(double i) {
- Persistence_landscape l;
- if (i < std::numeric_limits<double>::max()) {
- return compute_distance_of_landscapes(*this, l, i);
- } else {
- return compute_max_norm_distance_of_landscapes(*this, l);
- }
- }
-
- /**
- * An operator to compute the value of a landscape in the level 'level' at the argument 'x'.
- **/
- double operator()(unsigned level, double x) const { return this->compute_value_at_a_given_point(level, x); }
-
- /**
- *\private Computations of \f$L^{\infty}\f$ distance between two landscapes.
- **/
- friend double compute_max_norm_distance_of_landscapes(const Persistence_landscape& first,
- const Persistence_landscape& second);
-
- /**
- *\private Computations of \f$L^{p}\f$ distance between two landscapes. p is the parameter of the procedure.
- **/
- friend double compute_distance_of_landscapes(const Persistence_landscape& first, const Persistence_landscape& second,
- double p);
-
- /**
- * Function to compute absolute value of a PL function. The representation of persistence landscapes allow to store
- *general PL-function. When computing distance between two landscapes, we compute difference between
- * them. In this case, a general PL-function with negative value can appear as a result. Then in order to compute
- *distance, we need to take its absolute value. This is the purpose of this procedure.
- **/
- Persistence_landscape abs();
-
- Persistence_landscape* new_abs();
-
- /**
- * Computes the number of landscape functions.
- **/
- size_t size() const { return this->land.size(); }
-
- /**
- * Compute maximal value of lambda-level landscape.
- **/
- double find_max(unsigned lambda) const;
-
- /**
- *\private Function to compute inner (scalar) product of two landscapes.
- **/
- friend double compute_inner_product(const Persistence_landscape& l1, const Persistence_landscape& l2);
-
- // Implementations of functions for various concepts.
-
- /**
- * The number of projections to R is defined to the number of nonzero landscape functions. I-th projection is an
- *integral of i-th landscape function over whole R.
- * This function is required by the Real_valued_topological_data concept.
- * At the moment this function is not tested, since it is quite likely to be changed in the future. Given this, when
- *using it, keep in mind that it
- * will be most likely changed in the next versions.
- **/
- double project_to_R(int number_of_function) const {
- return this->compute_integral_of_a_level_of_a_landscape((size_t)number_of_function);
- }
-
- /**
- * The function gives the number of possible projections to R. This function is required by the
- *Real_valued_topological_data concept.
- **/
- size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals; }
-
- /**
- * This function produce a vector of doubles based on a landscape. It is required in a concept
- * Vectorized_topological_data
- */
- std::vector<double> vectorize(int number_of_function) const {
- // TODO(PD) think of something smarter over here
- std::vector<double> v;
- if ((size_t)number_of_function > this->land.size()) {
- return v;
- }
- v.reserve(this->land[number_of_function].size());
- for (size_t i = 0; i != this->land[number_of_function].size(); ++i) {
- v.push_back(this->land[number_of_function][i].second);
- }
- return v;
- }
- /**
- * This function return the number of functions that allows vectorization of persistence landscape. It is required in
- *a concept Vectorized_topological_data.
- **/
- size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization; }
-
- /**
- * A function to compute averaged persistence landscape, based on vector of persistence landscapes.
- * This function is required by Topological_data_with_averages concept.
- **/
- void compute_average(const std::vector<Persistence_landscape*>& to_average) {
- bool dbg = false;
-
- if (dbg) {
- std::cerr << "to_average.size() : " << to_average.size() << std::endl;
- }
-
- std::vector<Persistence_landscape*> nextLevelMerge(to_average.size());
- for (size_t i = 0; i != to_average.size(); ++i) {
- nextLevelMerge[i] = to_average[i];
- }
- bool is_this_first_level = true; // in the loop, we will create dynamically a number of intermediate complexes. We
- // have to clean that up, but we cannot erase the initial landscapes we have
- // to average. In this case, we simply check if the nextLevelMerge are the input landscapes or the ones created in
- // that loop by using this extra variable.
-
- while (nextLevelMerge.size() != 1) {
- if (dbg) {
- std::cerr << "nextLevelMerge.size() : " << nextLevelMerge.size() << std::endl;
- }
- std::vector<Persistence_landscape*> nextNextLevelMerge;
- nextNextLevelMerge.reserve(to_average.size());
- for (size_t i = 0; i < nextLevelMerge.size(); i = i + 2) {
- if (dbg) {
- std::cerr << "i : " << i << std::endl;
- }
- Persistence_landscape* l = new Persistence_landscape;
- if (i + 1 != nextLevelMerge.size()) {
- (*l) = (*nextLevelMerge[i]) + (*nextLevelMerge[i + 1]);
- } else {
- (*l) = *nextLevelMerge[i];
- }
- nextNextLevelMerge.push_back(l);
- }
- if (dbg) {
- std::cerr << "After this iteration \n";
- getchar();
- }
-
- if (!is_this_first_level) {
- // deallocate the memory if the vector nextLevelMerge do not consist of the initial landscapes
- for (size_t i = 0; i != nextLevelMerge.size(); ++i) {
- delete nextLevelMerge[i];
- }
- }
- is_this_first_level = false;
- nextLevelMerge.swap(nextNextLevelMerge);
- }
- (*this) = (*nextLevelMerge[0]);
- (*this) *= 1 / static_cast<double>(to_average.size());
- }
-
- /**
- * A function to compute distance between persistence landscape.
- * The parameter of this function is a Persistence_landscape.
- * This function is required in Topological_data_with_distances concept.
- * For max norm distance, set power to std::numeric_limits<double>::max()
- **/
- double distance(const Persistence_landscape& second, double power = 1) const {
- if (power < std::numeric_limits<double>::max()) {
- return compute_distance_of_landscapes(*this, second, power);
- } else {
- return compute_max_norm_distance_of_landscapes(*this, second);
- }
- }
-
- /**
- * A function to compute scalar product of persistence landscapes.
- * The parameter of this function is a Persistence_landscape.
- * This function is required in Topological_data_with_scalar_product concept.
- **/
- double compute_scalar_product(const Persistence_landscape& second) const {
- return compute_inner_product((*this), second);
- }
- // end of implementation of functions needed for concepts.
-
- /**
- * This procedure returns y-range of a given level persistence landscape. If a default value is used, the y-range
- * of 0th level landscape is given (and this range contains the ranges of all other landscapes).
- **/
- std::pair<double, double> get_y_range(size_t level = 0) const {
- std::pair<double, double> result;
- if (level < this->land.size()) {
- double maxx = this->compute_maximum();
- double minn = this->compute_minimum();
- result = std::make_pair(minn, maxx);
- } else {
- result = std::make_pair(0, 0);
- }
- return result;
- }
-
- // a function used to create a gnuplot script for visualization of landscapes
- void plot(const char* filename, double xRangeBegin = std::numeric_limits<double>::max(),
- double xRangeEnd = std::numeric_limits<double>::max(),
- double yRangeBegin = std::numeric_limits<double>::max(),
- double yRangeEnd = std::numeric_limits<double>::max(), int from = std::numeric_limits<int>::max(),
- int to = std::numeric_limits<int>::max());
-
- protected:
- std::vector<std::vector<std::pair<double, double> > > land;
- size_t number_of_functions_for_vectorization;
- size_t number_of_functions_for_projections_to_reals;
-
- void construct_persistence_landscape_from_barcode(const std::vector<std::pair<double, double> >& p,
- size_t number_of_levels = std::numeric_limits<size_t>::max());
- Persistence_landscape multiply_lanscape_by_real_number_not_overwrite(double x) const;
- void multiply_lanscape_by_real_number_overwrite(double x);
- friend double compute_maximal_distance_non_symmetric(const Persistence_landscape& pl1,
- const Persistence_landscape& pl2);
-
- void set_up_numbers_of_functions_for_vectorization_and_projections_to_reals() {
- // warning, this function can be only called after filling in the intervals vector.
- this->number_of_functions_for_vectorization = this->land.size();
- this->number_of_functions_for_projections_to_reals = this->land.size();
- }
-};
-
-Persistence_landscape::Persistence_landscape(const char* filename, size_t dimension, size_t number_of_levels) {
- std::vector<std::pair<double, double> > barcode;
- if (dimension < std::numeric_limits<double>::max()) {
- barcode = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- } else {
- barcode = read_persistence_intervals_in_one_dimension_from_file(filename);
- }
- this->construct_persistence_landscape_from_barcode(barcode, number_of_levels);
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-}
-
-bool operatorEqualDbg = false;
-bool Persistence_landscape::operator==(const Persistence_landscape& rhs) const {
- if (this->land.size() != rhs.land.size()) {
- if (operatorEqualDbg) std::cerr << "1\n";
- return false;
- }
- for (size_t level = 0; level != this->land.size(); ++level) {
- if (this->land[level].size() != rhs.land[level].size()) {
- if (operatorEqualDbg) std::cerr << "this->land[level].size() : " << this->land[level].size() << "\n";
- if (operatorEqualDbg) std::cerr << "rhs.land[level].size() : " << rhs.land[level].size() << "\n";
- if (operatorEqualDbg) std::cerr << "2\n";
- return false;
- }
- for (size_t i = 0; i != this->land[level].size(); ++i) {
- if (!(almost_equal(this->land[level][i].first, rhs.land[level][i].first) &&
- almost_equal(this->land[level][i].second, rhs.land[level][i].second))) {
- if (operatorEqualDbg)
- std::cerr << "this->land[level][i] : " << this->land[level][i].first << " " << this->land[level][i].second
- << "\n";
- if (operatorEqualDbg)
- std::cerr << "rhs.land[level][i] : " << rhs.land[level][i].first << " " << rhs.land[level][i].second << "\n";
- if (operatorEqualDbg) std::cerr << "3\n";
- return false;
- }
- }
- }
- return true;
-}
-
-Persistence_landscape::Persistence_landscape(const std::vector<std::pair<double, double> >& p,
- size_t number_of_levels) {
- this->construct_persistence_landscape_from_barcode(p, number_of_levels);
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-}
-
-void Persistence_landscape::construct_persistence_landscape_from_barcode(
- const std::vector<std::pair<double, double> >& p, size_t number_of_levels) {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Persistence_landscape::Persistence_landscape( const std::vector< std::pair< double , double > >& p )"
- << std::endl;
- }
-
- // this is a general algorithm to construct persistence landscapes.
- std::vector<std::pair<double, double> > bars;
- bars.insert(bars.begin(), p.begin(), p.end());
- std::sort(bars.begin(), bars.end(), compare_points_sorting);
-
- if (dbg) {
- std::cerr << "Bars : \n";
- for (size_t i = 0; i != bars.size(); ++i) {
- std::cerr << bars[i].first << " " << bars[i].second << "\n";
- }
- getchar();
- }
-
- std::vector<std::pair<double, double> > characteristicPoints(p.size());
- for (size_t i = 0; i != bars.size(); ++i) {
- characteristicPoints[i] =
- std::make_pair((bars[i].first + bars[i].second) / 2.0, (bars[i].second - bars[i].first) / 2.0);
- }
- std::vector<std::vector<std::pair<double, double> > > Persistence_landscape;
- size_t number_of_levels_in_the_landscape = 0;
- while (!characteristicPoints.empty()) {
- if (dbg) {
- for (size_t i = 0; i != characteristicPoints.size(); ++i) {
- std::cout << "(" << characteristicPoints[i].first << " " << characteristicPoints[i].second << ")\n";
- }
- std::cin.ignore();
- }
-
- std::vector<std::pair<double, double> > lambda_n;
- lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
- lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[0]), 0));
- lambda_n.push_back(characteristicPoints[0]);
-
- if (dbg) {
- std::cerr << "1 Adding to lambda_n : (" << -std::numeric_limits<int>::max() << " " << 0 << ") , ("
- << minus_length(characteristicPoints[0]) << " " << 0 << ") , (" << characteristicPoints[0].first << " "
- << characteristicPoints[0].second << ") \n";
- }
-
- size_t i = 1;
- std::vector<std::pair<double, double> > newCharacteristicPoints;
- while (i < characteristicPoints.size()) {
- size_t p = 1;
- if ((minus_length(characteristicPoints[i]) >= minus_length(lambda_n[lambda_n.size() - 1])) &&
- (birth_plus_deaths(characteristicPoints[i]) > birth_plus_deaths(lambda_n[lambda_n.size() - 1]))) {
- if (minus_length(characteristicPoints[i]) < birth_plus_deaths(lambda_n[lambda_n.size() - 1])) {
- std::pair<double, double> point = std::make_pair(
- (minus_length(characteristicPoints[i]) + birth_plus_deaths(lambda_n[lambda_n.size() - 1])) / 2,
- (birth_plus_deaths(lambda_n[lambda_n.size() - 1]) - minus_length(characteristicPoints[i])) / 2);
- lambda_n.push_back(point);
- if (dbg) {
- std::cerr << "2 Adding to lambda_n : (" << point.first << " " << point.second << ")\n";
- }
-
- if (dbg) {
- std::cerr << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
- << characteristicPoints[i + p].second << "\n";
- std::cerr << "point : " << point.first << " " << point.second << "\n";
- getchar();
- }
-
- while ((i + p < characteristicPoints.size()) &&
- (almost_equal(minus_length(point), minus_length(characteristicPoints[i + p]))) &&
- (birth_plus_deaths(point) <= birth_plus_deaths(characteristicPoints[i + p]))) {
- newCharacteristicPoints.push_back(characteristicPoints[i + p]);
- if (dbg) {
- std::cerr << "3.5 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
- << characteristicPoints[i + p].second << ")\n";
- getchar();
- }
- ++p;
- }
-
- newCharacteristicPoints.push_back(point);
- if (dbg) {
- std::cerr << "4 Adding to newCharacteristicPoints : (" << point.first << " " << point.second << ")\n";
- }
-
- while ((i + p < characteristicPoints.size()) &&
- (minus_length(point) <= minus_length(characteristicPoints[i + p])) &&
- (birth_plus_deaths(point) >= birth_plus_deaths(characteristicPoints[i + p]))) {
- newCharacteristicPoints.push_back(characteristicPoints[i + p]);
- if (dbg) {
- std::cerr << "characteristicPoints[i+p] : " << characteristicPoints[i + p].first << " "
- << characteristicPoints[i + p].second << "\n";
- std::cerr << "point : " << point.first << " " << point.second << "\n";
- std::cerr << "characteristicPoints[i+p] birth and death : " << minus_length(characteristicPoints[i + p])
- << " , " << birth_plus_deaths(characteristicPoints[i + p]) << "\n";
- std::cerr << "point birth and death : " << minus_length(point) << " , " << birth_plus_deaths(point)
- << "\n";
-
- std::cerr << "3 Adding to newCharacteristicPoints : (" << characteristicPoints[i + p].first << " "
- << characteristicPoints[i + p].second << ")\n";
- getchar();
- }
- ++p;
- }
-
- } else {
- lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
- lambda_n.push_back(std::make_pair(minus_length(characteristicPoints[i]), 0));
- if (dbg) {
- std::cerr << "5 Adding to lambda_n : (" << birth_plus_deaths(lambda_n[lambda_n.size() - 1]) << " " << 0
- << ")\n";
- std::cerr << "5 Adding to lambda_n : (" << minus_length(characteristicPoints[i]) << " " << 0 << ")\n";
- }
- }
- lambda_n.push_back(characteristicPoints[i]);
- if (dbg) {
- std::cerr << "6 Adding to lambda_n : (" << characteristicPoints[i].first << " "
- << characteristicPoints[i].second << ")\n";
- }
- } else {
- newCharacteristicPoints.push_back(characteristicPoints[i]);
- if (dbg) {
- std::cerr << "7 Adding to newCharacteristicPoints : (" << characteristicPoints[i].first << " "
- << characteristicPoints[i].second << ")\n";
- }
- }
- i = i + p;
- }
- lambda_n.push_back(std::make_pair(birth_plus_deaths(lambda_n[lambda_n.size() - 1]), 0));
- lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
-
- characteristicPoints = newCharacteristicPoints;
-
- lambda_n.erase(std::unique(lambda_n.begin(), lambda_n.end()), lambda_n.end());
- this->land.push_back(lambda_n);
-
- ++number_of_levels_in_the_landscape;
- if (number_of_levels == number_of_levels_in_the_landscape) {
- break;
- }
- }
-}
-
-// this function find maximum of lambda_n
-double Persistence_landscape::find_max(unsigned lambda) const {
- if (this->land.size() < lambda) return 0;
- double maximum = -std::numeric_limits<int>::max();
- for (size_t i = 0; i != this->land[lambda].size(); ++i) {
- if (this->land[lambda][i].second > maximum) maximum = this->land[lambda][i].second;
- }
- return maximum;
-}
-
-double Persistence_landscape::compute_integral_of_landscape() const {
- double result = 0;
- for (size_t i = 0; i != this->land.size(); ++i) {
- for (size_t nr = 2; nr != this->land[i].size() - 1; ++nr) {
- // it suffices to compute every planar integral and then sum them up for each lambda_n
- result += 0.5 * (this->land[i][nr].first - this->land[i][nr - 1].first) *
- (this->land[i][nr].second + this->land[i][nr - 1].second);
- }
- }
- return result;
-}
-
-double Persistence_landscape::compute_integral_of_a_level_of_a_landscape(size_t level) const {
- double result = 0;
- if (level >= this->land.size()) {
- // this landscape function is constantly equal 0, so is the integral.
- return result;
- }
- // also negative landscapes are assumed to be zero.
- if (level < 0) return 0;
-
- for (size_t nr = 2; nr != this->land[level].size() - 1; ++nr) {
- // it suffices to compute every planar integral and then sum them up for each lambda_n
- result += 0.5 * (this->land[level][nr].first - this->land[level][nr - 1].first) *
- (this->land[level][nr].second + this->land[level][nr - 1].second);
- }
-
- return result;
-}
-
-double Persistence_landscape::compute_integral_of_landscape(double p) const {
- bool dbg = false;
- double result = 0;
- for (size_t i = 0; i != this->land.size(); ++i) {
- for (size_t nr = 2; nr != this->land[i].size() - 1; ++nr) {
- if (dbg) std::cout << "nr : " << nr << "\n";
- // In this interval, the landscape has a form f(x) = ax+b. We want to compute integral of (ax+b)^p = 1/a *
- // (ax+b)^{p+1}/(p+1)
- std::pair<double, double> coef = compute_parameters_of_a_line(this->land[i][nr], this->land[i][nr - 1]);
- double a = coef.first;
- double b = coef.second;
-
- if (dbg)
- std::cout << "(" << this->land[i][nr].first << "," << this->land[i][nr].second << ") , "
- << this->land[i][nr - 1].first << "," << this->land[i][nr].second << ")" << std::endl;
- if (this->land[i][nr].first == this->land[i][nr - 1].first) continue;
- if (a != 0) {
- result += 1 / (a * (p + 1)) *
- (pow((a * this->land[i][nr].first + b), p + 1) - pow((a * this->land[i][nr - 1].first + b), p + 1));
- } else {
- result += (this->land[i][nr].first - this->land[i][nr - 1].first) * (pow(this->land[i][nr].second, p));
- }
- if (dbg) {
- std::cout << "a : " << a << " , b : " << b << std::endl;
- std::cout << "result : " << result << std::endl;
- }
- }
- }
- return result;
-}
-
-// this is O(log(n)) algorithm, where n is number of points in this->land.
-double Persistence_landscape::compute_value_at_a_given_point(unsigned level, double x) const {
- bool compute_value_at_a_given_pointDbg = false;
- // in such a case lambda_level = 0.
- if (level >= this->land.size()) return 0;
-
- // we know that the points in this->land[level] are ordered according to x coordinate. Therefore, we can find the
- // point by using bisection:
- unsigned coordBegin = 1;
- unsigned coordEnd = this->land[level].size() - 2;
-
- if (compute_value_at_a_given_pointDbg) {
- std::cerr << "Here \n";
- std::cerr << "x : " << x << "\n";
- std::cerr << "this->land[level][coordBegin].first : " << this->land[level][coordBegin].first << "\n";
- std::cerr << "this->land[level][coordEnd].first : " << this->land[level][coordEnd].first << "\n";
- }
-
- // in this case x is outside the support of the landscape, therefore the value of the landscape is 0.
- if (x <= this->land[level][coordBegin].first) return 0;
- if (x >= this->land[level][coordEnd].first) return 0;
-
- if (compute_value_at_a_given_pointDbg) std::cerr << "Entering to the while loop \n";
-
- while (coordBegin + 1 != coordEnd) {
- if (compute_value_at_a_given_pointDbg) {
- std::cerr << "coordBegin : " << coordBegin << "\n";
- std::cerr << "coordEnd : " << coordEnd << "\n";
- std::cerr << "this->land[level][coordBegin].first : " << this->land[level][coordBegin].first << "\n";
- std::cerr << "this->land[level][coordEnd].first : " << this->land[level][coordEnd].first << "\n";
- }
-
- unsigned newCord = (unsigned)floor((coordEnd + coordBegin) / 2.0);
-
- if (compute_value_at_a_given_pointDbg) {
- std::cerr << "newCord : " << newCord << "\n";
- std::cerr << "this->land[level][newCord].first : " << this->land[level][newCord].first << "\n";
- std::cin.ignore();
- }
-
- if (this->land[level][newCord].first <= x) {
- coordBegin = newCord;
- if (this->land[level][newCord].first == x) return this->land[level][newCord].second;
- } else {
- coordEnd = newCord;
- }
- }
-
- if (compute_value_at_a_given_pointDbg) {
- std::cout << "x : " << x << " is between : " << this->land[level][coordBegin].first << " a "
- << this->land[level][coordEnd].first << "\n";
- std::cout << "the y coords are : " << this->land[level][coordBegin].second << " a "
- << this->land[level][coordEnd].second << "\n";
- std::cerr << "coordBegin : " << coordBegin << "\n";
- std::cerr << "coordEnd : " << coordEnd << "\n";
- std::cin.ignore();
- }
- return function_value(this->land[level][coordBegin], this->land[level][coordEnd], x);
-}
-
-std::ostream& operator<<(std::ostream& out, Persistence_landscape& land) {
- for (size_t level = 0; level != land.land.size(); ++level) {
- out << "Lambda_" << level << ":" << std::endl;
- for (size_t i = 0; i != land.land[level].size(); ++i) {
- if (land.land[level][i].first == -std::numeric_limits<int>::max()) {
- out << "-inf";
- } else {
- if (land.land[level][i].first == std::numeric_limits<int>::max()) {
- out << "+inf";
- } else {
- out << land.land[level][i].first;
- }
- }
- out << " , " << land.land[level][i].second << std::endl;
- }
- }
- return out;
-}
-
-void Persistence_landscape::multiply_lanscape_by_real_number_overwrite(double x) {
- for (size_t dim = 0; dim != this->land.size(); ++dim) {
- for (size_t i = 0; i != this->land[dim].size(); ++i) {
- this->land[dim][i].second *= x;
- }
- }
-}
-
-bool AbsDbg = false;
-Persistence_landscape Persistence_landscape::abs() {
- Persistence_landscape result;
- for (size_t level = 0; level != this->land.size(); ++level) {
- if (AbsDbg) {
- std::cout << "level: " << level << std::endl;
- }
- std::vector<std::pair<double, double> > lambda_n;
- lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
- for (size_t i = 1; i != this->land[level].size(); ++i) {
- if (AbsDbg) {
- std::cout << "this->land[" << level << "][" << i << "] : " << this->land[level][i].first << " "
- << this->land[level][i].second << std::endl;
- }
- // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
- // add one landscape point t o result
- if ((this->land[level][i - 1].second) * (this->land[level][i].second) < 0) {
- double zero =
- find_zero_of_a_line_segment_between_those_two_points(this->land[level][i - 1], this->land[level][i]);
-
- lambda_n.push_back(std::make_pair(zero, 0));
- lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
- if (AbsDbg) {
- std::cout << "Adding pair : (" << zero << ",0)" << std::endl;
- std::cout << "In the same step adding pair : (" << this->land[level][i].first << ","
- << fabs(this->land[level][i].second) << ") " << std::endl;
- std::cin.ignore();
- }
- } else {
- lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
- if (AbsDbg) {
- std::cout << "Adding pair : (" << this->land[level][i].first << "," << fabs(this->land[level][i].second)
- << ") " << std::endl;
- std::cin.ignore();
- }
- }
- }
- result.land.push_back(lambda_n);
- }
- return result;
-}
-
-Persistence_landscape* Persistence_landscape::new_abs() {
- Persistence_landscape* result = new Persistence_landscape(*this);
- for (size_t level = 0; level != this->land.size(); ++level) {
- if (AbsDbg) {
- std::cout << "level: " << level << std::endl;
- }
- std::vector<std::pair<double, double> > lambda_n;
- lambda_n.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
- for (size_t i = 1; i != this->land[level].size(); ++i) {
- if (AbsDbg) {
- std::cout << "this->land[" << level << "][" << i << "] : " << this->land[level][i].first << " "
- << this->land[level][i].second << std::endl;
- }
- // if a line segment between this->land[level][i-1] and this->land[level][i] crosses the x-axis, then we have to
- // add one landscape point t o result
- if ((this->land[level][i - 1].second) * (this->land[level][i].second) < 0) {
- double zero =
- find_zero_of_a_line_segment_between_those_two_points(this->land[level][i - 1], this->land[level][i]);
-
- lambda_n.push_back(std::make_pair(zero, 0));
- lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
- if (AbsDbg) {
- std::cout << "Adding pair : (" << zero << ",0)" << std::endl;
- std::cout << "In the same step adding pair : (" << this->land[level][i].first << ","
- << fabs(this->land[level][i].second) << ") " << std::endl;
- std::cin.ignore();
- }
- } else {
- lambda_n.push_back(std::make_pair(this->land[level][i].first, fabs(this->land[level][i].second)));
- if (AbsDbg) {
- std::cout << "Adding pair : (" << this->land[level][i].first << "," << fabs(this->land[level][i].second)
- << ") " << std::endl;
- std::cin.ignore();
- }
- }
- }
- result->land.push_back(lambda_n);
- }
- return result;
-}
-
-Persistence_landscape Persistence_landscape::multiply_lanscape_by_real_number_not_overwrite(double x) const {
- std::vector<std::vector<std::pair<double, double> > > result(this->land.size());
- for (size_t dim = 0; dim != this->land.size(); ++dim) {
- std::vector<std::pair<double, double> > lambda_dim(this->land[dim].size());
- for (size_t i = 0; i != this->land[dim].size(); ++i) {
- lambda_dim[i] = std::make_pair(this->land[dim][i].first, x * this->land[dim][i].second);
- }
- result[dim] = lambda_dim;
- }
- Persistence_landscape res;
- // CHANGE
- // res.land = result;
- res.land.swap(result);
- return res;
-} // multiply_lanscape_by_real_number_overwrite
-
-void Persistence_landscape::print_to_file(const char* filename) const {
- std::ofstream write;
- write.open(filename);
- for (size_t dim = 0; dim != this->land.size(); ++dim) {
- write << "#lambda_" << dim << std::endl;
- for (size_t i = 1; i != this->land[dim].size() - 1; ++i) {
- write << this->land[dim][i].first << " " << this->land[dim][i].second << std::endl;
- }
- }
- write.close();
-}
-
-void Persistence_landscape::load_landscape_from_file(const char* filename) {
- bool dbg = false;
- // removing the current content of the persistence landscape.
- this->land.clear();
-
- // this constructor reads persistence landscape form a file. This file have to be created by this software before head
- std::ifstream in;
- in.open(filename);
- if (!in.good()) {
- std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
- throw "The persistence landscape file do not exist. The program will now terminate \n";
- }
-
- std::string line;
- std::vector<std::pair<double, double> > landscapeAtThisLevel;
-
- bool isThisAFirsLine = true;
- while (in.good()) {
- getline(in, line);
- if (!(line.length() == 0 || line[0] == '#')) {
- std::stringstream lineSS;
- lineSS << line;
- double beginn, endd;
- lineSS >> beginn;
- lineSS >> endd;
- landscapeAtThisLevel.push_back(std::make_pair(beginn, endd));
- if (dbg) {
- std::cerr << "Reading a point : " << beginn << " , " << endd << std::endl;
- }
- } else {
- if (dbg) {
- std::cout << "IGNORE LINE\n";
- getchar();
- }
- if (!isThisAFirsLine) {
- landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
- this->land.push_back(landscapeAtThisLevel);
- std::vector<std::pair<double, double> > newLevelOdLandscape;
- landscapeAtThisLevel.swap(newLevelOdLandscape);
- }
- landscapeAtThisLevel.push_back(std::make_pair(-std::numeric_limits<int>::max(), 0));
- isThisAFirsLine = false;
- }
- }
- if (landscapeAtThisLevel.size() > 1) {
- // seems that the last line of the file is not finished with the newline sign. We need to put what we have in
- // landscapeAtThisLevel to the constructed landscape.
- landscapeAtThisLevel.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
- this->land.push_back(landscapeAtThisLevel);
- }
-
- in.close();
-}
-
-template <typename T>
-Persistence_landscape operation_on_pair_of_landscapes(const Persistence_landscape& land1,
- const Persistence_landscape& land2) {
- bool operation_on_pair_of_landscapesDBG = false;
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "operation_on_pair_of_landscapes\n";
- std::cin.ignore();
- }
- Persistence_landscape result;
- std::vector<std::vector<std::pair<double, double> > > land(std::max(land1.land.size(), land2.land.size()));
- result.land = land;
- T oper;
-
- if (operation_on_pair_of_landscapesDBG) {
- for (size_t i = 0; i != std::min(land1.land.size(), land2.land.size()); ++i) {
- std::cerr << "land1.land[" << i << "].size() : " << land1.land[i].size() << std::endl;
- std::cerr << "land2.land[" << i << "].size() : " << land2.land[i].size() << std::endl;
- }
- getchar();
- }
-
- for (size_t i = 0; i != std::min(land1.land.size(), land2.land.size()); ++i) {
- std::vector<std::pair<double, double> > lambda_n;
- size_t p = 0;
- size_t q = 0;
- while ((p + 1 < land1.land[i].size()) && (q + 1 < land2.land[i].size())) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cerr << "p : " << p << "\n";
- std::cerr << "q : " << q << "\n";
- std::cerr << "land1.land.size() : " << land1.land.size() << std::endl;
- std::cerr << "land2.land.size() : " << land2.land.size() << std::endl;
- std::cerr << "land1.land[" << i << "].size() : " << land1.land[i].size() << std::endl;
- std::cerr << "land2.land[" << i << "].size() : " << land2.land[i].size() << std::endl;
- std::cout << "land1.land[i][p].first : " << land1.land[i][p].first << "\n";
- std::cout << "land2.land[i][q].first : " << land2.land[i][q].first << "\n";
- }
-
- if (land1.land[i][p].first < land2.land[i][q].first) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "first \n";
- std::cout << " function_value(land2.land[i][q-1],land2.land[i][q],land1.land[i][p].first) : "
- << function_value(land2.land[i][q - 1], land2.land[i][q], land1.land[i][p].first) << "\n";
- }
- lambda_n.push_back(
- std::make_pair(land1.land[i][p].first,
- oper(static_cast<double>(land1.land[i][p].second),
- function_value(land2.land[i][q - 1], land2.land[i][q], land1.land[i][p].first))));
- ++p;
- continue;
- }
- if (land1.land[i][p].first > land2.land[i][q].first) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "Second \n";
- std::cout << "function_value(" << land1.land[i][p - 1].first << " " << land1.land[i][p - 1].second << " ,"
- << land1.land[i][p].first << " " << land1.land[i][p].second << ", " << land2.land[i][q].first
- << " ) : " << function_value(land1.land[i][p - 1], land1.land[i][p - 1], land2.land[i][q].first)
- << "\n";
- std::cout << "oper( " << function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first) << ","
- << land2.land[i][q].second << " : "
- << oper(land2.land[i][q].second,
- function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first))
- << "\n";
- }
- lambda_n.push_back(std::make_pair(
- land2.land[i][q].first, oper(function_value(land1.land[i][p], land1.land[i][p - 1], land2.land[i][q].first),
- land2.land[i][q].second)));
- ++q;
- continue;
- }
- if (land1.land[i][p].first == land2.land[i][q].first) {
- if (operation_on_pair_of_landscapesDBG) std::cout << "Third \n";
- lambda_n.push_back(
- std::make_pair(land2.land[i][q].first, oper(land1.land[i][p].second, land2.land[i][q].second)));
- ++p;
- ++q;
- }
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "Next iteration \n";
- }
- }
- while ((p + 1 < land1.land[i].size()) && (q + 1 >= land2.land[i].size())) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "New point : " << land1.land[i][p].first
- << " oper(land1.land[i][p].second,0) : " << oper(land1.land[i][p].second, 0) << std::endl;
- }
- lambda_n.push_back(std::make_pair(land1.land[i][p].first, oper(land1.land[i][p].second, 0)));
- ++p;
- }
- while ((p + 1 >= land1.land[i].size()) && (q + 1 < land2.land[i].size())) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "New point : " << land2.land[i][q].first
- << " oper(0,land2.land[i][q].second) : " << oper(0, land2.land[i][q].second) << std::endl;
- }
- lambda_n.push_back(std::make_pair(land2.land[i][q].first, oper(0, land2.land[i][q].second)));
- ++q;
- }
- lambda_n.push_back(std::make_pair(std::numeric_limits<int>::max(), 0));
- // CHANGE
- // result.land[i] = lambda_n;
- result.land[i].swap(lambda_n);
- }
- if (land1.land.size() > std::min(land1.land.size(), land2.land.size())) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "land1.land.size() > std::min( land1.land.size() , land2.land.size() )" << std::endl;
- }
- for (size_t i = std::min(land1.land.size(), land2.land.size()); i != std::max(land1.land.size(), land2.land.size());
- ++i) {
- std::vector<std::pair<double, double> > lambda_n(land1.land[i]);
- for (size_t nr = 0; nr != land1.land[i].size(); ++nr) {
- lambda_n[nr] = std::make_pair(land1.land[i][nr].first, oper(land1.land[i][nr].second, 0));
- }
- // CHANGE
- // result.land[i] = lambda_n;
- result.land[i].swap(lambda_n);
- }
- }
- if (land2.land.size() > std::min(land1.land.size(), land2.land.size())) {
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "( land2.land.size() > std::min( land1.land.size() , land2.land.size() ) ) " << std::endl;
- }
- for (size_t i = std::min(land1.land.size(), land2.land.size()); i != std::max(land1.land.size(), land2.land.size());
- ++i) {
- std::vector<std::pair<double, double> > lambda_n(land2.land[i]);
- for (size_t nr = 0; nr != land2.land[i].size(); ++nr) {
- lambda_n[nr] = std::make_pair(land2.land[i][nr].first, oper(0, land2.land[i][nr].second));
- }
- // CHANGE
- // result.land[i] = lambda_n;
- result.land[i].swap(lambda_n);
- }
- }
- if (operation_on_pair_of_landscapesDBG) {
- std::cout << "operation_on_pair_of_landscapes END\n";
- std::cin.ignore();
- }
- return result;
-} // operation_on_pair_of_landscapes
-
-double compute_maximal_distance_non_symmetric(const Persistence_landscape& pl1, const Persistence_landscape& pl2) {
- bool dbg = false;
- if (dbg) std::cerr << " compute_maximal_distance_non_symmetric \n";
- // this distance is not symmetric. It compute ONLY distance between inflection points of pl1 and pl2.
- double maxDist = 0;
- size_t minimalNumberOfLevels = std::min(pl1.land.size(), pl2.land.size());
- for (size_t level = 0; level != minimalNumberOfLevels; ++level) {
- if (dbg) {
- std::cerr << "Level : " << level << std::endl;
- std::cerr << "PL1 : \n";
- for (size_t i = 0; i != pl1.land[level].size(); ++i) {
- std::cerr << "(" << pl1.land[level][i].first << "," << pl1.land[level][i].second << ") \n";
- }
- std::cerr << "PL2 : \n";
- for (size_t i = 0; i != pl2.land[level].size(); ++i) {
- std::cerr << "(" << pl2.land[level][i].first << "," << pl2.land[level][i].second << ") \n";
- }
- std::cin.ignore();
- }
-
- int p2Count = 0;
- // In this case, I consider points at the infinity
- for (size_t i = 1; i != pl1.land[level].size() - 1; ++i) {
- while (true) {
- if ((pl1.land[level][i].first >= pl2.land[level][p2Count].first) &&
- (pl1.land[level][i].first <= pl2.land[level][p2Count + 1].first))
- break;
- p2Count++;
- }
- double val =
- fabs(function_value(pl2.land[level][p2Count], pl2.land[level][p2Count + 1], pl1.land[level][i].first) -
- pl1.land[level][i].second);
- if (maxDist <= val) maxDist = val;
-
- if (dbg) {
- std::cerr << pl1.land[level][i].first << "in [" << pl2.land[level][p2Count].first << ","
- << pl2.land[level][p2Count + 1].first << "] \n";
- std::cerr << "pl1[level][i].second : " << pl1.land[level][i].second << std::endl;
- std::cerr << "function_value( pl2[level][p2Count] , pl2[level][p2Count+1] , pl1[level][i].first ) : "
- << function_value(pl2.land[level][p2Count], pl2.land[level][p2Count + 1], pl1.land[level][i].first)
- << std::endl;
- std::cerr << "val : " << val << std::endl;
- std::cin.ignore();
- }
- }
- }
-
- if (dbg) std::cerr << "minimalNumberOfLevels : " << minimalNumberOfLevels << std::endl;
-
- if (minimalNumberOfLevels < pl1.land.size()) {
- for (size_t level = minimalNumberOfLevels; level != pl1.land.size(); ++level) {
- for (size_t i = 0; i != pl1.land[level].size(); ++i) {
- if (dbg) std::cerr << "pl1[level][i].second : " << pl1.land[level][i].second << std::endl;
- if (maxDist < pl1.land[level][i].second) maxDist = pl1.land[level][i].second;
- }
- }
- }
- return maxDist;
-}
-
-double compute_distance_of_landscapes(const Persistence_landscape& first, const Persistence_landscape& second,
- double p) {
- bool dbg = false;
- // This is what we want to compute: (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p). We will do it one step at a
- // time:
-
- // first-second :
- Persistence_landscape lan = first - second;
-
- //| first-second |:
- lan = lan.abs();
-
- if (dbg) {
- std::cerr << "Abs of difference ; " << lan << std::endl;
- getchar();
- }
-
- if (p < std::numeric_limits<double>::max()) {
- // \int_{- \infty}^{+\infty}| first-second |^p
- double result;
- if (p != 1) {
- if (dbg) std::cerr << "Power != 1, compute integral to the power p\n";
- result = lan.compute_integral_of_landscape(p);
- } else {
- if (dbg) std::cerr << "Power = 1, compute integral \n";
- result = lan.compute_integral_of_landscape();
- }
- // (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p)
- return pow(result, 1.0 / p);
- } else {
- // p == infty
- if (dbg) std::cerr << "Power = infty, compute maximum \n";
- return lan.compute_maximum();
- }
-}
-
-double compute_max_norm_distance_of_landscapes(const Persistence_landscape& first,
- const Persistence_landscape& second) {
- return std::max(compute_maximal_distance_non_symmetric(first, second),
- compute_maximal_distance_non_symmetric(second, first));
-}
-
-bool comparePairsForMerging(std::pair<double, unsigned> first, std::pair<double, unsigned> second) {
- return (first.first < second.first);
-}
-
-double compute_inner_product(const Persistence_landscape& l1, const Persistence_landscape& l2) {
- bool dbg = false;
- double result = 0;
-
- for (size_t level = 0; level != std::min(l1.size(), l2.size()); ++level) {
- if (dbg) {
- std::cerr << "Computing inner product for a level : " << level << std::endl;
- getchar();
- }
- auto&& l1_land_level = l1.land[level];
- auto&& l2_land_level = l2.land[level];
-
- if (l1_land_level.size() * l2_land_level.size() == 0) continue;
-
- // endpoints of the interval on which we will compute the inner product of two locally linear functions:
- double x1 = -std::numeric_limits<int>::max();
- double x2;
- if (l1_land_level[1].first < l2_land_level[1].first) {
- x2 = l1_land_level[1].first;
- } else {
- x2 = l2_land_level[1].first;
- }
-
- // iterators for the landscapes l1 and l2
- size_t l1It = 0;
- size_t l2It = 0;
-
- while ((l1It < l1_land_level.size() - 1) && (l2It < l2_land_level.size() - 1)) {
- // compute the value of a inner product on a interval [x1,x2]
-
- double a, b, c, d;
-
- if (l1_land_level[l1It + 1].first != l1_land_level[l1It].first) {
- a = (l1_land_level[l1It + 1].second - l1_land_level[l1It].second) /
- (l1_land_level[l1It + 1].first - l1_land_level[l1It].first);
- } else {
- a = 0;
- }
- b = l1_land_level[l1It].second - a * l1_land_level[l1It].first;
- if (l2_land_level[l2It + 1].first != l2_land_level[l2It].first) {
- c = (l2_land_level[l2It + 1].second - l2_land_level[l2It].second) /
- (l2_land_level[l2It + 1].first - l2_land_level[l2It].first);
- } else {
- c = 0;
- }
- d = l2_land_level[l2It].second - c * l2_land_level[l2It].first;
-
- double contributionFromThisPart = (a * c * x2 * x2 * x2 / 3 + (a * d + b * c) * x2 * x2 / 2 + b * d * x2) -
- (a * c * x1 * x1 * x1 / 3 + (a * d + b * c) * x1 * x1 / 2 + b * d * x1);
-
- result += contributionFromThisPart;
-
- if (dbg) {
- std::cerr << "[l1_land_level[l1It].first,l1_land_level[l1It+1].first] : " << l1_land_level[l1It].first
- << " , " << l1_land_level[l1It + 1].first << std::endl;
- std::cerr << "[l2_land_level[l2It].first,l2_land_level[l2It+1].first] : " << l2_land_level[l2It].first
- << " , " << l2_land_level[l2It + 1].first << std::endl;
- std::cerr << "a : " << a << ", b : " << b << " , c: " << c << ", d : " << d << std::endl;
- std::cerr << "x1 : " << x1 << " , x2 : " << x2 << std::endl;
- std::cerr << "contributionFromThisPart : " << contributionFromThisPart << std::endl;
- std::cerr << "result : " << result << std::endl;
- getchar();
- }
-
- // we have two intervals in which functions are constant:
- // [l1_land_level[l1It].first , l1_land_level[l1It+1].first]
- // and
- // [l2_land_level[l2It].first , l2_land_level[l2It+1].first]
- // We also have an interval [x1,x2]. Since the intervals in the landscapes cover the whole R, then it is clear
- // that x2
- // is either l1_land_level[l1It+1].first of l2_land_level[l2It+1].first or both. Lets test it.
- if (x2 == l1_land_level[l1It + 1].first) {
- if (x2 == l2_land_level[l2It + 1].first) {
- // in this case, we increment both:
- ++l2It;
- if (dbg) {
- std::cerr << "Incrementing both \n";
- }
- } else {
- if (dbg) {
- std::cerr << "Incrementing first \n";
- }
- }
- ++l1It;
- } else {
- // in this case we increment l2It
- ++l2It;
- if (dbg) {
- std::cerr << "Incrementing second \n";
- }
- }
-
- if ( l1It + 1 >= l1_land_level.size() )break;
- if ( l2It + 1 >= l2_land_level.size() )break;
-
- // Now, we shift x1 and x2:
- x1 = x2;
- if (l1_land_level[l1It + 1].first < l2_land_level[l2It + 1].first) {
- x2 = l1_land_level[l1It + 1].first;
- } else {
- x2 = l2_land_level[l2It + 1].first;
- }
- }
- }
- return result;
-}
-
-void Persistence_landscape::plot(const char* filename, double xRangeBegin, double xRangeEnd, double yRangeBegin,
- double yRangeEnd, int from, int to) {
- // this program create a gnuplot script file that allows to plot persistence diagram.
- std::ofstream out;
-
- std::ostringstream gnuplot_script;
- gnuplot_script << filename << "_GnuplotScript";
- out.open(gnuplot_script.str().c_str());
-
- if ((xRangeBegin != std::numeric_limits<double>::max()) || (xRangeEnd != std::numeric_limits<double>::max()) ||
- (yRangeBegin != std::numeric_limits<double>::max()) || (yRangeEnd != std::numeric_limits<double>::max())) {
- out << "set xrange [" << xRangeBegin << " : " << xRangeEnd << "]" << std::endl;
- out << "set yrange [" << yRangeBegin << " : " << yRangeEnd << "]" << std::endl;
- }
-
- if (from == std::numeric_limits<int>::max()) {
- from = 0;
- }
- if (to == std::numeric_limits<int>::max()) {
- to = this->land.size();
- }
-
- out << "plot ";
- for (size_t lambda = std::min((size_t)from, this->land.size()); lambda != std::min((size_t)to, this->land.size());
- ++lambda) {
- // out << " '-' using 1:2 title 'l" << lambda << "' with lp";
- out << " '-' using 1:2 notitle with lp";
- if (lambda + 1 != std::min((size_t)to, this->land.size())) {
- out << ", \\";
- }
- out << std::endl;
- }
-
- for (size_t lambda = std::min((size_t)from, this->land.size()); lambda != std::min((size_t)to, this->land.size());
- ++lambda) {
- for (size_t i = 1; i != this->land[lambda].size() - 1; ++i) {
- out << this->land[lambda][i].first << " " << this->land[lambda][i].second << std::endl;
- }
- out << "EOF" << std::endl;
- }
- std::cout << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
- << gnuplot_script.str().c_str() << "\'\"" << std::endl;
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_LANDSCAPE_H_
diff --git a/include/gudhi/Persistence_landscape_on_grid.h b/include/gudhi/Persistence_landscape_on_grid.h
deleted file mode 100644
index fd8a181c..00000000
--- a/include/gudhi/Persistence_landscape_on_grid.h
+++ /dev/null
@@ -1,1348 +0,0 @@
-/** This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#ifndef PERSISTENCE_LANDSCAPE_ON_GRID_H_
-#define PERSISTENCE_LANDSCAPE_ON_GRID_H_
-
-// gudhi include
-#include <gudhi/read_persistence_from_file.h>
-#include <gudhi/common_persistence_representations.h>
-
-// standard include
-#include <iostream>
-#include <vector>
-#include <limits>
-#include <fstream>
-#include <sstream>
-#include <algorithm>
-#include <cmath>
-#include <functional>
-#include <utility>
-#include <string>
-#include <cstdint>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-// pre declaration
-class Persistence_landscape_on_grid;
-template <typename operation>
-Persistence_landscape_on_grid operation_on_pair_of_landscapes_on_grid(const Persistence_landscape_on_grid& land1,
- const Persistence_landscape_on_grid& land2);
-
-/**
- * \class Persistence_landscape_on_grid Persistence_landscape_on_grid.h gudhi/Persistence_landscape_on_grid.h
- * \brief A class implementing persistence landscapes by approximating them on a collection of grid points.
- *
- * \ingroup Persistence_representations
- *
- * \details
- * Persistence landscapes on grid allows vectorization, computations of distances, computations of projections to Real,
- * computations of averages and scalar products. Therefore they implement suitable interfaces.
- * It implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
- * Real_valued_topological_data, Topological_data_with_averages, Topological_data_with_scalar_product
- *
- * Note that at the moment, due to rounding errors during the construction of persistence landscapes on a grid,
- * elements which are different by 0.000005 are considered the same. If the scale in your persistence diagrams
- * is comparable to this value, please rescale them before use this code.
-**/
-
-// this class implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
-// Real_valued_topological_data, Topological_data_with_averages, Topological_data_with_scalar_product
-class Persistence_landscape_on_grid {
- public:
- /**
- * Default constructor.
- **/
- Persistence_landscape_on_grid() {
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
- this->grid_min = this->grid_max = 0;
- }
-
- /**
- * Constructor that takes as an input a vector of birth-death pairs.
- **/
- Persistence_landscape_on_grid(const std::vector<std::pair<double, double> >& p, double grid_min_, double grid_max_,
- size_t number_of_points_);
-
- /**
- * Constructor that takes as an input a vector of birth-death pairs, parameters of the grid and number of
- *landscape function to be created.
- **/
- Persistence_landscape_on_grid(const std::vector<std::pair<double, double> >& p, double grid_min_, double grid_max_,
- size_t number_of_points_, unsigned number_of_levels_of_landscape);
-
- /**
- * Constructor that reads persistence intervals from file and creates persistence landscape. The format of the
- *input file is the following: in each line we put birth-death pair. Last line is assumed
- * to be empty. Even if the points within a line are not ordered, they will be ordered while the input is read.
- *The additional parameters of this procedure are: ranges of grid, resolution of a grid
- * number of landscape functions to be created and the dimension of intervals that are need to be read from a file
- *(in case of Gudhi format files).
- **/
- Persistence_landscape_on_grid(const char* filename, double grid_min_, double grid_max_, size_t number_of_points_,
- unsigned number_of_levels_of_landscape,
- uint16_t dimension_ = std::numeric_limits<uint16_t>::max());
-
- /**
- * Constructor that reads persistence intervals from file and creates persistence landscape. The format of the
- *input file is the following: in each line we put birth-death pair. Last line is assumed
- * to be empty. Even if the points within a line are not ordered, they will be ordered while the input is read. The
- *additional parameters of this procedure are: ranges of grid, resolution of a grid
- * and the dimension of intervals that are need to be read from a file (in case of Gudhi format files).
- **/
- Persistence_landscape_on_grid(const char* filename, double grid_min_, double grid_max_, size_t number_of_points_,
- uint16_t dimension_ = std::numeric_limits<uint16_t>::max());
-
- /**
- * Constructor that reads persistence intervals from file and creates persistence landscape. The format of the
- *input file is the following: in each line we put birth-death pair. Last line is assumed
- * to be empty. Even if the points within a line are not ordered, they will be ordered while the input is read.
- *The additional parameter is the resolution of a grid and the number of landscape
- * functions to be created. The remaining parameters are calculated based on data.
- **/
- Persistence_landscape_on_grid(const char* filename, size_t number_of_points, unsigned number_of_levels_of_landscape,
- uint16_t dimension = std::numeric_limits<uint16_t>::max());
-
- /**
- * Constructor that reads persistence intervals from file and creates persistence landscape. The format of the input
- *file is the following: in each line we put birth-death pair. Last line is assumed
- * to be empty. Even if the points within a line are not ordered, they will be ordered while the input is read. The
- *additional parameter is the resolution of a grid. The last parameter is the dimension
- * of a persistence to read from the file. If your file contains only persistence pair in a single dimension, please
- *set it up to std::numeric_limits<unsigned>::max().
- * The remaining parameters are calculated based on data.
- **/
- Persistence_landscape_on_grid(const char* filename, size_t number_of_points,
- uint16_t dimension = std::numeric_limits<uint16_t>::max());
-
- /**
- * This procedure loads a landscape from file. It erase all the data that was previously stored in this landscape.
- **/
- void load_landscape_from_file(const char* filename);
-
- /**
- * The procedure stores a landscape to a file. The file can be later used by a procedure load_landscape_from_file.
- **/
- void print_to_file(const char* filename) const;
-
- /**
- * This function compute integral of the landscape (defined formally as sum of integrals on R of all landscape
- *functions)
- **/
- double compute_integral_of_landscape() const {
- size_t maximal_level = this->number_of_nonzero_levels();
- double result = 0;
- for (size_t i = 0; i != maximal_level; ++i) {
- result += this->compute_integral_of_landscape(i);
- }
- return result;
- }
-
- /**
- * This function compute integral of the 'level'-level of a landscape.
- **/
- double compute_integral_of_landscape(size_t level) const {
- bool dbg = false;
- double result = 0;
- double dx = (this->grid_max - this->grid_min) / static_cast<double>(this->values_of_landscapes.size() - 1);
-
- if (dbg) {
- std::cerr << "this->grid_max : " << this->grid_max << std::endl;
- std::cerr << "this->grid_min : " << this->grid_min << std::endl;
- std::cerr << "this->values_of_landscapes.size() : " << this->values_of_landscapes.size() << std::endl;
- getchar();
- }
-
- double previous_x = this->grid_min - dx;
- double previous_y = 0;
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- double current_x = previous_x + dx;
- double current_y = 0;
- if (this->values_of_landscapes[i].size() > level) current_y = this->values_of_landscapes[i][level];
-
- if (dbg) {
- std::cerr << "this->values_of_landscapes[i].size() : " << this->values_of_landscapes[i].size()
- << " , level : " << level << std::endl;
- if (this->values_of_landscapes[i].size() > level)
- std::cerr << "this->values_of_landscapes[i][level] : " << this->values_of_landscapes[i][level] << std::endl;
- std::cerr << "previous_y : " << previous_y << std::endl;
- std::cerr << "current_y : " << current_y << std::endl;
- std::cerr << "dx : " << dx << std::endl;
- std::cerr << "0.5*dx*( previous_y + current_y ); " << 0.5 * dx * (previous_y + current_y) << std::endl;
- }
-
- result += 0.5 * dx * (previous_y + current_y);
- previous_x = current_x;
- previous_y = current_y;
- }
- return result;
- }
-
- /**
- * This function compute integral of the landscape p-th power of a landscape (defined formally as sum of integrals on
- *R of p-th powers of all landscape functions)
- **/
- double compute_integral_of_landscape(double p) const {
- size_t maximal_level = this->number_of_nonzero_levels();
- double result = 0;
- for (size_t i = 0; i != maximal_level; ++i) {
- result += this->compute_integral_of_landscape(p, i);
- }
- return result;
- }
-
- /**
- * This function compute integral of the landscape p-th power of a level of a landscape (defined formally as sum
- *of integrals on R of p-th powers of all landscape functions)
- **/
- double compute_integral_of_landscape(double p, size_t level) const {
- bool dbg = false;
-
- double result = 0;
- double dx = (this->grid_max - this->grid_min) / static_cast<double>(this->values_of_landscapes.size() - 1);
- double previous_x = this->grid_min;
- double previous_y = 0;
- if (this->values_of_landscapes[0].size() > level) previous_y = this->values_of_landscapes[0][level];
-
- if (dbg) {
- std::cerr << "dx : " << dx << std::endl;
- std::cerr << "previous_x : " << previous_x << std::endl;
- std::cerr << "previous_y : " << previous_y << std::endl;
- std::cerr << "power : " << p << std::endl;
- getchar();
- }
-
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- double current_x = previous_x + dx;
- double current_y = 0;
- if (this->values_of_landscapes[i].size() > level) current_y = this->values_of_landscapes[i][level];
-
- if (dbg) std::cerr << "current_y : " << current_y << std::endl;
-
- if (current_y == previous_y) continue;
-
- std::pair<double, double> coef =
- compute_parameters_of_a_line(std::make_pair(previous_x, previous_y), std::make_pair(current_x, current_y));
- double a = coef.first;
- double b = coef.second;
-
- if (dbg) {
- std::cerr << "A line passing through points : (" << previous_x << "," << previous_y << ") and (" << current_x
- << "," << current_y << ") is : " << a << "x+" << b << std::endl;
- }
-
- // In this interval, the landscape has a form f(x) = ax+b. We want to compute integral of (ax+b)^p = 1/a *
- // (ax+b)^{p+1}/(p+1)
- double value_to_add = 0;
- if (a != 0) {
- value_to_add = 1 / (a * (p + 1)) * (pow((a * current_x + b), p + 1) - pow((a * previous_x + b), p + 1));
- } else {
- value_to_add = (current_x - previous_x) * (pow(b, p));
- }
- result += value_to_add;
- if (dbg) {
- std::cerr << "Increasing result by : " << value_to_add << std::endl;
- std::cerr << "result : " << result << std::endl;
- getchar();
- }
- previous_x = current_x;
- previous_y = current_y;
- }
- if (dbg) std::cerr << "The total result is : " << result << std::endl;
- return result;
- }
-
- /**
-* Writing landscape into a stream. A i-th level landscape starts with a string "lambda_i". Then the discontinuity points
-*of the landscapes follows.
-* Shall those points be joined with lines, we will obtain the i-th landscape function.
-**/
- friend std::ostream& operator<<(std::ostream& out, const Persistence_landscape_on_grid& land) {
- double dx = (land.grid_max - land.grid_min) / static_cast<double>(land.values_of_landscapes.size() - 1);
- double x = land.grid_min;
- for (size_t i = 0; i != land.values_of_landscapes.size(); ++i) {
- out << x << " : ";
- for (size_t j = 0; j != land.values_of_landscapes[i].size(); ++j) {
- out << land.values_of_landscapes[i][j] << " ";
- }
- out << std::endl;
- x += dx;
- }
- return out;
- }
-
- template <typename oper>
- friend Persistence_landscape_on_grid operation_on_pair_of_landscapes_on_grid(
- const Persistence_landscape_on_grid& land1, const Persistence_landscape_on_grid& land2);
-
- /**
- * A function that computes the value of a landscape at a given point. The parameters of the function are: unsigned
- *level and double x.
- * The procedure will compute the value of the level-landscape at the point x.
- **/
- double compute_value_at_a_given_point(unsigned level, double x) const {
- bool dbg = false;
- if ((x < this->grid_min) || (x > this->grid_max)) return 0;
-
- // find a position of a vector closest to x:
- double dx = (this->grid_max - this->grid_min) / static_cast<double>(this->values_of_landscapes.size() - 1);
- size_t position = size_t((x - this->grid_min) / dx);
-
- if (dbg) {
- std::cerr << "This is a procedure compute_value_at_a_given_point \n";
- std::cerr << "level : " << level << std::endl;
- std::cerr << "x : " << x << std::endl;
- std::cerr << "position : " << position << std::endl;
- }
- // check if we are not exactly in the grid point:
- if (almost_equal(position * dx + this->grid_min, x)) {
- if (this->values_of_landscapes[position].size() < level) {
- return this->values_of_landscapes[position][level];
- } else {
- return 0;
- }
- }
- // in the other case, approximate with a line:
- std::pair<double, double> line;
- if ((this->values_of_landscapes[position].size() > level) &&
- (this->values_of_landscapes[position + 1].size() > level)) {
- line = compute_parameters_of_a_line(
- std::make_pair(position * dx + this->grid_min, this->values_of_landscapes[position][level]),
- std::make_pair((position + 1) * dx + this->grid_min, this->values_of_landscapes[position + 1][level]));
- } else {
- if ((this->values_of_landscapes[position].size() > level) ||
- (this->values_of_landscapes[position + 1].size() > level)) {
- if ((this->values_of_landscapes[position].size() > level)) {
- line = compute_parameters_of_a_line(
- std::make_pair(position * dx + this->grid_min, this->values_of_landscapes[position][level]),
- std::make_pair((position + 1) * dx + this->grid_min, 0));
- } else {
- line = compute_parameters_of_a_line(
- std::make_pair(position * dx + this->grid_min, 0),
- std::make_pair((position + 1) * dx + this->grid_min, this->values_of_landscapes[position + 1][level]));
- }
- } else {
- return 0;
- }
- }
- // compute the value of the linear function parametrized by line on a point x:
- return line.first * x + line.second;
- }
-
- public:
- /**
- *\private A function that compute sum of two landscapes.
- **/
- friend Persistence_landscape_on_grid add_two_landscapes(const Persistence_landscape_on_grid& land1,
- const Persistence_landscape_on_grid& land2) {
- return operation_on_pair_of_landscapes_on_grid<std::plus<double> >(land1, land2);
- }
-
- /**
- *\private A function that compute difference of two landscapes.
- **/
- friend Persistence_landscape_on_grid subtract_two_landscapes(const Persistence_landscape_on_grid& land1,
- const Persistence_landscape_on_grid& land2) {
- return operation_on_pair_of_landscapes_on_grid<std::minus<double> >(land1, land2);
- }
-
- /**
- * An operator +, that compute sum of two landscapes.
- **/
- friend Persistence_landscape_on_grid operator+(const Persistence_landscape_on_grid& first,
- const Persistence_landscape_on_grid& second) {
- return add_two_landscapes(first, second);
- }
-
- /**
- * An operator -, that compute difference of two landscapes.
- **/
- friend Persistence_landscape_on_grid operator-(const Persistence_landscape_on_grid& first,
- const Persistence_landscape_on_grid& second) {
- return subtract_two_landscapes(first, second);
- }
-
- /**
- * An operator * that allows multiplication of a landscape by a real number.
- **/
- friend Persistence_landscape_on_grid operator*(const Persistence_landscape_on_grid& first, double con) {
- return first.multiply_lanscape_by_real_number_not_overwrite(con);
- }
-
- /**
- * An operator * that allows multiplication of a landscape by a real number (order of parameters swapped).
- **/
- friend Persistence_landscape_on_grid operator*(double con, const Persistence_landscape_on_grid& first) {
- return first.multiply_lanscape_by_real_number_not_overwrite(con);
- }
-
- friend bool check_if_defined_on_the_same_domain(const Persistence_landscape_on_grid& land1,
- const Persistence_landscape_on_grid& land2) {
- if (land1.values_of_landscapes.size() != land2.values_of_landscapes.size()) return false;
- if (land1.grid_min != land2.grid_min) return false;
- if (land1.grid_max != land2.grid_max) return false;
- return true;
- }
-
- /**
- * Operator +=. The second parameter is persistence landscape.
- **/
- Persistence_landscape_on_grid operator+=(const Persistence_landscape_on_grid& rhs) {
- *this = *this + rhs;
- return *this;
- }
-
- /**
- * Operator -=. The second parameter is persistence landscape.
- **/
- Persistence_landscape_on_grid operator-=(const Persistence_landscape_on_grid& rhs) {
- *this = *this - rhs;
- return *this;
- }
-
- /**
- * Operator *=. The second parameter is a real number by which the y values of all landscape functions are multiplied.
- *The x-values remain unchanged.
- **/
- Persistence_landscape_on_grid operator*=(double x) {
- *this = *this * x;
- return *this;
- }
-
- /**
- * Operator /=. The second parameter is a real number.
- **/
- Persistence_landscape_on_grid operator/=(double x) {
- if (x == 0) throw("In operator /=, division by 0. Program terminated.");
- *this = *this * (1 / x);
- return *this;
- }
-
- /**
- * An operator to compare two persistence landscapes.
- **/
- bool operator==(const Persistence_landscape_on_grid& rhs) const {
- bool dbg = true;
- if (this->values_of_landscapes.size() != rhs.values_of_landscapes.size()) {
- if (dbg) std::cerr << "values_of_landscapes of incompatible sizes\n";
- return false;
- }
- if (!almost_equal(this->grid_min, rhs.grid_min)) {
- if (dbg) std::cerr << "grid_min not equal\n";
- return false;
- }
- if (!almost_equal(this->grid_max, rhs.grid_max)) {
- if (dbg) std::cerr << "grid_max not equal\n";
- return false;
- }
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- for (size_t aa = 0; aa != this->values_of_landscapes[i].size(); ++aa) {
- if (!almost_equal(this->values_of_landscapes[i][aa], rhs.values_of_landscapes[i][aa])) {
- if (dbg) {
- std::cerr << "Problem in the position : " << i << " of values_of_landscapes. \n";
- std::cerr << this->values_of_landscapes[i][aa] << " " << rhs.values_of_landscapes[i][aa] << std::endl;
- }
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * An operator to compare two persistence landscapes.
- **/
- bool operator!=(const Persistence_landscape_on_grid& rhs) const { return !((*this) == rhs); }
-
- /**
- * Computations of maximum (y) value of landscape.
- **/
- double compute_maximum() const {
- // since the function can only be entirely positive or negative, the maximal value will be an extremal value in the
- // arrays:
- double max_value = -std::numeric_limits<double>::max();
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- if (this->values_of_landscapes[i].size()) {
- if (this->values_of_landscapes[i][0] > max_value) max_value = this->values_of_landscapes[i][0];
- if (this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1] > max_value)
- max_value = this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1];
- }
- }
- return max_value;
- }
-
- /**
- * Computations of minimum and maximum value of landscape.
- **/
- std::pair<double, double> compute_minimum_maximum() const {
- // since the function can only be entirely positive or negative, the maximal value will be an extremal value in the
- // arrays:
- double max_value = -std::numeric_limits<double>::max();
- double min_value = 0;
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- if (this->values_of_landscapes[i].size()) {
- if (this->values_of_landscapes[i][0] > max_value) max_value = this->values_of_landscapes[i][0];
- if (this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1] > max_value)
- max_value = this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1];
-
- if (this->values_of_landscapes[i][0] < min_value) min_value = this->values_of_landscapes[i][0];
- if (this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1] < min_value)
- min_value = this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1];
- }
- }
- return std::make_pair(min_value, max_value);
- }
-
- /**
- * This procedure returns x-range of a given level persistence landscape. If a default value is used, the x-range
- * of 0th level landscape is given (and this range contains the ranges of all other landscapes).
- **/
- std::pair<double, double> get_x_range(size_t level = 0) const {
- return std::make_pair(this->grid_min, this->grid_max);
- }
-
- /**
- * This procedure returns y-range of a persistence landscape. If a default value is used, the y-range
- * of 0th level landscape is given (and this range contains the ranges of all other landscapes).
- **/
- std::pair<double, double> get_y_range(size_t level = 0) const { return this->compute_minimum_maximum(); }
-
- /**
- * This function computes maximal lambda for which lambda-level landscape is nonzero.
- **/
- size_t number_of_nonzero_levels() const {
- size_t result = 0;
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- if (this->values_of_landscapes[i].size() > result) result = this->values_of_landscapes[i].size();
- }
- return result;
- }
-
- /**
- * Computations of a \f$L^i\f$ norm of landscape, where i is the input parameter.
- **/
- double compute_norm_of_landscape(double i) const {
- std::vector<std::pair<double, double> > p;
- Persistence_landscape_on_grid l(p, this->grid_min, this->grid_max, this->values_of_landscapes.size() - 1);
-
- if (i < std::numeric_limits<double>::max()) {
- return compute_distance_of_landscapes_on_grid(*this, l, i);
- } else {
- return compute_max_norm_distance_of_landscapes(*this, l);
- }
- }
-
- /**
- * An operator to compute the value of a landscape in the level 'level' at the argument 'x'.
- **/
- double operator()(unsigned level, double x) const { return this->compute_value_at_a_given_point(level, x); }
-
- /**
- * Computations of \f$L^{\infty}\f$ distance between two landscapes.
- **/
- friend double compute_max_norm_distance_of_landscapes(const Persistence_landscape_on_grid& first,
- const Persistence_landscape_on_grid& second);
-
- /**
- * Function to compute absolute value of a PL function. The representation of persistence landscapes allow to store
- *general PL-function. When computing distance between two landscapes, we compute difference between
- * them. In this case, a general PL-function with negative value can appear as a result. Then in order to compute
- *distance, we need to take its absolute value. This is the purpose of this procedure.
- **/
- void abs() {
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- for (size_t j = 0; j != this->values_of_landscapes[i].size(); ++j) {
- this->values_of_landscapes[i][j] = std::abs(this->values_of_landscapes[i][j]);
- }
- }
- }
-
- /**
- * Computes the number of landscape functions.
- **/
- size_t size() const { return this->number_of_nonzero_levels(); }
-
- /**
- * Compute maximal value of lambda-level landscape.
- **/
- double find_max(unsigned lambda) const {
- double max_value = -std::numeric_limits<double>::max();
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- if (this->values_of_landscapes[i].size() > lambda) {
- if (this->values_of_landscapes[i][lambda] > max_value) max_value = this->values_of_landscapes[i][lambda];
- }
- }
- return max_value;
- }
-
- /**
- * Function to compute inner (scalar) product of two landscapes.
- **/
- friend double compute_inner_product(const Persistence_landscape_on_grid& l1,
- const Persistence_landscape_on_grid& l2) {
- if (!check_if_defined_on_the_same_domain(l1, l2))
- throw "Landscapes are not defined on the same grid, the program will now terminate";
- size_t maximal_level = l1.number_of_nonzero_levels();
- double result = 0;
- for (size_t i = 0; i != maximal_level; ++i) {
- result += compute_inner_product(l1, l2, i);
- }
- return result;
- }
-
- /**
- * Function to compute inner (scalar) product of given levels of two landscapes.
- **/
- friend double compute_inner_product(const Persistence_landscape_on_grid& l1, const Persistence_landscape_on_grid& l2,
- size_t level) {
- bool dbg = false;
-
- if (!check_if_defined_on_the_same_domain(l1, l2))
- throw "Landscapes are not defined on the same grid, the program will now terminate";
- double result = 0;
-
- double dx = (l1.grid_max - l1.grid_min) / static_cast<double>(l1.values_of_landscapes.size() - 1);
-
- double previous_x = l1.grid_min - dx;
- double previous_y_l1 = 0;
- double previous_y_l2 = 0;
- for (size_t i = 0; i != l1.values_of_landscapes.size(); ++i) {
- if (dbg) std::cerr << "i : " << i << std::endl;
-
- double current_x = previous_x + dx;
- double current_y_l1 = 0;
- if (l1.values_of_landscapes[i].size() > level) current_y_l1 = l1.values_of_landscapes[i][level];
-
- double current_y_l2 = 0;
- if (l2.values_of_landscapes[i].size() > level) current_y_l2 = l2.values_of_landscapes[i][level];
-
- if (dbg) {
- std::cerr << "previous_x : " << previous_x << std::endl;
- std::cerr << "previous_y_l1 : " << previous_y_l1 << std::endl;
- std::cerr << "current_y_l1 : " << current_y_l1 << std::endl;
- std::cerr << "previous_y_l2 : " << previous_y_l2 << std::endl;
- std::cerr << "current_y_l2 : " << current_y_l2 << std::endl;
- }
-
- std::pair<double, double> l1_coords = compute_parameters_of_a_line(std::make_pair(previous_x, previous_y_l1),
- std::make_pair(current_x, current_y_l1));
- std::pair<double, double> l2_coords = compute_parameters_of_a_line(std::make_pair(previous_x, previous_y_l2),
- std::make_pair(current_x, current_y_l2));
-
- // let us assume that the first line is of a form y = ax+b, and the second one is of a form y = cx + d. Then here
- // are a,b,c,d:
- double a = l1_coords.first;
- double b = l1_coords.second;
-
- double c = l2_coords.first;
- double d = l2_coords.second;
-
- if (dbg) {
- std::cerr << "Here are the formulas for a line: \n";
- std::cerr << "a : " << a << std::endl;
- std::cerr << "b : " << b << std::endl;
- std::cerr << "c : " << c << std::endl;
- std::cerr << "d : " << d << std::endl;
- }
-
- // now, to compute the inner product in this interval we need to compute the integral of (ax+b)(cx+d) = acx^2 +
- // (ad+bc)x + bd in the interval from previous_x to current_x:
- // The integral is ac/3*x^3 + (ac+bd)/2*x^2 + bd*x
-
- double added_value = (a * c / 3 * current_x * current_x * current_x +
- (a * d + b * c) / 2 * current_x * current_x + b * d * current_x) -
- (a * c / 3 * previous_x * previous_x * previous_x +
- (a * d + b * c) / 2 * previous_x * previous_x + b * d * previous_x);
-
- if (dbg) {
- std::cerr << "Value of the integral on the left end i.e. : " << previous_x << " is : "
- << a * c / 3 * previous_x * previous_x * previous_x + (a * d + b * c) / 2 * previous_x * previous_x +
- b * d * previous_x
- << std::endl;
- std::cerr << "Value of the integral on the right end i.e. : " << current_x << " is "
- << a * c / 3 * current_x * current_x * current_x + (a * d + b * c) / 2 * current_x * current_x +
- b * d * current_x
- << std::endl;
- }
-
- result += added_value;
-
- if (dbg) {
- std::cerr << "added_value : " << added_value << std::endl;
- std::cerr << "result : " << result << std::endl;
- getchar();
- }
-
- previous_x = current_x;
- previous_y_l1 = current_y_l1;
- previous_y_l2 = current_y_l2;
- }
- return result;
- }
-
- /**
- * Computations of \f$L^{p}\f$ distance between two landscapes on a grid. p is the parameter of the procedure.
- * FIXME: Note that, due to the grid representation, the method below may give non--accurate results in case when the
- *landscape P and Q the difference of which we want to compute
- * are intersecting. This is a consequence of a general way they are computed. In the future, an integral of absolute
- *value of a difference of P and Q will be given as a separated
- * function to fix that inaccuracy.
- **/
- friend double compute_distance_of_landscapes_on_grid(const Persistence_landscape_on_grid& first,
- const Persistence_landscape_on_grid& second, double p) {
- bool dbg = false;
- // This is what we want to compute: (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p). We will do it one step at a
- // time:
-
- if (dbg) {
- std::cerr << "first : " << first << std::endl;
- std::cerr << "second : " << second << std::endl;
- getchar();
- }
-
- // first-second :
- Persistence_landscape_on_grid lan = first - second;
-
- if (dbg) {
- std::cerr << "Difference : " << lan << std::endl;
- }
-
- //| first-second |:
- lan.abs();
-
- if (dbg) {
- std::cerr << "Abs : " << lan << std::endl;
- }
-
- if (p < std::numeric_limits<double>::max()) {
- // \int_{- \infty}^{+\infty}| first-second |^p
- double result;
- if (p != 1) {
- if (dbg) {
- std::cerr << "p : " << p << std::endl;
- getchar();
- }
- result = lan.compute_integral_of_landscape(p);
- if (dbg) {
- std::cerr << "integral : " << result << std::endl;
- getchar();
- }
- } else {
- result = lan.compute_integral_of_landscape();
- if (dbg) {
- std::cerr << "integral, without power : " << result << std::endl;
- getchar();
- }
- }
- // (\int_{- \infty}^{+\infty}| first-second |^p)^(1/p)
- return pow(result, 1.0 / p);
- } else {
- // p == infty
- return lan.compute_maximum();
- }
- }
-
- // Functions that are needed for that class to implement the concept.
-
- /**
- * The number of projections to R is defined to the number of nonzero landscape functions. I-th projection is an
- *integral of i-th landscape function over whole R.
- * This function is required by the Real_valued_topological_data concept.
- * At the moment this function is not tested, since it is quite likely to be changed in the future. Given this, when
- *using it, keep in mind that it
- * will be most likely changed in the next versions.
- **/
- double project_to_R(int number_of_function) const {
- return this->compute_integral_of_landscape((size_t)number_of_function);
- }
-
- /**
- * The function gives the number of possible projections to R. This function is required by the
- *Real_valued_topological_data concept.
- **/
- size_t number_of_projections_to_R() const { return number_of_functions_for_projections_to_reals; }
-
- /**
- * This function produce a vector of doubles based on a landscape. It is required in a concept
- * Vectorized_topological_data
- */
- std::vector<double> vectorize(int number_of_function) const {
- // TODO(PD) think of something smarter over here
- if ((number_of_function < 0) || ((size_t)number_of_function >= this->values_of_landscapes.size())) {
- throw "Wrong number of function\n";
- }
- std::vector<double> v(this->values_of_landscapes.size());
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- v[i] = 0;
- if (this->values_of_landscapes[i].size() > (size_t)number_of_function) {
- v[i] = this->values_of_landscapes[i][number_of_function];
- }
- }
- return v;
- }
-
- /**
- * This function return the number of functions that allows vectorization of persistence landscape. It is required in
- *a concept Vectorized_topological_data.
- **/
- size_t number_of_vectorize_functions() const { return number_of_functions_for_vectorization; }
-
- /**
- * A function to compute averaged persistence landscape on a grid, based on vector of persistence landscapes on grid.
- * This function is required by Topological_data_with_averages concept.
- **/
- void compute_average(const std::vector<Persistence_landscape_on_grid*>& to_average) {
- bool dbg = false;
- // After execution of this procedure, the average is supposed to be in the current object. To make sure that this is
- // the case, we need to do some cleaning first.
- this->values_of_landscapes.clear();
- this->grid_min = this->grid_max = 0;
-
- // if there is nothing to average, then the average is a zero landscape.
- if (to_average.size() == 0) return;
-
- // now we need to check if the grids in all objects of to_average are the same:
- for (size_t i = 0; i != to_average.size(); ++i) {
- if (!check_if_defined_on_the_same_domain(*(to_average[0]), *(to_average[i])))
- throw "Two grids are not compatible";
- }
-
- this->values_of_landscapes = std::vector<std::vector<double> >((to_average[0])->values_of_landscapes.size());
- this->grid_min = (to_average[0])->grid_min;
- this->grid_max = (to_average[0])->grid_max;
-
- if (dbg) {
- std::cerr << "Computations of average. The data from the current landscape have been cleared. We are ready to do "
- "the computations. \n";
- }
-
- // for every point in the grid:
- for (size_t grid_point = 0; grid_point != (to_average[0])->values_of_landscapes.size(); ++grid_point) {
- // set up a vector of the correct size:
- size_t maximal_size_of_vector = 0;
- for (size_t land_no = 0; land_no != to_average.size(); ++land_no) {
- if ((to_average[land_no])->values_of_landscapes[grid_point].size() > maximal_size_of_vector)
- maximal_size_of_vector = (to_average[land_no])->values_of_landscapes[grid_point].size();
- }
- this->values_of_landscapes[grid_point] = std::vector<double>(maximal_size_of_vector);
-
- if (dbg) {
- std::cerr << "We are considering the point : " << grid_point
- << " of the grid. In this point, there are at most : " << maximal_size_of_vector
- << " nonzero landscape functions \n";
- }
-
- // and compute an arithmetic average:
- for (size_t land_no = 0; land_no != to_average.size(); ++land_no) {
- // summing:
- for (size_t i = 0; i != (to_average[land_no])->values_of_landscapes[grid_point].size(); ++i) {
- // compute the average in a smarter way.
- this->values_of_landscapes[grid_point][i] += (to_average[land_no])->values_of_landscapes[grid_point][i];
- }
- }
- // normalizing:
- for (size_t i = 0; i != this->values_of_landscapes[grid_point].size(); ++i) {
- this->values_of_landscapes[grid_point][i] /= static_cast<double>(to_average.size());
- }
- }
- } // compute_average
-
- /**
- * A function to compute distance between persistence landscape on a grid.
- * The parameter of this function is a Persistence_landscape_on_grid.
- * This function is required in Topological_data_with_distances concept.
- * For max norm distance, set power to std::numeric_limits<double>::max()
- **/
- double distance(const Persistence_landscape_on_grid& second, double power = 1) const {
- if (power < std::numeric_limits<double>::max()) {
- return compute_distance_of_landscapes_on_grid(*this, second, power);
- } else {
- return compute_max_norm_distance_of_landscapes(*this, second);
- }
- }
-
- /**
- * A function to compute scalar product of persistence landscape on a grid.
- * The parameter of this function is a Persistence_landscape_on_grid.
- * This function is required in Topological_data_with_scalar_product concept.
- **/
- double compute_scalar_product(const Persistence_landscape_on_grid& second) {
- return compute_inner_product((*this), second);
- }
-
- // end of implementation of functions needed for concepts.
-
- /**
- * A function that returns values of landscapes. It can be used for visualization
- **/
- std::vector<std::vector<double> > output_for_visualization() const { return this->values_of_landscapes; }
-
- /**
- * function used to create a gnuplot script for visualization of landscapes. Over here we need to specify which
- *landscapes do we want to plot.
- * In addition, the user may specify the range (min and max) where landscape is plot. The default values for min and
- *max are std::numeric_limits<double>::max(). If the procedure detect those
- * values, it will determine the range so that the whole landscape is supported there. If at least one min or max value
- *is different from std::numeric_limits<double>::max(), then the values
- * provided by the user will be used.
- **/
- void plot(const char* filename, size_t from_, size_t to_) const {
- this->plot(filename, std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
- std::numeric_limits<double>::max(), std::numeric_limits<double>::max(), from_, to_);
- }
-
- /**
- * function used to create a gnuplot script for visualization of landscapes. Over here we can restrict also x and y
- *range of the landscape.
- **/
- void plot(const char* filename, double min_x = std::numeric_limits<double>::max(),
- double max_x = std::numeric_limits<double>::max(), double min_y = std::numeric_limits<double>::max(),
- double max_y = std::numeric_limits<double>::max(), size_t from_ = std::numeric_limits<size_t>::max(),
- size_t to_ = std::numeric_limits<size_t>::max()) const;
-
- protected:
- double grid_min;
- double grid_max;
- std::vector<std::vector<double> > values_of_landscapes;
- size_t number_of_functions_for_vectorization;
- size_t number_of_functions_for_projections_to_reals;
-
- void set_up_numbers_of_functions_for_vectorization_and_projections_to_reals() {
- // warning, this function can be only called after filling in the values_of_landscapes vector.
- this->number_of_functions_for_vectorization = this->values_of_landscapes.size();
- this->number_of_functions_for_projections_to_reals = this->values_of_landscapes.size();
- }
- void set_up_values_of_landscapes(const std::vector<std::pair<double, double> >& p, double grid_min_, double grid_max_,
- size_t number_of_points_,
- unsigned number_of_levels = std::numeric_limits<unsigned>::max());
- Persistence_landscape_on_grid multiply_lanscape_by_real_number_not_overwrite(double x) const;
-};
-
-void Persistence_landscape_on_grid::set_up_values_of_landscapes(const std::vector<std::pair<double, double> >& p,
- double grid_min_, double grid_max_,
- size_t number_of_points_, unsigned number_of_levels) {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Here is the procedure : set_up_values_of_landscapes. The parameters are : grid_min_ : " << grid_min_
- << ", grid_max_ : " << grid_max_ << ", number_of_points_ : " << number_of_points_
- << ", number_of_levels: " << number_of_levels << std::endl;
- std::cerr << "Here are the intervals at our disposal : \n";
- for (size_t i = 0; i != p.size(); ++i) {
- std::cerr << p[i].first << " , " << p[i].second << std::endl;
- }
- }
-
- if ((grid_min_ == std::numeric_limits<double>::max()) || (grid_max_ == std::numeric_limits<double>::max())) {
- // in this case, we need to find grid_min_ and grid_min_ based on the data.
- double min = std::numeric_limits<double>::max();
- double max = std::numeric_limits<double>::min();
- for (size_t i = 0; i != p.size(); ++i) {
- if (p[i].first < min) min = p[i].first;
- if (p[i].second > max) max = p[i].second;
- }
- if (grid_min_ == std::numeric_limits<double>::max()) {
- grid_min_ = min;
- } else {
- // in this case grid_max_ == std::numeric_limits<double>::max()
- grid_max_ = max;
- }
- }
-
- // if number_of_levels == std::numeric_limits<size_t>::max(), then we will have all the nonzero values of landscapes,
- // and will store them in a vector
- // if number_of_levels != std::numeric_limits<size_t>::max(), then we will use those vectors as heaps.
- this->values_of_landscapes = std::vector<std::vector<double> >(number_of_points_ + 1);
-
- this->grid_min = grid_min_;
- this->grid_max = grid_max_;
-
- if (grid_max_ <= grid_min_) {
- throw "Wrong parameters of grid_min and grid_max given to the procedure. The program will now terminate.\n";
- }
-
- double dx = (grid_max_ - grid_min_) / static_cast<double>(number_of_points_);
- // for every interval in the diagram:
- for (size_t int_no = 0; int_no != p.size(); ++int_no) {
- size_t grid_interval_begin = (p[int_no].first - grid_min_) / dx;
- size_t grid_interval_end = (p[int_no].second - grid_min_) / dx;
- size_t grid_interval_midpoint = (size_t)(0.5 * (grid_interval_begin + grid_interval_end));
-
- if (dbg) {
- std::cerr << "Considering an interval : " << p[int_no].first << "," << p[int_no].second << std::endl;
-
- std::cerr << "grid_interval_begin : " << grid_interval_begin << std::endl;
- std::cerr << "grid_interval_end : " << grid_interval_end << std::endl;
- std::cerr << "grid_interval_midpoint : " << grid_interval_midpoint << std::endl;
- }
-
- double landscape_value = dx;
- for (size_t i = grid_interval_begin + 1; i < grid_interval_midpoint; ++i) {
- if (dbg) {
- std::cerr << "Adding landscape value (going up) for a point : " << i << " equal : " << landscape_value
- << std::endl;
- }
- if (number_of_levels != std::numeric_limits<unsigned>::max()) {
- // we have a heap of no more that number_of_levels values.
- // Note that if we are using heaps, we want to know the shortest distance in the heap.
- // This is achieved by putting -distance to the heap.
- if (this->values_of_landscapes[i].size() >= number_of_levels) {
- // in this case, the full heap is build, and we need to check if the landscape_value is not larger than the
- // smallest element in the heap.
- if (-landscape_value < this->values_of_landscapes[i].front()) {
- // if it is, we remove the largest value in the heap, and move on.
- std::pop_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1] = -landscape_value;
- std::push_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- }
- } else {
- // in this case we are still filling in the array.
- this->values_of_landscapes[i].push_back(-landscape_value);
- if (this->values_of_landscapes[i].size() == number_of_levels - 1) {
- // this->values_of_landscapes[i].size() == number_of_levels
- // in this case we need to create the heap.
- std::make_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- }
- }
- } else {
- // we have vector of all values
- this->values_of_landscapes[i].push_back(landscape_value);
- }
- landscape_value += dx;
- }
- for (size_t i = grid_interval_midpoint; i <= grid_interval_end; ++i) {
- if (landscape_value > 0) {
- if (number_of_levels != std::numeric_limits<unsigned>::max()) {
- // we have a heap of no more that number_of_levels values
- if (this->values_of_landscapes[i].size() >= number_of_levels) {
- // in this case, the full heap is build, and we need to check if the landscape_value is not larger than the
- // smallest element in the heap.
- if (-landscape_value < this->values_of_landscapes[i].front()) {
- // if it is, we remove the largest value in the heap, and move on.
- std::pop_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- this->values_of_landscapes[i][this->values_of_landscapes[i].size() - 1] = -landscape_value;
- std::push_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- }
- } else {
- // in this case we are still filling in the array.
- this->values_of_landscapes[i].push_back(-landscape_value);
- if (this->values_of_landscapes[i].size() == number_of_levels - 1) {
- // this->values_of_landscapes[i].size() == number_of_levels
- // in this case we need to create the heap.
- std::make_heap(this->values_of_landscapes[i].begin(), this->values_of_landscapes[i].end());
- }
- }
- } else {
- this->values_of_landscapes[i].push_back(landscape_value);
- }
-
- if (dbg) {
- std::cerr << "Adding landscape value (going down) for a point : " << i << " equal : " << landscape_value
- << std::endl;
- }
- }
- landscape_value -= dx;
- }
- }
-
- if (number_of_levels != std::numeric_limits<unsigned>::max()) {
- // in this case, vectors are used as heaps. And, since we want to have the smallest element at the top of
- // each heap, we store minus distances. To get if right at the end, we need to multiply each value
- // in the heap by -1 to get real vector of distances.
- for (size_t pt = 0; pt != this->values_of_landscapes.size(); ++pt) {
- for (size_t j = 0; j != this->values_of_landscapes[pt].size(); ++j) {
- this->values_of_landscapes[pt][j] *= -1;
- }
- }
- }
-
- // and now we need to sort the values:
- for (size_t pt = 0; pt != this->values_of_landscapes.size(); ++pt) {
- std::sort(this->values_of_landscapes[pt].begin(), this->values_of_landscapes[pt].end(), std::greater<double>());
- }
-} // set_up_values_of_landscapes
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const std::vector<std::pair<double, double> >& p,
- double grid_min_, double grid_max_,
- size_t number_of_points_) {
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_);
-} // Persistence_landscape_on_grid
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const std::vector<std::pair<double, double> >& p,
- double grid_min_, double grid_max_,
- size_t number_of_points_,
- unsigned number_of_levels_of_landscape) {
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_, number_of_levels_of_landscape);
-}
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const char* filename, double grid_min_, double grid_max_,
- size_t number_of_points_, uint16_t dimension) {
- std::vector<std::pair<double, double> > p;
- if (dimension == std::numeric_limits<uint16_t>::max()) {
- p = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- p = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_);
-}
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const char* filename, double grid_min_, double grid_max_,
- size_t number_of_points_,
- unsigned number_of_levels_of_landscape,
- uint16_t dimension) {
- std::vector<std::pair<double, double> > p;
- if (dimension == std::numeric_limits<uint16_t>::max()) {
- p = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- p = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_, number_of_levels_of_landscape);
-}
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const char* filename, size_t number_of_points_,
- uint16_t dimension) {
- std::vector<std::pair<double, double> > p;
- if (dimension == std::numeric_limits<uint16_t>::max()) {
- p = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- p = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- double grid_min_ = std::numeric_limits<double>::max();
- double grid_max_ = -std::numeric_limits<double>::max();
- for (size_t i = 0; i != p.size(); ++i) {
- if (p[i].first < grid_min_) grid_min_ = p[i].first;
- if (p[i].second > grid_max_) grid_max_ = p[i].second;
- }
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_);
-}
-
-Persistence_landscape_on_grid::Persistence_landscape_on_grid(const char* filename, size_t number_of_points_,
- unsigned number_of_levels_of_landscape,
- uint16_t dimension) {
- std::vector<std::pair<double, double> > p;
- if (dimension == std::numeric_limits<uint16_t>::max()) {
- p = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- p = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- double grid_min_ = std::numeric_limits<double>::max();
- double grid_max_ = -std::numeric_limits<double>::max();
- for (size_t i = 0; i != p.size(); ++i) {
- if (p[i].first < grid_min_) grid_min_ = p[i].first;
- if (p[i].second > grid_max_) grid_max_ = p[i].second;
- }
- this->set_up_values_of_landscapes(p, grid_min_, grid_max_, number_of_points_, number_of_levels_of_landscape);
-}
-
-void Persistence_landscape_on_grid::load_landscape_from_file(const char* filename) {
- std::ifstream in;
- in.open(filename);
- // check if the file exist.
- if (!in.good()) {
- std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
- throw "The persistence landscape file do not exist. The program will now terminate \n";
- }
-
- size_t number_of_points_in_the_grid = 0;
- in >> this->grid_min >> this->grid_max >> number_of_points_in_the_grid;
-
- std::vector<std::vector<double> > v(number_of_points_in_the_grid);
- std::string line;
- std::getline(in, line);
- double number;
- for (size_t i = 0; i != number_of_points_in_the_grid; ++i) {
- // read a line of a file and convert it to a vector.
- std::vector<double> vv;
- std::getline(in, line);
- std::istringstream stream(line);
- while (stream >> number) {
- vv.push_back(number);
- }
- v[i] = vv;
- }
- this->values_of_landscapes = v;
- in.close();
-}
-
-void Persistence_landscape_on_grid::print_to_file(const char* filename) const {
- std::ofstream out;
- out.open(filename);
-
- // first we store the parameters of the grid:
- out << grid_min << std::endl << grid_max << std::endl << this->values_of_landscapes.size() << std::endl;
-
- // and now in the following lines, the values of this->values_of_landscapes for the following arguments:
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- for (size_t j = 0; j != this->values_of_landscapes[i].size(); ++j) {
- out << this->values_of_landscapes[i][j] << " ";
- }
- out << std::endl;
- }
-
- out.close();
-}
-
-void Persistence_landscape_on_grid::plot(const char* filename, double min_x, double max_x, double min_y, double max_y,
- size_t from_, size_t to_) const {
- // this program create a gnuplot script file that allows to plot persistence diagram.
- std::ofstream out;
-
- std::ostringstream gnuplot_script;
- gnuplot_script << filename << "_GnuplotScript";
- out.open(gnuplot_script.str().c_str());
-
- if (min_x == max_x) {
- std::pair<double, double> min_max = compute_minimum_maximum();
- out << "set xrange [" << this->grid_min << " : " << this->grid_max << "]" << std::endl;
- out << "set yrange [" << min_max.first << " : " << min_max.second << "]" << std::endl;
- } else {
- out << "set xrange [" << min_x << " : " << max_x << "]" << std::endl;
- out << "set yrange [" << min_y << " : " << max_y << "]" << std::endl;
- }
-
- size_t number_of_nonzero_levels = this->number_of_nonzero_levels();
- double dx = (this->grid_max - this->grid_min) / static_cast<double>(this->values_of_landscapes.size() - 1);
-
- size_t from = 0;
- if (from_ != std::numeric_limits<size_t>::max()) {
- if (from_ < number_of_nonzero_levels) {
- from = from_;
- } else {
- return;
- }
- }
- size_t to = number_of_nonzero_levels;
- if (to_ != std::numeric_limits<size_t>::max()) {
- if (to_ < number_of_nonzero_levels) {
- to = to_;
- }
- }
-
- out << "plot ";
- for (size_t lambda = from; lambda != to; ++lambda) {
- out << " '-' using 1:2 notitle with lp";
- if (lambda + 1 != to) {
- out << ", \\";
- }
- out << std::endl;
- }
-
- for (size_t lambda = from; lambda != to; ++lambda) {
- double point = this->grid_min;
- for (size_t i = 0; i != this->values_of_landscapes.size(); ++i) {
- double value = 0;
- if (this->values_of_landscapes[i].size() > lambda) {
- value = this->values_of_landscapes[i][lambda];
- }
- out << point << " " << value << std::endl;
- point += dx;
- }
- out << "EOF" << std::endl;
- }
- std::cout << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
- << gnuplot_script.str().c_str() << "\'\"" << std::endl;
-}
-
-template <typename T>
-Persistence_landscape_on_grid operation_on_pair_of_landscapes_on_grid(const Persistence_landscape_on_grid& land1,
- const Persistence_landscape_on_grid& land2) {
- // first we need to check if the domains are the same:
- if (!check_if_defined_on_the_same_domain(land1, land2)) throw "Two grids are not compatible";
-
- T oper;
- Persistence_landscape_on_grid result;
- result.values_of_landscapes = std::vector<std::vector<double> >(land1.values_of_landscapes.size());
- result.grid_min = land1.grid_min;
- result.grid_max = land1.grid_max;
-
- // now we perform the operations:
- for (size_t grid_point = 0; grid_point != land1.values_of_landscapes.size(); ++grid_point) {
- result.values_of_landscapes[grid_point] = std::vector<double>(
- std::max(land1.values_of_landscapes[grid_point].size(), land2.values_of_landscapes[grid_point].size()));
- for (size_t lambda = 0; lambda != std::max(land1.values_of_landscapes[grid_point].size(),
- land2.values_of_landscapes[grid_point].size());
- ++lambda) {
- double value1 = 0;
- double value2 = 0;
- if (lambda < land1.values_of_landscapes[grid_point].size())
- value1 = land1.values_of_landscapes[grid_point][lambda];
- if (lambda < land2.values_of_landscapes[grid_point].size())
- value2 = land2.values_of_landscapes[grid_point][lambda];
- result.values_of_landscapes[grid_point][lambda] = oper(value1, value2);
- }
- }
-
- return result;
-}
-
-Persistence_landscape_on_grid Persistence_landscape_on_grid::multiply_lanscape_by_real_number_not_overwrite(
- double x) const {
- Persistence_landscape_on_grid result;
- result.values_of_landscapes = std::vector<std::vector<double> >(this->values_of_landscapes.size());
- result.grid_min = this->grid_min;
- result.grid_max = this->grid_max;
-
- for (size_t grid_point = 0; grid_point != this->values_of_landscapes.size(); ++grid_point) {
- result.values_of_landscapes[grid_point] = std::vector<double>(this->values_of_landscapes[grid_point].size());
- for (size_t i = 0; i != this->values_of_landscapes[grid_point].size(); ++i) {
- result.values_of_landscapes[grid_point][i] = x * this->values_of_landscapes[grid_point][i];
- }
- }
-
- return result;
-}
-
-double compute_max_norm_distance_of_landscapes(const Persistence_landscape_on_grid& first,
- const Persistence_landscape_on_grid& second) {
- double result = 0;
-
- // first we need to check if first and second is defined on the same domain"
- if (!check_if_defined_on_the_same_domain(first, second)) throw "Two grids are not compatible";
-
- for (size_t i = 0; i != first.values_of_landscapes.size(); ++i) {
- for (size_t j = 0; j != std::min(first.values_of_landscapes[i].size(), second.values_of_landscapes[i].size());
- ++j) {
- if (result < abs(first.values_of_landscapes[i][j] - second.values_of_landscapes[i][j])) {
- result = abs(first.values_of_landscapes[i][j] - second.values_of_landscapes[i][j]);
- }
- }
- if (first.values_of_landscapes[i].size() ==
- std::min(first.values_of_landscapes[i].size(), second.values_of_landscapes[i].size())) {
- for (size_t j = first.values_of_landscapes[i].size(); j != second.values_of_landscapes[i].size(); ++j) {
- if (result < second.values_of_landscapes[i][j]) result = second.values_of_landscapes[i][j];
- }
- }
- if (second.values_of_landscapes[i].size() ==
- std::min(first.values_of_landscapes[i].size(), second.values_of_landscapes[i].size())) {
- for (size_t j = second.values_of_landscapes[i].size(); j != first.values_of_landscapes[i].size(); ++j) {
- if (result < first.values_of_landscapes[i][j]) result = first.values_of_landscapes[i][j];
- }
- }
- }
- return result;
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_LANDSCAPE_ON_GRID_H_
diff --git a/include/gudhi/Persistence_vectors.h b/include/gudhi/Persistence_vectors.h
deleted file mode 100644
index 9c04be1d..00000000
--- a/include/gudhi/Persistence_vectors.h
+++ /dev/null
@@ -1,640 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENCE_VECTORS_H_
-#define PERSISTENCE_VECTORS_H_
-
-// gudhi include
-#include <gudhi/read_persistence_from_file.h>
-#include <gudhi/common_persistence_representations.h>
-#include <gudhi/distance_functions.h>
-
-#include <fstream>
-#include <cmath>
-#include <algorithm>
-#include <iostream>
-#include <limits>
-#include <functional>
-#include <utility>
-#include <vector>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-template <typename T>
-struct Maximum_distance {
- double operator()(const std::pair<T, T>& f, const std::pair<T, T>& s) {
- return std::max(fabs(f.first - s.first), fabs(f.second - s.second));
- }
-};
-
-/**
- * \class Vector_distances_in_diagram Persistence_vectors.h gudhi/Persistence_vectors.h
- * \brief A class implementing persistence vectors.
- *
- * \ingroup Persistence_representations
- *
- * \details
- * This is an implementation of idea presented in the paper <i>Stable Topological Signatures for Points on 3D
- * Shapes</i> \cite Carriere_Oudot_Ovsjanikov_top_signatures_3d .<br>
- * The parameter of the class is the class that computes distance used to construct the vectors. The typical function
- * is either Euclidean of maximum (Manhattan) distance.
- *
- * This class implements the following concepts: Vectorized_topological_data, Topological_data_with_distances,
- * Real_valued_topological_data, Topological_data_with_averages, Topological_data_with_scalar_product
- **/
-template <typename F>
-class Vector_distances_in_diagram {
- public:
- /**
- * The default constructor.
- **/
- Vector_distances_in_diagram() {}
-
- /**
- * The constructor that takes as an input a multiset of persistence intervals (given as vector of birth-death
- *pairs). The second parameter is the desired length of the output vectors.
- **/
- Vector_distances_in_diagram(const std::vector<std::pair<double, double> >& intervals, size_t where_to_cut);
-
- /**
- * The constructor taking as an input a file with birth-death pairs. The second parameter is the desired length of
- *the output vectors.
- **/
- Vector_distances_in_diagram(const char* filename, size_t where_to_cut,
- unsigned dimension = std::numeric_limits<unsigned>::max());
-
- /**
- * Writing to a stream.
- **/
- template <typename K>
- friend std::ostream& operator<<(std::ostream& out, const Vector_distances_in_diagram<K>& d) {
- for (size_t i = 0; i != std::min(d.sorted_vector_of_distances.size(), d.where_to_cut); ++i) {
- out << d.sorted_vector_of_distances[i] << " ";
- }
- return out;
- }
-
- /**
- * This procedure gives the value of a vector on a given position.
- **/
- inline double vector_in_position(size_t position) const {
- if (position >= this->sorted_vector_of_distances.size())
- throw("Wrong position in accessing Vector_distances_in_diagram::sorted_vector_of_distances\n");
- return this->sorted_vector_of_distances[position];
- }
-
- /**
- * Return a size of a vector.
- **/
- inline size_t size() const { return this->sorted_vector_of_distances.size(); }
-
- /**
- * Write a vector to a file.
- **/
- void write_to_file(const char* filename) const;
-
- /**
- * Write a vector to a file.
- **/
- void print_to_file(const char* filename) const { this->write_to_file(filename); }
-
- /**
- * Loading a vector to a file.
- **/
- void load_from_file(const char* filename);
-
- /**
- * Comparison operators:
- **/
- bool operator==(const Vector_distances_in_diagram& second) const {
- if (this->sorted_vector_of_distances.size() != second.sorted_vector_of_distances.size()) return false;
- for (size_t i = 0; i != this->sorted_vector_of_distances.size(); ++i) {
- if (!almost_equal(this->sorted_vector_of_distances[i], second.sorted_vector_of_distances[i])) return false;
- }
- return true;
- }
-
- bool operator!=(const Vector_distances_in_diagram& second) const { return !(*this == second); }
-
- // Implementations of functions for various concepts.
- /**
- * Compute projection to real numbers of persistence vector. This function is required by the
- *Real_valued_topological_data concept
- * At the moment this function is not tested, since it is quite likely to be changed in the future. Given this, when
- *using it, keep in mind that it
- * will be most likely changed in the next versions.
- **/
- double project_to_R(int number_of_function) const;
- /**
- * The function gives the number of possible projections to R. This function is required by the
- *Real_valued_topological_data concept.
- **/
- size_t number_of_projections_to_R() const { return this->number_of_functions_for_projections_to_reals; }
-
- /**
- * Compute a vectorization of a persistent vectors. It is required in a concept Vectorized_topological_data.
- **/
- std::vector<double> vectorize(int number_of_function) const;
- /**
- * This function return the number of functions that allows vectorization of a persistence vector. It is required
- *in a concept Vectorized_topological_data.
- **/
- size_t number_of_vectorize_functions() const { return this->number_of_functions_for_vectorization; }
-
- /**
- * Compute a average of two persistent vectors. This function is required by Topological_data_with_averages concept.
- **/
- void compute_average(const std::vector<Vector_distances_in_diagram*>& to_average);
-
- /**
- * Compute a distance of two persistent vectors. This function is required in Topological_data_with_distances concept.
- * For max norm distance, set power to std::numeric_limits<double>::max()
- **/
- double distance(const Vector_distances_in_diagram& second, double power = 1) const;
-
- /**
- * Compute a scalar product of two persistent vectors. This function is required in
- *Topological_data_with_scalar_product concept.
- **/
- double compute_scalar_product(const Vector_distances_in_diagram& second) const;
- // end of implementation of functions needed for concepts.
-
- /**
- * For visualization use output from vectorize and build histograms.
- **/
- std::vector<double> output_for_visualization() const { return this->sorted_vector_of_distances; }
-
- /**
- * Create a gnuplot script to visualize the data structure.
- **/
- void plot(const char* filename) const {
- std::stringstream gnuplot_script;
- gnuplot_script << filename << "_GnuplotScript";
- std::ofstream out;
- out.open(gnuplot_script.str().c_str());
- out << "set style data histogram" << std::endl;
- out << "set style histogram cluster gap 1" << std::endl;
- out << "set style fill solid border -1" << std::endl;
- out << "plot '-' notitle" << std::endl;
- for (size_t i = 0; i != this->sorted_vector_of_distances.size(); ++i) {
- out << this->sorted_vector_of_distances[i] << std::endl;
- }
- out << std::endl;
- out.close();
- std::cout << "To visualize, install gnuplot and type the command: gnuplot -persist -e \"load \'"
- << gnuplot_script.str().c_str() << "\'\"" << std::endl;
- }
-
- /**
- * The x-range of the persistence vector.
- **/
- std::pair<double, double> get_x_range() const { return std::make_pair(0, this->sorted_vector_of_distances.size()); }
-
- /**
- * The y-range of the persistence vector.
- **/
- std::pair<double, double> get_y_range() const {
- if (this->sorted_vector_of_distances.size() == 0) return std::make_pair(0, 0);
- return std::make_pair(this->sorted_vector_of_distances[0], 0);
- }
-
- // arithmetic operations:
- template <typename Operation_type>
- friend Vector_distances_in_diagram operation_on_pair_of_vectors(const Vector_distances_in_diagram& first,
- const Vector_distances_in_diagram& second,
- Operation_type opertion) {
- Vector_distances_in_diagram result;
- // Operation_type operation;
- result.sorted_vector_of_distances.reserve(
- std::max(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size()));
- for (size_t i = 0; i != std::min(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size());
- ++i) {
- result.sorted_vector_of_distances.push_back(
- opertion(first.sorted_vector_of_distances[i], second.sorted_vector_of_distances[i]));
- }
- if (first.sorted_vector_of_distances.size() ==
- std::min(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size())) {
- for (size_t i = std::min(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size());
- i != std::max(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size()); ++i) {
- result.sorted_vector_of_distances.push_back(opertion(0, second.sorted_vector_of_distances[i]));
- }
- } else {
- for (size_t i = std::min(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size());
- i != std::max(first.sorted_vector_of_distances.size(), second.sorted_vector_of_distances.size()); ++i) {
- result.sorted_vector_of_distances.push_back(opertion(first.sorted_vector_of_distances[i], 0));
- }
- }
- return result;
- } // operation_on_pair_of_vectors
-
- /**
- * This function implements an operation of multiplying Vector_distances_in_diagram by a scalar.
- **/
- Vector_distances_in_diagram multiply_by_scalar(double scalar) const {
- Vector_distances_in_diagram result;
- result.sorted_vector_of_distances.reserve(this->sorted_vector_of_distances.size());
- for (size_t i = 0; i != this->sorted_vector_of_distances.size(); ++i) {
- result.sorted_vector_of_distances.push_back(scalar * this->sorted_vector_of_distances[i]);
- }
- return result;
- } // multiply_by_scalar
-
- /**
- * This function computes a sum of two objects of a type Vector_distances_in_diagram.
- **/
- friend Vector_distances_in_diagram operator+(const Vector_distances_in_diagram& first,
- const Vector_distances_in_diagram& second) {
- return operation_on_pair_of_vectors(first, second, std::plus<double>());
- }
- /**
-* This function computes a difference of two objects of a type Vector_distances_in_diagram.
-**/
- friend Vector_distances_in_diagram operator-(const Vector_distances_in_diagram& first,
- const Vector_distances_in_diagram& second) {
- return operation_on_pair_of_vectors(first, second, std::minus<double>());
- }
- /**
-* This function computes a product of an object of a type Vector_distances_in_diagram with real number.
-**/
- friend Vector_distances_in_diagram operator*(double scalar, const Vector_distances_in_diagram& A) {
- return A.multiply_by_scalar(scalar);
- }
- /**
-* This function computes a product of an object of a type Vector_distances_in_diagram with real number.
-**/
- friend Vector_distances_in_diagram operator*(const Vector_distances_in_diagram& A, double scalar) {
- return A.multiply_by_scalar(scalar);
- }
- /**
-* This function computes a product of an object of a type Vector_distances_in_diagram with real number.
-**/
- Vector_distances_in_diagram operator*(double scalar) { return this->multiply_by_scalar(scalar); }
- /**
- * += operator for Vector_distances_in_diagram.
- **/
- Vector_distances_in_diagram operator+=(const Vector_distances_in_diagram& rhs) {
- *this = *this + rhs;
- return *this;
- }
- /**
- * -= operator for Vector_distances_in_diagram.
- **/
- Vector_distances_in_diagram operator-=(const Vector_distances_in_diagram& rhs) {
- *this = *this - rhs;
- return *this;
- }
- /**
- * *= operator for Vector_distances_in_diagram.
- **/
- Vector_distances_in_diagram operator*=(double x) {
- *this = *this * x;
- return *this;
- }
- /**
- * /= operator for Vector_distances_in_diagram.
- **/
- Vector_distances_in_diagram operator/=(double x) {
- if (x == 0) throw("In operator /=, division by 0. Program terminated.");
- *this = *this * (1 / x);
- return *this;
- }
-
- private:
- std::vector<std::pair<double, double> > intervals;
- std::vector<double> sorted_vector_of_distances;
- size_t number_of_functions_for_vectorization;
- size_t number_of_functions_for_projections_to_reals;
- size_t where_to_cut;
-
- void compute_sorted_vector_of_distances_via_heap(size_t where_to_cut);
- void compute_sorted_vector_of_distances_via_vector_sorting(size_t where_to_cut);
-
- Vector_distances_in_diagram(const std::vector<double>& sorted_vector_of_distances_)
- : sorted_vector_of_distances(sorted_vector_of_distances_) {
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
- }
-
- void set_up_numbers_of_functions_for_vectorization_and_projections_to_reals() {
- // warning, this function can be only called after filling in the intervals vector.
- this->number_of_functions_for_vectorization = this->sorted_vector_of_distances.size();
- this->number_of_functions_for_projections_to_reals = this->sorted_vector_of_distances.size();
- }
-};
-
-template <typename F>
-Vector_distances_in_diagram<F>::Vector_distances_in_diagram(const std::vector<std::pair<double, double> >& intervals_,
- size_t where_to_cut_)
- : where_to_cut(where_to_cut_) {
- std::vector<std::pair<double, double> > i(intervals_);
- this->intervals = i;
- // this->compute_sorted_vector_of_distances_via_heap( where_to_cut );
- this->compute_sorted_vector_of_distances_via_vector_sorting(where_to_cut);
- this->set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-}
-
-template <typename F>
-Vector_distances_in_diagram<F>::Vector_distances_in_diagram(const char* filename, size_t where_to_cut,
- unsigned dimension)
- : where_to_cut(where_to_cut) {
- std::vector<std::pair<double, double> > intervals;
- if (dimension == std::numeric_limits<unsigned>::max()) {
- intervals = read_persistence_intervals_in_one_dimension_from_file(filename);
- } else {
- intervals = read_persistence_intervals_in_one_dimension_from_file(filename, dimension);
- }
- this->intervals = intervals;
- this->compute_sorted_vector_of_distances_via_heap(where_to_cut);
- // this->compute_sorted_vector_of_distances_via_vector_sorting( where_to_cut );
- set_up_numbers_of_functions_for_vectorization_and_projections_to_reals();
-}
-
-template <typename F>
-void Vector_distances_in_diagram<F>::compute_sorted_vector_of_distances_via_heap(size_t where_to_cut) {
- bool dbg = false;
- if (dbg) {
- std::cerr << "Here are the intervals : \n";
- for (size_t i = 0; i != this->intervals.size(); ++i) {
- std::cerr << this->intervals[i].first << " , " << this->intervals[i].second << std::endl;
- }
- }
- where_to_cut = std::min(
- where_to_cut, (size_t)(0.5 * this->intervals.size() * (this->intervals.size() - 1) + this->intervals.size()));
-
- std::vector<double> heap(where_to_cut, std::numeric_limits<int>::max());
- std::make_heap(heap.begin(), heap.end());
- F f;
-
- // for every pair of points in the diagram, compute the minimum of their distance, and distance of those points from
- // diagonal
- for (size_t i = 0; i < this->intervals.size(); ++i) {
- for (size_t j = i + 1; j < this->intervals.size(); ++j) {
- double value = std::min(
- f(this->intervals[i], this->intervals[j]),
- std::min(
- f(this->intervals[i], std::make_pair(0.5 * (this->intervals[i].first + this->intervals[i].second),
- 0.5 * (this->intervals[i].first + this->intervals[i].second))),
- f(this->intervals[j], std::make_pair(0.5 * (this->intervals[j].first + this->intervals[j].second),
- 0.5 * (this->intervals[j].first + this->intervals[j].second)))));
-
- if (dbg) {
- std::cerr << "Value : " << value << std::endl;
- std::cerr << "heap.front() : " << heap.front() << std::endl;
- getchar();
- }
-
- if (-value < heap.front()) {
- if (dbg) {
- std::cerr << "Replacing : " << heap.front() << " with : " << -value << std::endl;
- getchar();
- }
- // remove the first element from the heap
- std::pop_heap(heap.begin(), heap.end());
- // heap.pop_back();
- // and put value there instead:
- // heap.push_back(-value);
- heap[where_to_cut - 1] = -value;
- std::push_heap(heap.begin(), heap.end());
- }
- }
- }
-
- // now add distances of all points from diagonal
- for (size_t i = 0; i < this->intervals.size(); ++i) {
- double value = f(this->intervals[i], std::make_pair(0.5 * (this->intervals[i].first + this->intervals[i].second),
- 0.5 * (this->intervals[i].first + this->intervals[i].second)));
- if (-value < heap.front()) {
- // remove the first element from the heap
- std::pop_heap(heap.begin(), heap.end());
- // heap.pop_back();
- // and put value there instead:
- // heap.push_back(-value);
- heap[where_to_cut - 1] = -value;
- std::push_heap(heap.begin(), heap.end());
- }
- }
-
- std::sort_heap(heap.begin(), heap.end());
- for (size_t i = 0; i != heap.size(); ++i) {
- if (heap[i] == std::numeric_limits<int>::max()) {
- heap[i] = 0;
- } else {
- heap[i] *= -1;
- }
- }
-
- if (dbg) {
- std::cerr << "This is the heap after all the operations :\n";
- for (size_t i = 0; i != heap.size(); ++i) {
- std::cout << heap[i] << " ";
- }
- std::cout << std::endl;
- }
-
- this->sorted_vector_of_distances = heap;
-}
-
-template <typename F>
-void Vector_distances_in_diagram<F>::compute_sorted_vector_of_distances_via_vector_sorting(size_t where_to_cut) {
- std::vector<double> distances;
- distances.reserve((size_t)(0.5 * this->intervals.size() * (this->intervals.size() - 1) + this->intervals.size()));
- F f;
-
- // for every pair of points in the diagram, compute the minimum of their distance, and distance of those points from
- // diagonal
- for (size_t i = 0; i < this->intervals.size(); ++i) {
- // add distance of i-th point in the diagram from the diagonal to the distances vector
- distances.push_back(
- f(this->intervals[i], std::make_pair(0.5 * (this->intervals[i].first + this->intervals[i].second),
- 0.5 * (this->intervals[i].first + this->intervals[i].second))));
- for (size_t j = i + 1; j < this->intervals.size(); ++j) {
- double value = std::min(
- f(this->intervals[i], this->intervals[j]),
- std::min(
- f(this->intervals[i], std::make_pair(0.5 * (this->intervals[i].first + this->intervals[i].second),
- 0.5 * (this->intervals[i].first + this->intervals[i].second))),
- f(this->intervals[j], std::make_pair(0.5 * (this->intervals[j].first + this->intervals[j].second),
- 0.5 * (this->intervals[j].first + this->intervals[j].second)))));
- distances.push_back(value);
- }
- }
- std::sort(distances.begin(), distances.end(), std::greater<double>());
- if (distances.size() > where_to_cut) distances.resize(where_to_cut);
-
- this->sorted_vector_of_distances = distances;
-}
-
-// Implementations of functions for various concepts.
-template <typename F>
-double Vector_distances_in_diagram<F>::project_to_R(int number_of_function) const {
- if ((size_t)number_of_function > this->number_of_functions_for_projections_to_reals)
- throw "Wrong index of a function in a method Vector_distances_in_diagram<F>::project_to_R";
- if (number_of_function < 0)
- throw "Wrong index of a function in a method Vector_distances_in_diagram<F>::project_to_R";
-
- double result = 0;
- for (size_t i = 0; i != (size_t)number_of_function; ++i) {
- result += sorted_vector_of_distances[i];
- }
- return result;
-}
-
-template <typename F>
-void Vector_distances_in_diagram<F>::compute_average(const std::vector<Vector_distances_in_diagram*>& to_average) {
- if (to_average.size() == 0) {
- (*this) = Vector_distances_in_diagram<F>();
- return;
- }
-
- size_t maximal_length_of_vector = 0;
- for (size_t i = 0; i != to_average.size(); ++i) {
- if (to_average[i]->sorted_vector_of_distances.size() > maximal_length_of_vector) {
- maximal_length_of_vector = to_average[i]->sorted_vector_of_distances.size();
- }
- }
-
- std::vector<double> av(maximal_length_of_vector, 0);
- for (size_t i = 0; i != to_average.size(); ++i) {
- for (size_t j = 0; j != to_average[i]->sorted_vector_of_distances.size(); ++j) {
- av[j] += to_average[i]->sorted_vector_of_distances[j];
- }
- }
-
- for (size_t i = 0; i != maximal_length_of_vector; ++i) {
- av[i] /= static_cast<double>(to_average.size());
- }
- this->sorted_vector_of_distances = av;
- this->where_to_cut = av.size();
-}
-
-template <typename F>
-double Vector_distances_in_diagram<F>::distance(const Vector_distances_in_diagram& second_, double power) const {
- bool dbg = false;
-
- if (dbg) {
- std::cerr << "Entering double Vector_distances_in_diagram<F>::distance( const Abs_Topological_data_with_distances* "
- "second , double power ) procedure \n";
- std::cerr << "Power : " << power << std::endl;
- std::cerr << "This : " << *this << std::endl;
- std::cerr << "second : " << second_ << std::endl;
- }
-
- double result = 0;
- for (size_t i = 0; i != std::min(this->sorted_vector_of_distances.size(), second_.sorted_vector_of_distances.size());
- ++i) {
- if (power == 1) {
- if (dbg) {
- std::cerr << "|" << this->sorted_vector_of_distances[i] << " - " << second_.sorted_vector_of_distances[i]
- << " | : " << fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i])
- << std::endl;
- }
- result += fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i]);
- } else {
- if (power < std::numeric_limits<double>::max()) {
- result += std::pow(fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i]), power);
- } else {
- // max norm
- if (result < fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i]))
- result = fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i]);
- }
- if (dbg) {
- std::cerr << "| " << this->sorted_vector_of_distances[i] << " - " << second_.sorted_vector_of_distances[i]
- << " : " << fabs(this->sorted_vector_of_distances[i] - second_.sorted_vector_of_distances[i])
- << std::endl;
- }
- }
- }
- if (this->sorted_vector_of_distances.size() != second_.sorted_vector_of_distances.size()) {
- if (this->sorted_vector_of_distances.size() > second_.sorted_vector_of_distances.size()) {
- for (size_t i = second_.sorted_vector_of_distances.size(); i != this->sorted_vector_of_distances.size(); ++i) {
- result += fabs(this->sorted_vector_of_distances[i]);
- }
- } else {
- // this->sorted_vector_of_distances.size() < second_.sorted_vector_of_distances.size()
- for (size_t i = this->sorted_vector_of_distances.size(); i != second_.sorted_vector_of_distances.size(); ++i) {
- result += fabs(second_.sorted_vector_of_distances[i]);
- }
- }
- }
-
- if (power != 1) {
- result = std::pow(result, (1.0 / power));
- }
- return result;
-}
-
-template <typename F>
-std::vector<double> Vector_distances_in_diagram<F>::vectorize(int number_of_function) const {
- if ((size_t)number_of_function > this->number_of_functions_for_vectorization)
- throw "Wrong index of a function in a method Vector_distances_in_diagram<F>::vectorize";
- if (number_of_function < 0) throw "Wrong index of a function in a method Vector_distances_in_diagram<F>::vectorize";
-
- std::vector<double> result(std::min((size_t)number_of_function, this->sorted_vector_of_distances.size()));
- for (size_t i = 0; i != std::min((size_t)number_of_function, this->sorted_vector_of_distances.size()); ++i) {
- result[i] = this->sorted_vector_of_distances[i];
- }
- return result;
-}
-
-template <typename F>
-void Vector_distances_in_diagram<F>::write_to_file(const char* filename) const {
- std::ofstream out;
- out.open(filename);
-
- for (size_t i = 0; i != this->sorted_vector_of_distances.size(); ++i) {
- out << this->sorted_vector_of_distances[i] << " ";
- }
-
- out.close();
-}
-
-template <typename F>
-void Vector_distances_in_diagram<F>::load_from_file(const char* filename) {
- std::ifstream in;
- in.open(filename);
- // check if the file exist.
- if (!in.good()) {
- std::cerr << "The file : " << filename << " do not exist. The program will now terminate \n";
- throw "The persistence landscape file do not exist. The program will now terminate \n";
- }
-
- double number;
- while (in >> number) {
- this->sorted_vector_of_distances.push_back(number);
- }
- in.close();
-}
-
-template <typename F>
-double Vector_distances_in_diagram<F>::compute_scalar_product(const Vector_distances_in_diagram& second_vector) const {
- double result = 0;
- for (size_t i = 0;
- i != std::min(this->sorted_vector_of_distances.size(), second_vector.sorted_vector_of_distances.size()); ++i) {
- result += this->sorted_vector_of_distances[i] * second_vector.sorted_vector_of_distances[i];
- }
- return result;
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // PERSISTENCE_VECTORS_H_
diff --git a/include/gudhi/Persistent_cohomology.h b/include/gudhi/Persistent_cohomology.h
deleted file mode 100644
index c51e47a5..00000000
--- a/include/gudhi/Persistent_cohomology.h
+++ /dev/null
@@ -1,769 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENT_COHOMOLOGY_H_
-#define PERSISTENT_COHOMOLOGY_H_
-
-#include <gudhi/Persistent_cohomology/Persistent_cohomology_column.h>
-#include <gudhi/Persistent_cohomology/Field_Zp.h>
-#include <gudhi/Simple_object_pool.h>
-
-#include <boost/intrusive/set.hpp>
-#include <boost/pending/disjoint_sets.hpp>
-#include <boost/intrusive/list.hpp>
-
-#include <map>
-#include <utility>
-#include <list>
-#include <vector>
-#include <set>
-#include <fstream> // std::ofstream
-#include <limits> // for numeric_limits<>
-#include <tuple>
-#include <algorithm>
-#include <string>
-#include <stdexcept> // for std::out_of_range
-
-namespace Gudhi {
-
-namespace persistent_cohomology {
-
-/** \brief Computes the persistent cohomology of a filtered complex.
- *
- * \ingroup persistent_cohomology
- *
- * The computation is implemented with a Compressed Annotation Matrix
- * (CAM)\cite DBLP:conf/esa/BoissonnatDM13,
- * and is adapted to the computation of Multi-Field Persistent Homology (MF)
- * \cite boissonnat:hal-00922572 .
- *
- * \implements PersistentHomology
- *
- */
-// TODO(CM): Memory allocation policy: classic, use a mempool, etc.
-template<class FilteredComplex, class CoefficientField>
-class Persistent_cohomology {
- public:
- typedef FilteredComplex Complex_ds;
- // Data attached to each simplex to interface with a Property Map.
- typedef typename Complex_ds::Simplex_key Simplex_key;
- typedef typename Complex_ds::Simplex_handle Simplex_handle;
- typedef typename Complex_ds::Filtration_value Filtration_value;
- typedef typename CoefficientField::Element Arith_element;
- // Compressed Annotation Matrix types:
- // Column type
- typedef Persistent_cohomology_column<Simplex_key, Arith_element> Column; // contains 1 set_hook
- // Cell type
- typedef typename Column::Cell Cell; // contains 2 list_hooks
- // Remark: constant_time_size must be false because base_hook_cam_h has auto_unlink link_mode
- typedef boost::intrusive::list<Cell,
- boost::intrusive::constant_time_size<false>,
- boost::intrusive::base_hook<base_hook_cam_h> > Hcell;
-
- typedef boost::intrusive::set<Column,
- boost::intrusive::constant_time_size<false> > Cam;
- // Sparse column type for the annotation of the boundary of an element.
- typedef std::vector<std::pair<Simplex_key, Arith_element> > A_ds_type;
- // Persistent interval type. The Arith_element field is used for the multi-field framework.
- typedef std::tuple<Simplex_handle, Simplex_handle, Arith_element> Persistent_interval;
-
- /** \brief Initializes the Persistent_cohomology class.
- *
- * @param[in] cpx Complex for which the persistent homology is computed.
- * cpx is a model of FilteredComplex
- * @exception std::out_of_range In case the number of simplices is more than Simplex_key type numeric limit.
- */
- explicit Persistent_cohomology(Complex_ds& cpx)
- : cpx_(&cpx),
- dim_max_(cpx.dimension()), // upper bound on the dimension of the simplices
- coeff_field_(), // initialize the field coefficient structure.
- num_simplices_(cpx_->num_simplices()), // num_simplices save to avoid to call thrice the function
- ds_rank_(num_simplices_), // union-find
- ds_parent_(num_simplices_), // union-find
- ds_repr_(num_simplices_, NULL), // union-find -> annotation vectors
- dsets_(&ds_rank_[0], &ds_parent_[0]), // union-find
- cam_(), // collection of annotation vectors
- zero_cocycles_(), // union-find -> Simplex_key of creator for 0-homology
- transverse_idx_(), // key -> row
- persistent_pairs_(),
- interval_length_policy(&cpx, 0),
- column_pool_(), // memory pools for the CAM
- cell_pool_() {
- if (cpx_->num_simplices() > std::numeric_limits<Simplex_key>::max()) {
- // num_simplices must be strictly lower than the limit, because a value is reserved for null_key.
- throw std::out_of_range("The number of simplices is more than Simplex_key type numeric limit.");
- }
- Simplex_key idx_fil = 0;
- for (auto sh : cpx_->filtration_simplex_range()) {
- cpx_->assign_key(sh, idx_fil);
- ++idx_fil;
- dsets_.make_set(cpx_->key(sh));
- }
- }
-
- /** \brief Initializes the Persistent_cohomology class.
- *
- * @param[in] cpx Complex for which the persistent homology is compiuted.
- * cpx is a model of FilteredComplex
- *
- * @param[in] persistence_dim_max if true, the persistent homology for the maximal dimension in the
- * complex is computed. If false, it is ignored. Default is false.
- */
- Persistent_cohomology(Complex_ds& cpx, bool persistence_dim_max)
- : Persistent_cohomology(cpx) {
- if (persistence_dim_max) {
- ++dim_max_;
- }
- }
-
- ~Persistent_cohomology() {
- // Clean the transversal lists
- for (auto & transverse_ref : transverse_idx_) {
- // Destruct all the cells
- transverse_ref.second.row_->clear_and_dispose([&](Cell*p){p->~Cell();});
- delete transverse_ref.second.row_;
- }
- }
-
- private:
- struct length_interval {
- length_interval(Complex_ds * cpx, Filtration_value min_length)
- : cpx_(cpx),
- min_length_(min_length) {
- }
-
- bool operator()(Simplex_handle sh1, Simplex_handle sh2) {
- return cpx_->filtration(sh2) - cpx_->filtration(sh1) > min_length_;
- }
-
- void set_length(Filtration_value new_length) {
- min_length_ = new_length;
- }
-
- Complex_ds * cpx_;
- Filtration_value min_length_;
- };
-
- public:
- /** \brief Initializes the coefficient field.*/
- void init_coefficients(int charac) {
- coeff_field_.init(charac);
- }
- /** \brief Initializes the coefficient field for multi-field persistent homology.*/
- void init_coefficients(int charac_min, int charac_max) {
- coeff_field_.init(charac_min, charac_max);
- }
-
- /** \brief Compute the persistent homology of the filtered simplicial
- * complex.
- *
- * @param[in] min_interval_length the computation discards all intervals of length
- * less or equal than min_interval_length
- *
- * Assumes that the filtration provided by the simplicial complex is
- * valid. Undefined behavior otherwise. */
- void compute_persistent_cohomology(Filtration_value min_interval_length = 0) {
- interval_length_policy.set_length(min_interval_length);
- // Compute all finite intervals
- for (auto sh : cpx_->filtration_simplex_range()) {
- int dim_simplex = cpx_->dimension(sh);
- switch (dim_simplex) {
- case 0:
- break;
- case 1:
- update_cohomology_groups_edge(sh);
- break;
- default:
- update_cohomology_groups(sh, dim_simplex);
- break;
- }
- }
- // Compute infinite intervals of dimension 0
- Simplex_key key;
- for (auto v_sh : cpx_->skeleton_simplex_range(0)) { // for all 0-dimensional simplices
- key = cpx_->key(v_sh);
-
- if (ds_parent_[key] == key // root of its tree
- && zero_cocycles_.find(key) == zero_cocycles_.end()) {
- persistent_pairs_.emplace_back(
- cpx_->simplex(key), cpx_->null_simplex(), coeff_field_.characteristic());
- }
- }
- for (auto zero_idx : zero_cocycles_) {
- persistent_pairs_.emplace_back(
- cpx_->simplex(zero_idx.second), cpx_->null_simplex(), coeff_field_.characteristic());
- }
- // Compute infinite interval of dimension > 0
- for (auto cocycle : transverse_idx_) {
- persistent_pairs_.emplace_back(
- cpx_->simplex(cocycle.first), cpx_->null_simplex(), cocycle.second.characteristics_);
- }
- }
-
- private:
- /** \brief Update the cohomology groups under the insertion of an edge.
- *
- * The 0-homology is maintained with a simple Union-Find data structure, which
- * explains the existance of a specific function of edge insertions. */
- void update_cohomology_groups_edge(Simplex_handle sigma) {
- Simplex_handle u, v;
- boost::tie(u, v) = cpx_->endpoints(sigma);
-
- Simplex_key ku = dsets_.find_set(cpx_->key(u));
- Simplex_key kv = dsets_.find_set(cpx_->key(v));
-
- if (ku != kv) { // Destroy a connected component
- dsets_.link(ku, kv);
- // Keys of the simplices which created the connected components containing
- // respectively u and v.
- Simplex_key idx_coc_u, idx_coc_v;
- auto map_it_u = zero_cocycles_.find(ku);
- // If the index of the cocycle representing the class is already ku.
- if (map_it_u == zero_cocycles_.end()) {
- idx_coc_u = ku;
- } else {
- idx_coc_u = map_it_u->second;
- }
-
- auto map_it_v = zero_cocycles_.find(kv);
- // If the index of the cocycle representing the class is already kv.
- if (map_it_v == zero_cocycles_.end()) {
- idx_coc_v = kv;
- } else {
- idx_coc_v = map_it_v->second;
- }
-
- if (cpx_->filtration(cpx_->simplex(idx_coc_u))
- < cpx_->filtration(cpx_->simplex(idx_coc_v))) { // Kill cocycle [idx_coc_v], which is younger.
- if (interval_length_policy(cpx_->simplex(idx_coc_v), sigma)) {
- persistent_pairs_.emplace_back(
- cpx_->simplex(idx_coc_v), sigma, coeff_field_.characteristic());
- }
- // Maintain the index of the 0-cocycle alive.
- if (kv != idx_coc_v) {
- zero_cocycles_.erase(map_it_v);
- }
- if (kv == dsets_.find_set(kv)) {
- if (ku != idx_coc_u) {
- zero_cocycles_.erase(map_it_u);
- }
- zero_cocycles_[kv] = idx_coc_u;
- }
- } else { // Kill cocycle [idx_coc_u], which is younger.
- if (interval_length_policy(cpx_->simplex(idx_coc_u), sigma)) {
- persistent_pairs_.emplace_back(
- cpx_->simplex(idx_coc_u), sigma, coeff_field_.characteristic());
- }
- // Maintain the index of the 0-cocycle alive.
- if (ku != idx_coc_u) {
- zero_cocycles_.erase(map_it_u);
- }
- if (ku == dsets_.find_set(ku)) {
- if (kv != idx_coc_v) {
- zero_cocycles_.erase(map_it_v);
- }
- zero_cocycles_[ku] = idx_coc_v;
- }
- }
- cpx_->assign_key(sigma, cpx_->null_key());
- } else if (dim_max_ > 1) { // If ku == kv, same connected component: create a 1-cocycle class.
- create_cocycle(sigma, coeff_field_.multiplicative_identity(), coeff_field_.characteristic());
- }
- }
-
- /*
- * Compute the annotation of the boundary of a simplex.
- */
- void annotation_of_the_boundary(
- std::map<Simplex_key, Arith_element> & map_a_ds, Simplex_handle sigma,
- int dim_sigma) {
- // traverses the boundary of sigma, keeps track of the annotation vectors,
- // with multiplicity. We used to sum the coefficients directly in
- // annotations_in_boundary by using a map, we now do it later.
- typedef std::pair<Column *, int> annotation_t;
-#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- thread_local
-#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- std::vector<annotation_t> annotations_in_boundary;
- annotations_in_boundary.clear();
- int sign = 1 - 2 * (dim_sigma % 2); // \in {-1,1} provides the sign in the
- // alternate sum in the boundary.
- Simplex_key key;
- Column * curr_col;
-
- for (auto sh : cpx_->boundary_simplex_range(sigma)) {
- key = cpx_->key(sh);
- if (key != cpx_->null_key()) { // A simplex with null_key is a killer, and have null annotation
- // Find its annotation vector
- curr_col = ds_repr_[dsets_.find_set(key)];
- if (curr_col != NULL) { // and insert it in annotations_in_boundary with multyiplicative factor "sign".
- annotations_in_boundary.emplace_back(curr_col, sign);
- }
- }
- sign = -sign;
- }
- // Place identical annotations consecutively so we can easily sum their multiplicities.
- std::sort(annotations_in_boundary.begin(), annotations_in_boundary.end(),
- [](annotation_t const& a, annotation_t const& b) { return a.first < b.first; });
-
- // Sum the annotations with multiplicity, using a map<key,coeff>
- // to represent a sparse vector.
- std::pair<typename std::map<Simplex_key, Arith_element>::iterator, bool> result_insert_a_ds;
-
- for (auto ann_it = annotations_in_boundary.begin(); ann_it != annotations_in_boundary.end(); /**/) {
- Column* col = ann_it->first;
- int mult = ann_it->second;
- while (++ann_it != annotations_in_boundary.end() && ann_it->first == col) {
- mult += ann_it->second;
- }
- // The following test is just a heuristic, it is not required, and it is fine that is misses p == 0.
- if (mult != coeff_field_.additive_identity()) { // For all columns in the boundary,
- for (auto cell_ref : col->col_) { // insert every cell in map_a_ds with multiplicity
- Arith_element w_y = coeff_field_.times(cell_ref.coefficient_, mult); // coefficient * multiplicity
-
- if (w_y != coeff_field_.additive_identity()) { // if != 0
- result_insert_a_ds = map_a_ds.insert(std::pair<Simplex_key, Arith_element>(cell_ref.key_, w_y));
- if (!(result_insert_a_ds.second)) { // if cell_ref.key_ already a Key in map_a_ds
- result_insert_a_ds.first->second = coeff_field_.plus_equal(result_insert_a_ds.first->second, w_y);
- if (result_insert_a_ds.first->second == coeff_field_.additive_identity()) {
- map_a_ds.erase(result_insert_a_ds.first);
- }
- }
- }
- }
- }
- }
- }
-
- /*
- * Update the cohomology groups under the insertion of a simplex.
- */
- void update_cohomology_groups(Simplex_handle sigma, int dim_sigma) {
-// Compute the annotation of the boundary of sigma:
- std::map<Simplex_key, Arith_element> map_a_ds;
- annotation_of_the_boundary(map_a_ds, sigma, dim_sigma);
-// Update the cohomology groups:
- if (map_a_ds.empty()) { // sigma is a creator in all fields represented in coeff_field_
- if (dim_sigma < dim_max_) {
- create_cocycle(sigma, coeff_field_.multiplicative_identity(),
- coeff_field_.characteristic());
- }
- } else { // sigma is a destructor in at least a field in coeff_field_
- // Convert map_a_ds to a vector
- A_ds_type a_ds; // admits reverse iterators
- for (auto map_a_ds_ref : map_a_ds) {
- a_ds.push_back(
- std::pair<Simplex_key, Arith_element>(map_a_ds_ref.first,
- map_a_ds_ref.second));
- }
-
- Arith_element inv_x, charac;
- Arith_element prod = coeff_field_.characteristic(); // Product of characteristic of the fields
- for (auto a_ds_rit = a_ds.rbegin();
- (a_ds_rit != a_ds.rend())
- && (prod != coeff_field_.multiplicative_identity()); ++a_ds_rit) {
- std::tie(inv_x, charac) = coeff_field_.inverse(a_ds_rit->second, prod);
-
- if (inv_x != coeff_field_.additive_identity()) {
- destroy_cocycle(sigma, a_ds, a_ds_rit->first, inv_x, charac);
- prod /= charac;
- }
- }
- if (prod != coeff_field_.multiplicative_identity()
- && dim_sigma < dim_max_) {
- create_cocycle(sigma, coeff_field_.multiplicative_identity(prod), prod);
- }
- }
- }
-
- /* \brief Create a new cocycle class.
- *
- * The class is created by the insertion of the simplex sigma.
- * The methods adds a cocycle, representing the new cocycle class,
- * to the matrix representing the cohomology groups.
- * The new cocycle has value 0 on every simplex except on sigma
- * where it worths 1.*/
- void create_cocycle(Simplex_handle sigma, Arith_element x,
- Arith_element charac) {
- Simplex_key key = cpx_->key(sigma);
- // Create a column containing only one cell,
- Column * new_col = column_pool_.construct(key);
- Cell * new_cell = cell_pool_.construct(key, x, new_col);
- new_col->col_.push_back(*new_cell);
- // and insert it in the matrix, in constant time thanks to the hint cam_.end().
- // Indeed *new_col has the biggest lexicographic value because key is the
- // biggest key used so far.
- cam_.insert(cam_.end(), *new_col);
- // Update the disjoint sets data structure.
- Hcell * new_hcell = new Hcell;
- new_hcell->push_back(*new_cell);
- transverse_idx_[key] = cocycle(charac, new_hcell); // insert the new row
- ds_repr_[key] = new_col;
- }
-
- /* \brief Destroy a cocycle class.
- *
- * The cocycle class is destroyed by the insertion of sigma.
- * The methods proceeds to a reduction of the matrix representing
- * the cohomology groups using Gauss pivoting. The reduction zeros-out
- * the row containing the cell with highest key in
- * a_ds, the annotation of the boundary of simplex sigma. This key
- * is "death_key".*/
- void destroy_cocycle(Simplex_handle sigma, A_ds_type const& a_ds,
- Simplex_key death_key, Arith_element inv_x,
- Arith_element charac) {
- // Create a finite persistent interval for which the interval exists
- if (interval_length_policy(cpx_->simplex(death_key), sigma)) {
- persistent_pairs_.emplace_back(cpx_->simplex(death_key) // creator
- , sigma // destructor
- , charac); // fields
- }
-
- auto death_key_row = transverse_idx_.find(death_key); // Find the beginning of the row.
- std::pair<typename Cam::iterator, bool> result_insert_cam;
-
- auto row_cell_it = death_key_row->second.row_->begin();
-
- while (row_cell_it != death_key_row->second.row_->end()) { // Traverse all cells in
- // the row at index death_key.
- Arith_element w = coeff_field_.times_minus(inv_x, row_cell_it->coefficient_);
-
- if (w != coeff_field_.additive_identity()) {
- Column * curr_col = row_cell_it->self_col_;
- ++row_cell_it;
- // Disconnect the column from the rows in the CAM.
- for (auto& col_cell : curr_col->col_) {
- col_cell.base_hook_cam_h::unlink();
- }
-
- // Remove the column from the CAM before modifying its value
- cam_.erase(cam_.iterator_to(*curr_col));
- // Proceed to the reduction of the column
- plus_equal_column(*curr_col, a_ds, w);
-
- if (curr_col->col_.empty()) { // If the column is null
- ds_repr_[curr_col->class_key_] = NULL;
- column_pool_.destroy(curr_col); // delete curr_col;
- } else {
- // Find whether the column obtained is already in the CAM
- result_insert_cam = cam_.insert(*curr_col);
- if (result_insert_cam.second) { // If it was not in the CAM before: insertion has succeeded
- for (auto& col_cell : curr_col->col_) {
- // re-establish the row links
- transverse_idx_[col_cell.key_].row_->push_front(col_cell);
- }
- } else { // There is already an identical column in the CAM:
- // merge two disjoint sets.
- dsets_.link(curr_col->class_key_,
- result_insert_cam.first->class_key_);
-
- Simplex_key key_tmp = dsets_.find_set(curr_col->class_key_);
- ds_repr_[key_tmp] = &(*(result_insert_cam.first));
- result_insert_cam.first->class_key_ = key_tmp;
- // intrusive containers don't own their elements, we have to release them manually
- curr_col->col_.clear_and_dispose([&](Cell*p){cell_pool_.destroy(p);});
- column_pool_.destroy(curr_col); // delete curr_col;
- }
- }
- } else {
- ++row_cell_it;
- } // If w == 0, pass.
- }
-
- // Because it is a killer simplex, set the data of sigma to null_key().
- if (charac == coeff_field_.characteristic()) {
- cpx_->assign_key(sigma, cpx_->null_key());
- }
- if (death_key_row->second.characteristics_ == charac) {
- delete death_key_row->second.row_;
- transverse_idx_.erase(death_key_row);
- } else {
- death_key_row->second.characteristics_ /= charac;
- }
- }
-
- /*
- * Assign: target <- target + w * other.
- */
- void plus_equal_column(Column & target, A_ds_type const& other // value_type is pair<Simplex_key,Arith_element>
- , Arith_element w) {
- auto target_it = target.col_.begin();
- auto other_it = other.begin();
- while (target_it != target.col_.end() && other_it != other.end()) {
- if (target_it->key_ < other_it->first) {
- ++target_it;
- } else {
- if (target_it->key_ > other_it->first) {
- Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first // key
- , coeff_field_.additive_identity(), &target));
-
- cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
-
- target.col_.insert(target_it, *cell_tmp);
-
- ++other_it;
- } else { // it1->key == it2->key
- // target_it->coefficient_ <- target_it->coefficient_ + other_it->second * w
- target_it->coefficient_ = coeff_field_.plus_times_equal(target_it->coefficient_, other_it->second, w);
- if (target_it->coefficient_ == coeff_field_.additive_identity()) {
- auto tmp_it = target_it;
- ++target_it;
- ++other_it; // iterators remain valid
- Cell * tmp_cell_ptr = &(*tmp_it);
- target.col_.erase(tmp_it); // removed from column
-
- cell_pool_.destroy(tmp_cell_ptr); // delete from memory
- } else {
- ++target_it;
- ++other_it;
- }
- }
- }
- }
- while (other_it != other.end()) {
- Cell * cell_tmp = cell_pool_.construct(Cell(other_it->first, coeff_field_.additive_identity(), &target));
- cell_tmp->coefficient_ = coeff_field_.plus_times_equal(cell_tmp->coefficient_, other_it->second, w);
- target.col_.insert(target.col_.end(), *cell_tmp);
-
- ++other_it;
- }
- }
-
- /*
- * Compare two intervals by length.
- */
- struct cmp_intervals_by_length {
- explicit cmp_intervals_by_length(Complex_ds * sc)
- : sc_(sc) {
- }
- bool operator()(const Persistent_interval & p1, const Persistent_interval & p2) {
- return (sc_->filtration(get < 1 > (p1)) - sc_->filtration(get < 0 > (p1))
- > sc_->filtration(get < 1 > (p2)) - sc_->filtration(get < 0 > (p2)));
- }
- Complex_ds * sc_;
- };
-
- public:
- /** \brief Output the persistence diagram in ostream.
- *
- * The file format is the following:
- * p1*...*pr dim b d
- *
- * where "dim" is the dimension of the homological feature,
- * b and d are respectively the birth and death of the feature and
- * p1*...*pr is the product of prime numbers pi such that the homology
- * feature exists in homology with Z/piZ coefficients.
- */
- void output_diagram(std::ostream& ostream = std::cout) {
- cmp_intervals_by_length cmp(cpx_);
- std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
- bool has_infinity = std::numeric_limits<Filtration_value>::has_infinity;
- for (auto pair : persistent_pairs_) {
- // Special case on windows, inf is "1.#INF" (cf. unitary tests and R package TDA)
- if (has_infinity && cpx_->filtration(get<1>(pair)) == std::numeric_limits<Filtration_value>::infinity()) {
- ostream << get<2>(pair) << " " << cpx_->dimension(get<0>(pair)) << " "
- << cpx_->filtration(get<0>(pair)) << " inf " << std::endl;
- } else {
- ostream << get<2>(pair) << " " << cpx_->dimension(get<0>(pair)) << " "
- << cpx_->filtration(get<0>(pair)) << " "
- << cpx_->filtration(get<1>(pair)) << " " << std::endl;
- }
- }
- }
-
- void write_output_diagram(std::string diagram_name) {
- std::ofstream diagram_out(diagram_name.c_str());
- cmp_intervals_by_length cmp(cpx_);
- std::sort(std::begin(persistent_pairs_), std::end(persistent_pairs_), cmp);
- bool has_infinity = std::numeric_limits<Filtration_value>::has_infinity;
- for (auto pair : persistent_pairs_) {
- // Special case on windows, inf is "1.#INF"
- if (has_infinity && cpx_->filtration(get<1>(pair)) == std::numeric_limits<Filtration_value>::infinity()) {
- diagram_out << cpx_->dimension(get<0>(pair)) << " "
- << cpx_->filtration(get<0>(pair)) << " inf" << std::endl;
- } else {
- diagram_out << cpx_->dimension(get<0>(pair)) << " "
- << cpx_->filtration(get<0>(pair)) << " "
- << cpx_->filtration(get<1>(pair)) << std::endl;
- }
- }
- }
-
- /** @brief Returns Betti numbers.
- * @return A vector of Betti numbers.
- */
- std::vector<int> betti_numbers() const {
- // Init Betti numbers vector with zeros until Simplicial complex dimension
- std::vector<int> betti_numbers(dim_max_, 0);
-
- for (auto pair : persistent_pairs_) {
- // Count never ended persistence intervals
- if (cpx_->null_simplex() == get<1>(pair)) {
- // Increment corresponding betti number
- betti_numbers[cpx_->dimension(get<0>(pair))] += 1;
- }
- }
- return betti_numbers;
- }
-
- /** @brief Returns the Betti number of the dimension passed by parameter.
- * @param[in] dimension The Betti number dimension to get.
- * @return Betti number of the given dimension
- *
- */
- int betti_number(int dimension) const {
- int betti_number = 0;
-
- for (auto pair : persistent_pairs_) {
- // Count never ended persistence intervals
- if (cpx_->null_simplex() == get<1>(pair)) {
- if (cpx_->dimension(get<0>(pair)) == dimension) {
- // Increment betti number found
- ++betti_number;
- }
- }
- }
- return betti_number;
- }
-
- /** @brief Returns the persistent Betti numbers.
- * @param[in] from The persistence birth limit to be added in the number \f$(persistent birth \leq from)\f$.
- * @param[in] to The persistence death limit to be added in the number \f$(persistent death > to)\f$.
- * @return A vector of persistent Betti numbers.
- */
- std::vector<int> persistent_betti_numbers(Filtration_value from, Filtration_value to) const {
- // Init Betti numbers vector with zeros until Simplicial complex dimension
- std::vector<int> betti_numbers(dim_max_, 0);
- for (auto pair : persistent_pairs_) {
- // Count persistence intervals that covers the given interval
- // null_simplex test : if the function is called with to=+infinity, we still get something useful. And it will
- // still work if we change the complex filtration function to reject null simplices.
- if (cpx_->filtration(get<0>(pair)) <= from &&
- (get<1>(pair) == cpx_->null_simplex() || cpx_->filtration(get<1>(pair)) > to)) {
- // Increment corresponding betti number
- betti_numbers[cpx_->dimension(get<0>(pair))] += 1;
- }
- }
- return betti_numbers;
- }
-
- /** @brief Returns the persistent Betti number of the dimension passed by parameter.
- * @param[in] dimension The Betti number dimension to get.
- * @param[in] from The persistence birth limit to be added in the number \f$(persistent birth \leq from)\f$.
- * @param[in] to The persistence death limit to be added in the number \f$(persistent death > to)\f$.
- * @return Persistent Betti number of the given dimension
- */
- int persistent_betti_number(int dimension, Filtration_value from, Filtration_value to) const {
- int betti_number = 0;
-
- for (auto pair : persistent_pairs_) {
- // Count persistence intervals that covers the given interval
- // null_simplex test : if the function is called with to=+infinity, we still get something useful. And it will
- // still work if we change the complex filtration function to reject null simplices.
- if (cpx_->filtration(get<0>(pair)) <= from &&
- (get<1>(pair) == cpx_->null_simplex() || cpx_->filtration(get<1>(pair)) > to)) {
- if (cpx_->dimension(get<0>(pair)) == dimension) {
- // Increment betti number found
- ++betti_number;
- }
- }
- }
- return betti_number;
- }
-
- /** @brief Returns the persistent pairs.
- * @return Persistent pairs
- *
- */
- const std::vector<Persistent_interval>& get_persistent_pairs() const {
- return persistent_pairs_;
- }
-
- /** @brief Returns persistence intervals for a given dimension.
- * @param[in] dimension Dimension to get the birth and death pairs from.
- * @return A vector of persistence intervals (birth and death) on a fixed dimension.
- */
- std::vector< std::pair< Filtration_value , Filtration_value > >
- intervals_in_dimension(int dimension) {
- std::vector< std::pair< Filtration_value , Filtration_value > > result;
- // auto && pair, to avoid unnecessary copying
- for (auto && pair : persistent_pairs_) {
- if (cpx_->dimension(get<0>(pair)) == dimension) {
- result.emplace_back(cpx_->filtration(get<0>(pair)), cpx_->filtration(get<1>(pair)));
- }
- }
- return result;
- }
-
- private:
- /*
- * Structure representing a cocycle.
- */
- struct cocycle {
- cocycle()
- : row_(nullptr),
- characteristics_() {
- }
- cocycle(Arith_element characteristics, Hcell * row)
- : row_(row),
- characteristics_(characteristics) {
- }
-
- Hcell * row_; // points to the corresponding row in the CAM
- Arith_element characteristics_; // product of field characteristics for which the cocycle exist
- };
-
- public:
- Complex_ds * cpx_;
- int dim_max_;
- CoefficientField coeff_field_;
- size_t num_simplices_;
-
- /* Disjoint sets data structure to link the model of FilteredComplex
- * with the compressed annotation matrix.
- * ds_rank_ is a property map Simplex_key -> int, ds_parent_ is a property map
- * Simplex_key -> simplex_key_t */
- std::vector<int> ds_rank_;
- std::vector<Simplex_key> ds_parent_;
- std::vector<Column *> ds_repr_;
- boost::disjoint_sets<int *, Simplex_key *> dsets_;
- /* The compressed annotation matrix fields.*/
- Cam cam_;
- /* Dictionary establishing the correspondance between the Simplex_key of
- * the root vertex in the union-find ds and the Simplex_key of the vertex which
- * created the connected component as a 0-dimension homology feature.*/
- std::map<Simplex_key, Simplex_key> zero_cocycles_;
- /* Key -> row. */
- std::map<Simplex_key, cocycle> transverse_idx_;
- /* Persistent intervals. */
- std::vector<Persistent_interval> persistent_pairs_;
- length_interval interval_length_policy;
-
- Simple_object_pool<Column> column_pool_;
- Simple_object_pool<Cell> cell_pool_;
-};
-
-} // namespace persistent_cohomology
-
-} // namespace Gudhi
-
-#endif // PERSISTENT_COHOMOLOGY_H_
diff --git a/include/gudhi/Persistent_cohomology/Field_Zp.h b/include/gudhi/Persistent_cohomology/Field_Zp.h
deleted file mode 100644
index e98b4bb4..00000000
--- a/include/gudhi/Persistent_cohomology/Field_Zp.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENT_COHOMOLOGY_FIELD_ZP_H_
-#define PERSISTENT_COHOMOLOGY_FIELD_ZP_H_
-
-#include <utility>
-#include <vector>
-
-namespace Gudhi {
-
-namespace persistent_cohomology {
-
-/** \brief Structure representing the coefficient field \f$\mathbb{Z}/p\mathbb{Z}\f$
- *
- * \implements CoefficientField
- * \ingroup persistent_cohomology
- */
-class Field_Zp {
- public:
- typedef int Element;
-
- Field_Zp()
- : Prime(0),
- inverse_() {
- }
-
- void init(int charac) {
- assert(charac > 0); // division by zero + non negative values
- Prime = charac;
- inverse_.clear();
- inverse_.reserve(charac);
- inverse_.push_back(0);
- for (int i = 1; i < Prime; ++i) {
- int inv = 1;
- while (((inv * i) % Prime) != 1)
- ++inv;
- inverse_.push_back(inv);
- }
- }
-
- /** Set x <- x + w * y*/
- Element plus_times_equal(const Element& x, const Element& y, const Element& w) {
- assert(Prime > 0); // division by zero + non negative values
- Element result = (x + w * y) % Prime;
- if (result < 0)
- result += Prime;
- return result;
- }
-
-// operator= defined on Element
-
- /** Returns y * w */
- Element times(const Element& y, const Element& w) {
- return plus_times_equal(0, y, (Element)w);
- }
-
- Element plus_equal(const Element& x, const Element& y) {
- return plus_times_equal(x, y, (Element)1);
- }
-
- /** \brief Returns the additive idendity \f$0_{\Bbbk}\f$ of the field.*/
- Element additive_identity() const {
- return 0;
- }
- /** \brief Returns the multiplicative identity \f$1_{\Bbbk}\f$ of the field.*/
- Element multiplicative_identity(Element = 0) const {
- return 1;
- }
- /** Returns the inverse in the field. Modifies P. ??? */
- std::pair<Element, Element> inverse(Element x, Element P) {
- return std::pair<Element, Element>(inverse_[x], P);
- } // <------ return the product of field characteristic for which x is invertible
-
- /** Returns -x * y.*/
- Element times_minus(Element x, Element y) {
- assert(Prime > 0); // division by zero + non negative values
- Element out = (-x * y) % Prime;
- return (out < 0) ? out + Prime : out;
- }
-
- /** \brief Returns the characteristic \f$p\f$ of the field.*/
- int characteristic() const {
- return Prime;
- }
-
- private:
- int Prime;
- /** Property map Element -> Element, which associate to an element its inverse in the field.*/
- std::vector<Element> inverse_;
-};
-
-} // namespace persistent_cohomology
-
-} // namespace Gudhi
-
-#endif // PERSISTENT_COHOMOLOGY_FIELD_ZP_H_
diff --git a/include/gudhi/Persistent_cohomology/Multi_field.h b/include/gudhi/Persistent_cohomology/Multi_field.h
deleted file mode 100644
index 2bae8654..00000000
--- a/include/gudhi/Persistent_cohomology/Multi_field.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_
-#define PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_
-
-#include <gmpxx.h>
-
-#include <vector>
-#include <utility>
-
-namespace Gudhi {
-
-namespace persistent_cohomology {
-
-/** \brief Structure representing coefficients in a set of finite fields simultaneously
- * using the chinese remainder theorem.
- *
- * \implements CoefficientField
- * \ingroup persistent_cohomology
-
- * Details on the algorithms may be found in \cite boissonnat:hal-00922572
- */
-class Multi_field {
- public:
- typedef mpz_class Element;
-
- Multi_field()
- : prod_characteristics_(0),
- mult_id_all(0),
- add_id_all(0) {
- }
-
- /* Initialize the multi-field. The generation of prime numbers might fail with
- * a very small probability.*/
- void init(int min_prime, int max_prime) {
- if (max_prime < 2) {
- std::cerr << "There is no prime less than " << max_prime << std::endl;
- }
- if (min_prime > max_prime) {
- std::cerr << "No prime in [" << min_prime << ":" << max_prime << "]"
- << std::endl;
- }
- // fill the list of prime numbers
- int curr_prime = min_prime;
- mpz_t tmp_prime;
- mpz_init_set_ui(tmp_prime, min_prime);
- // test if min_prime is prime
- int is_prime = mpz_probab_prime_p(tmp_prime, 25); // probabilistic primality test
-
- if (is_prime == 0) { // min_prime is composite
- mpz_nextprime(tmp_prime, tmp_prime);
- curr_prime = mpz_get_ui(tmp_prime);
- }
-
- while (curr_prime <= max_prime) {
- primes_.push_back(curr_prime);
- mpz_nextprime(tmp_prime, tmp_prime);
- curr_prime = mpz_get_ui(tmp_prime);
- }
- mpz_clear(tmp_prime);
- // set m to primorial(bound_prime)
- prod_characteristics_ = 1;
- for (auto p : primes_) {
- prod_characteristics_ *= p;
- }
-
- // Uvect_
- Element Ui;
- Element tmp_elem;
- for (auto p : primes_) {
- assert(p > 0); // division by zero + non negative values
- tmp_elem = prod_characteristics_ / p;
- // Element tmp_elem_bis = 10;
- mpz_powm_ui(tmp_elem.get_mpz_t(), tmp_elem.get_mpz_t(), p - 1,
- prod_characteristics_.get_mpz_t());
- Uvect_.push_back(tmp_elem);
- }
- mult_id_all = 0;
- for (auto uvect : Uvect_) {
- assert(prod_characteristics_ > 0); // division by zero + non negative values
- mult_id_all = (mult_id_all + uvect) % prod_characteristics_;
- }
- }
-
- /** \brief Returns the additive idendity \f$0_{\Bbbk}\f$ of the field.*/
- const Element& additive_identity() const {
- return add_id_all;
- }
- /** \brief Returns the multiplicative identity \f$1_{\Bbbk}\f$ of the field.*/
- const Element& multiplicative_identity() const {
- return mult_id_all;
- } // 1 everywhere
-
- Element multiplicative_identity(Element Q) {
- if (Q == prod_characteristics_) {
- return multiplicative_identity();
- }
-
- assert(prod_characteristics_ > 0); // division by zero + non negative values
- Element mult_id = 0;
- for (unsigned int idx = 0; idx < primes_.size(); ++idx) {
- assert(primes_[idx] > 0); // division by zero + non negative values
- if ((Q % primes_[idx]) == 0) {
- mult_id = (mult_id + Uvect_[idx]) % prod_characteristics_;
- }
- }
- return mult_id;
- }
-
- /** Returns y * w */
- Element times(const Element& y, const Element& w) {
- return plus_times_equal(0, y, w);
- }
-
- Element plus_equal(const Element& x, const Element& y) {
- return plus_times_equal(x, y, (Element)1);
- }
-
- /** \brief Returns the characteristic \f$p\f$ of the field.*/
- const Element& characteristic() const {
- return prod_characteristics_;
- }
-
- /** Returns the inverse in the field. Modifies P. ??? */
- std::pair<Element, Element> inverse(Element x, Element QS) {
- Element QR;
- mpz_gcd(QR.get_mpz_t(), x.get_mpz_t(), QS.get_mpz_t()); // QR <- gcd(x,QS)
- if (QR == QS)
- return std::pair<Element, Element>(additive_identity(), multiplicative_identity()); // partial inverse is 0
- Element QT = QS / QR;
- Element inv_qt;
- mpz_invert(inv_qt.get_mpz_t(), x.get_mpz_t(), QT.get_mpz_t());
-
- assert(prod_characteristics_ > 0); // division by zero + non negative values
- return { (inv_qt * multiplicative_identity(QT)) % prod_characteristics_, QT };
- }
- /** Returns -x * y.*/
- Element times_minus(const Element& x, const Element& y) {
- assert(prod_characteristics_ > 0); // division by zero + non negative values
- /* This assumes that (x*y)%pc cannot be zero, but Field_Zp has specific code for the 0 case ??? */
- return prod_characteristics_ - ((x * y) % prod_characteristics_);
- }
-
- /** Set x <- x + w * y*/
- Element plus_times_equal(const Element& x, const Element& y, const Element& w) {
- assert(prod_characteristics_ > 0); // division by zero + non negative values
- Element result = (x + w * y) % prod_characteristics_;
- if (result < 0)
- result += prod_characteristics_;
- return result;
- }
-
- Element prod_characteristics_; // product of characteristics of the fields
- // represented by the multi-field class
- std::vector<int> primes_; // all the characteristics of the fields
- std::vector<Element> Uvect_;
- Element mult_id_all;
- const Element add_id_all;
-};
-
-} // namespace persistent_cohomology
-
-} // namespace Gudhi
-
-#endif // PERSISTENT_COHOMOLOGY_MULTI_FIELD_H_
diff --git a/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h b/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h
deleted file mode 100644
index de6c0750..00000000
--- a/include/gudhi/Persistent_cohomology/Persistent_cohomology_column.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_
-#define PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_
-
-#include <boost/intrusive/set.hpp>
-#include <boost/intrusive/list.hpp>
-
-#include <list>
-
-namespace Gudhi {
-
-namespace persistent_cohomology {
-
-template<typename SimplexKey, typename ArithmeticElement>
-class Persistent_cohomology_column;
-
-struct cam_h_tag;
-// for horizontal traversal in the CAM
-struct cam_v_tag;
-// for vertical traversal in the CAM
-
-typedef boost::intrusive::list_base_hook<boost::intrusive::tag<cam_h_tag>,
- boost::intrusive::link_mode<boost::intrusive::auto_unlink> // allows .unlink()
-> base_hook_cam_h;
-
-typedef boost::intrusive::list_base_hook<boost::intrusive::tag<cam_v_tag>,
- boost::intrusive::link_mode<boost::intrusive::normal_link> // faster hook, less safe
-> base_hook_cam_v;
-
-/** \internal
- * \brief
- *
- */
-template<typename SimplexKey, typename ArithmeticElement>
-class Persistent_cohomology_cell : public base_hook_cam_h,
- public base_hook_cam_v {
- public:
- template<class T1, class T2> friend class Persistent_cohomology;
- friend class Persistent_cohomology_column<SimplexKey, ArithmeticElement>;
-
- typedef Persistent_cohomology_column<SimplexKey, ArithmeticElement> Column;
-
- Persistent_cohomology_cell(SimplexKey key, ArithmeticElement x,
- Column * self_col)
- : key_(key),
- coefficient_(x),
- self_col_(self_col) {
- }
-
- SimplexKey key_;
- ArithmeticElement coefficient_;
- Column * self_col_;
-};
-
-/*
- * \brief Sparse column for the Compressed Annotation Matrix.
- *
- * The non-zero coefficients of the column are stored in a
- * boost::intrusive::list. Contains a hook to be stored in a
- * boost::intrusive::set.
- *
- * Movable but not Copyable.
- */
-template<typename SimplexKey, typename ArithmeticElement>
-class Persistent_cohomology_column : public boost::intrusive::set_base_hook<
- boost::intrusive::link_mode<boost::intrusive::normal_link> > {
- template<class T1, class T2> friend class Persistent_cohomology;
-
- public:
- typedef Persistent_cohomology_cell<SimplexKey, ArithmeticElement> Cell;
- typedef boost::intrusive::list<Cell,
- boost::intrusive::constant_time_size<false>,
- boost::intrusive::base_hook<base_hook_cam_v> > Col_type;
-
- /** \brief Creates an empty column.*/
- explicit Persistent_cohomology_column(SimplexKey key)
- : col_(),
- class_key_(key) {}
-
- /** \brief Returns true iff the column is null.*/
- bool is_null() const {
- return col_.empty();
- }
- /** \brief Returns the key of the representative simplex of
- * the set of simplices having this column as annotation vector
- * in the compressed annotation matrix.*/
- SimplexKey class_key() const {
- return class_key_;
- }
-
- /** \brief Lexicographic comparison of two columns.*/
- friend bool operator<(const Persistent_cohomology_column& c1,
- const Persistent_cohomology_column& c2) {
- typename Col_type::const_iterator it1 = c1.col_.begin();
- typename Col_type::const_iterator it2 = c2.col_.begin();
- while (it1 != c1.col_.end() && it2 != c2.col_.end()) {
- if (it1->key_ == it2->key_) {
- if (it1->coefficient_ == it2->coefficient_) {
- ++it1;
- ++it2;
- } else {
- return it1->coefficient_ < it2->coefficient_;
- }
- } else {
- return it1->key_ < it2->key_;
- }
- }
- return (it2 != c2.col_.end());
- }
-
- Col_type col_;
- SimplexKey class_key_;
-};
-
-} // namespace persistent_cohomology
-
-} // namespace Gudhi
-
-#endif // PERSISTENT_COHOMOLOGY_PERSISTENT_COHOMOLOGY_COLUMN_H_
diff --git a/include/gudhi/Point.h b/include/gudhi/Point.h
deleted file mode 100644
index 345a8465..00000000
--- a/include/gudhi/Point.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef POINT_H_
-#define POINT_H_
-
-#include <cmath>
-#include <vector>
-#include <cassert>
-#include <cstddef>
-#include <initializer_list>
-
-class Point_d {
- public:
- Point_d(size_t dim = 3) : coords_(dim, 0) { }
-
- Point_d(const Point_d& other) : coords_(other.coords_) { }
-
- Point_d(const std::initializer_list<double>& list) : coords_(list) { }
-
- template<typename CoordsIt>
- Point_d(CoordsIt begin, CoordsIt end) : coords_(begin, end) { }
-
- size_t dimension() const {
- return coords_.size();
- }
-
- double x() const {
- return coords_[0];
- }
-
- double y() const {
- return coords_[1];
- }
-
- double z() const {
- return coords_[2];
- }
-
- double& x() {
- return coords_[0];
- }
-
- double& y() {
- return coords_[1];
- }
-
- double& z() {
- return coords_[2];
- }
-
- std::vector<double>::const_iterator begin() const {
- return coords_.begin();
- }
-
- std::vector<double>::const_iterator end() const {
- return coords_.end();
- }
-
- double& operator[](unsigned i) {
- return coords_[i];
- }
-
- const double& operator[](unsigned i) const {
- return coords_[i];
- }
-
- double squared_norm() const {
- double res = 0;
- for (auto x : coords_)
- res += x * x;
- return res;
- }
-
- friend double squared_dist(const Point_d& p1, const Point_d& p2) {
- assert(p1.dimension() == p2.dimension());
- double res = 0;
- for (unsigned i = 0; i < p1.coords_.size(); ++i)
- res += (p1[i] - p2[i])*(p1[i] - p2[i]);
- return res;
- }
-
- /**
- * dot product
- */
- double operator*(const Point_d& other) const {
- assert(dimension() == other.dimension());
- double res = 0;
- for (unsigned i = 0; i < coords_.size(); ++i)
- res += coords_[i] * other[i];
- return res;
- }
-
- /**
- * only if points have dimension 3
- */
- Point_d cross_product(const Point_d& other) {
- assert(dimension() == 3 && other.dimension() == 3);
- Point_d res(3);
- res[0] = (*this)[1] * other[2] - (*this)[2] * other[1];
- res[1] = (*this)[2] * other[0] - (*this)[0] * other[2];
- res[2] = (*this)[0] * other[1] - (*this)[1] * other[0];
- return res;
- }
-
- Point_d operator+(const Point_d& other) const {
- assert(dimension() == other.dimension());
- Point_d res(dimension());
- for (unsigned i = 0; i < coords_.size(); ++i)
- res[i] = (*this)[i] + other[i];
- return res;
- }
-
- Point_d operator*(double lambda) const {
- Point_d res(dimension());
- for (unsigned i = 0; i < coords_.size(); ++i)
- res[i] = (*this)[i] * lambda;
- return res;
- }
-
- Point_d operator/(double lambda) const {
- Point_d res(dimension());
- for (unsigned i = 0; i < coords_.size(); ++i)
- res[i] = (*this)[i] / lambda;
- return res;
- }
-
- Point_d operator-(const Point_d& other) const {
- assert(dimension() == other.dimension());
- Point_d res(dimension());
- for (unsigned i = 0; i < coords_.size(); ++i)
- res[i] = (*this)[i] - other[i];
- return res;
- }
-
- friend Point_d unit_normal(const Point_d& p1, const Point_d& p2, const Point_d& p3) {
- assert(p1.dimension() == 3);
- assert(p2.dimension() == 3);
- assert(p3.dimension() == 3);
- Point_d p1p2 = p2 - p1;
- Point_d p1p3 = p3 - p1;
- Point_d res(p1p2.cross_product(p1p3));
- return res / std::sqrt(res.squared_norm());
- }
-
- private:
- std::vector<double> coords_;
-};
-
-#endif // POINT_H_
diff --git a/include/gudhi/Points_3D_off_io.h b/include/gudhi/Points_3D_off_io.h
deleted file mode 100644
index 704f73a7..00000000
--- a/include/gudhi/Points_3D_off_io.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef POINTS_3D_OFF_IO_H_
-#define POINTS_3D_OFF_IO_H_
-
-#include <gudhi/Off_reader.h>
-
-#include <string>
-#include <vector>
-#include <fstream>
-#include <map>
-
-namespace Gudhi {
-
-/**
- * @brief OFF file visitor implementation according to Off_reader in order to read points from an OFF file.
- */
-template<typename Point_3>
-class Points_3D_off_visitor_reader {
- private:
- std::vector<Point_3> point_cloud_;
- bool valid_;
-
- public:
- /** @brief Off_reader visitor init implementation.
- *
- * The init parameters are set from OFF file header.
- * Dimension value is required and the value must be 3.
- *
- * @param[in] dim space dimension of vertices.
- * @param[in] num_vertices number of vertices in the OFF file (not used).
- * @param[in] num_faces number of faces in the OFF file (not used).
- * @param[in] num_edges number of edges in the OFF file (not used).
- */
- void init(int dim, int num_vertices, int num_faces, int num_edges) {
-#ifdef DEBUG_TRACES
- std::cout << "Points_3D_off_visitor_reader::init - dim=" << dim << " - num_vertices=" <<
- num_vertices << " - num_faces=" << num_faces << " - num_edges=" << num_edges << std::endl;
-#endif // DEBUG_TRACES
- if (dim == 3) {
- valid_ = true;
- } else {
- valid_ = false;
- std::cerr << "Points_3D_off_reader::Points_3D_off_reader cannot read OFF files in dimension " << dim << "\n";
- }
-
- if (num_faces > 0) {
- std::cerr << "Points_3D_off_visitor_reader::init faces are not taken into account from OFF file for Points.\n";
- }
- if (num_edges > 0) {
- std::cerr << "Points_3D_off_visitor_reader::init edges are not taken into account from OFF file for Points.\n";
- }
- }
-
- /** @brief Off_reader visitor point implementation.
- *
- * The point function is called on each vertex line from OFF file.
- * This function inserts the vertex in the vector of points.
- *
- * @param[in] point vector of vertex coordinates.
- *
- * @details
- * Point_3 must have a constructor with the following form:
- *
- * @code template<class InputIterator > Point_3::Point_3(double x, double y, double z) @endcode
- */
- void point(const std::vector<double>& point) {
- if (valid_) {
-#ifdef DEBUG_TRACES
- std::cout << "Points_3D_off_visitor_reader::point ";
- for (auto coordinate : point) {
- std::cout << coordinate << " | ";
- }
- std::cout << std::endl;
-#endif // DEBUG_TRACES
- // Fill the point cloud
- point_cloud_.push_back(Point_3(point[0], point[1], point[2]));
- }
- }
-
- // Off_reader visitor maximal_face implementation - Only points are read
-
- void maximal_face(const std::vector<int>& face) { }
-
- // Off_reader visitor done implementation - Only points are read
-
- void done() { }
-
- /** @brief Point cloud getter.
- *
- * @return The point cloud.
- */
- const std::vector<Point_3>& get_point_cloud() const {
- return point_cloud_;
- }
-
- /** @brief Returns if the OFF file read operation was successful or not.
- *
- * @return OFF file read status.
- */
- bool is_valid() const {
- return valid_;
- }
-};
-
-/**
- * \@brief OFF file reader implementation in order to read dimension 3 points from an OFF file.
- *
- * @details
- * This class is using the Points_3D_off_visitor_reader to visit the OFF file according to Off_reader.
- *
- * Point_3 must have a constructor with the following form:
- *
- * @code template<class InputIterator > Point_3::Point_3(double x, double y, double z) @endcode
- *
- * @section point3doffioexample Example
- *
- * This example loads points from an OFF file and builds a vector of CGAL points in dimension 3.
- * Then, it is asked to display the points.
- *
- * @include common/example_CGAL_3D_points_off_reader.cpp
- *
- * When launching:
- *
- * @code $> ./cgal3Doffreader ../../data/points/tore3D_300.off
- * @endcode
- *
- * the program output is:
- *
- * @include common/cgal3Doffreader_result.txt
- */
-template<typename Point_3>
-class Points_3D_off_reader {
- public:
- /** @brief Reads the OFF file and constructs a vector of points from the points
- * that are in the OFF file.
- *
- * @param[in] name_file OFF file to read.
- *
- * @post Check with is_valid() function to see if read operation was successful.
- */
- Points_3D_off_reader(const std::string& name_file)
- : valid_(false) {
- std::ifstream stream(name_file);
- if (stream.is_open()) {
- Off_reader off_reader(stream);
- Points_3D_off_visitor_reader<Point_3> off_visitor;
- valid_ = off_reader.read(off_visitor);
- valid_ = valid_ && off_visitor.is_valid();
- if (valid_) {
- point_cloud = off_visitor.get_point_cloud();
- }
- } else {
- std::cerr << "Points_3D_off_reader::Points_3D_off_reader could not open file " << name_file << "\n";
- }
- }
-
- /** @brief Returns if the OFF file read operation was successful or not.
- *
- * @return OFF file read status.
- */
- bool is_valid() const {
- return valid_;
- }
-
- /** @brief Point cloud getter.
- *
- * @return point_cloud.
- */
- const std::vector<Point_3>& get_point_cloud() const {
- return point_cloud;
- }
-
- private:
- /** @brief point_cloud.*/
- std::vector<Point_3> point_cloud;
- /** @brief OFF file read status.*/
- bool valid_;
-};
-
-} // namespace Gudhi
-
-#endif // POINTS_3D_OFF_IO_H_
diff --git a/include/gudhi/Points_off_io.h b/include/gudhi/Points_off_io.h
deleted file mode 100644
index 38029658..00000000
--- a/include/gudhi/Points_off_io.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef POINTS_OFF_IO_H_
-#define POINTS_OFF_IO_H_
-
-#include <gudhi/Off_reader.h>
-
-#include <string>
-#include <vector>
-#include <fstream>
-#include <map>
-
-namespace Gudhi {
-
-/**
- * \brief OFF file visitor implementation according to Off_reader in order to read points from an OFF file.
- */
-template<typename Point_d>
-class Points_off_visitor_reader {
- private:
- std::vector<Point_d> point_cloud;
-
- public:
- /** \brief Off_reader visitor init implementation.
- *
- * The init parameters are set from OFF file header.
- * Dimension value is required in order to construct a vector of points.
- *
- * @param[in] dim space dimension of vertices.
- * @param[in] num_vertices number of vertices in the OFF file (not used).
- * @param[in] num_faces number of faces in the OFF file (not used).
- * @param[in] num_edges number of edges in the OFF file (not used).
- */
- void init(int dim, int num_vertices, int num_faces, int num_edges) {
-#ifdef DEBUG_TRACES
- std::cout << "Points_off_visitor_reader::init - dim=" << dim << " - num_vertices=" <<
- num_vertices << " - num_faces=" << num_faces << " - num_edges=" << num_edges << std::endl;
-#endif // DEBUG_TRACES
- if (num_faces > 0) {
- std::cerr << "Points_off_visitor_reader::init faces are not taken into account from OFF file for Points.\n";
- }
- if (num_edges > 0) {
- std::cerr << "Points_off_visitor_reader::init edges are not taken into account from OFF file for Points.\n";
- }
- }
-
- /** @brief Off_reader visitor point implementation.
- *
- * The point function is called on each vertex line from OFF file.
- * This function inserts the vertex in the vector of points.
- *
- * @param[in] point vector of vertex coordinates.
- *
- * @details
- * Point_d must have a constructor with the following form:
- *
- * @code template<class InputIterator > Point_d::Point_d(InputIterator first, InputIterator last) @endcode
- *
- */
- void point(const std::vector<double>& point) {
-#ifdef DEBUG_TRACES
- std::cout << "Points_off_visitor_reader::point ";
- for (auto coordinate : point) {
- std::cout << coordinate << " | ";
- }
- std::cout << std::endl;
-#endif // DEBUG_TRACES
- // Fill the point cloud
- point_cloud.push_back(Point_d(point.begin(), point.end()));
- }
-
- // Off_reader visitor maximal_face implementation - Only points are read
- void maximal_face(const std::vector<int>& face) { }
-
- // Off_reader visitor done implementation - Only points are read
- void done() { }
-
- /** \brief Point cloud getter.
- *
- * @return point_cloud.
- */
- const std::vector<Point_d>& get_point_cloud() const {
- return point_cloud;
- }
-};
-
-/**
- * \brief OFF file reader implementation in order to read points from an OFF file.
- *
- * This class is using the Points_off_visitor_reader to visit the OFF file according to Off_reader.
- *
- * Point_d must have a constructor with the following form:
- *
- * \code template<class InputIterator > Point_d::Point_d(int d, InputIterator first, InputIterator last) \endcode
- *
- * where d is the point dimension.
- *
- * \section pointoffioexample Example
- *
- * This example loads points from an OFF file and builds a vector of points (vector of double).
- * Then, it is asked to display the points.
- *
- * \include common/example_vector_double_points_off_reader.cpp
- *
- * When launching:
- *
- * \code $> ./vector_double_off_reader ../../data/points/alphacomplexdoc.off
- * \endcode
- *
- * the program outputs a file ../../data/points/alphacomplexdoc.off.txt:
- *
- * \include common/vectordoubleoffreader_result.txt
- */
-template<typename Point_d>
-class Points_off_reader {
- public:
- /** \brief Reads the OFF file and constructs a vector of points from the points
- * that are in the OFF file.
- *
- * @param[in] name_file OFF file to read.
- *
- * \post Check with is_valid() function to see if read operation was successful.
- */
- Points_off_reader(const std::string& name_file)
- : valid_(false) {
- std::ifstream stream(name_file);
- if (stream.is_open()) {
- Off_reader off_reader(stream);
- Points_off_visitor_reader<Point_d> off_visitor;
- valid_ = off_reader.read(off_visitor);
- if (valid_) {
- point_cloud = off_visitor.get_point_cloud();
- }
- } else {
- std::cerr << "Points_off_reader::Points_off_reader could not open file " << name_file << "\n";
- }
- }
-
- /** \brief Returns if the OFF file read operation was successful or not.
- *
- * @return OFF file read status.
- */
- bool is_valid() const {
- return valid_;
- }
-
- /** \brief Point cloud getter.
- *
- * @return point_cloud.
- */
- const std::vector<Point_d>& get_point_cloud() const {
- return point_cloud;
- }
-
- private:
- /** \brief point_cloud.*/
- std::vector<Point_d> point_cloud;
- /** \brief OFF file read status.*/
- bool valid_;
-};
-
-} // namespace Gudhi
-
-#endif // POINTS_OFF_IO_H_
diff --git a/include/gudhi/Rips_complex.h b/include/gudhi/Rips_complex.h
deleted file mode 100644
index f0fe57f4..00000000
--- a/include/gudhi/Rips_complex.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria, Pawel Dlotko, Vincent Rouvreau
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef RIPS_COMPLEX_H_
-#define RIPS_COMPLEX_H_
-
-#include <gudhi/Debug_utils.h>
-#include <gudhi/graph_simplicial_complex.h>
-
-#include <boost/graph/adjacency_list.hpp>
-
-#include <iostream>
-#include <vector>
-#include <map>
-#include <string>
-#include <limits> // for numeric_limits
-#include <utility> // for pair<>
-
-
-namespace Gudhi {
-
-namespace rips_complex {
-
-/**
- * \class Rips_complex
- * \brief Rips complex data structure.
- *
- * \ingroup rips_complex
- *
- * \details
- * The data structure is a one skeleton graph, or Rips graph, containing edges when the edge length is less or equal
- * to a given threshold. Edge length is computed from a user given point cloud with a given distance function, or a
- * distance matrix.
- *
- * \tparam Filtration_value is the type used to store the filtration values of the simplicial complex.
- */
-template<typename Filtration_value>
-class Rips_complex {
- public:
- /**
- * \brief Type of the one skeleton graph stored inside the Rips complex structure.
- */
- typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS
- , boost::property < vertex_filtration_t, Filtration_value >
- , boost::property < edge_filtration_t, Filtration_value >> OneSkeletonGraph;
-
- private:
- typedef int Vertex_handle;
-
- public:
- /** \brief Rips_complex constructor from a list of points.
- *
- * @param[in] points Range of points.
- * @param[in] threshold Rips value.
- * @param[in] distance distance function that returns a `Filtration_value` from 2 given points.
- *
- * \tparam ForwardPointRange must be a range for which `std::begin` and `std::end` return input iterators on a
- * point.
- *
- * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where
- * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`.
- */
- template<typename ForwardPointRange, typename Distance >
- Rips_complex(const ForwardPointRange& points, Filtration_value threshold, Distance distance) {
- compute_proximity_graph(points, threshold, distance);
- }
-
- /** \brief Rips_complex constructor from a distance matrix.
- *
- * @param[in] distance_matrix Range of distances.
- * @param[in] threshold Rips value.
- *
- * \tparam DistanceMatrix must have a `size()` method and on which `distance_matrix[i][j]` returns
- * the distance between points \f$i\f$ and \f$j\f$ as long as \f$ 0 \leqslant i < j \leqslant
- * distance\_matrix.size().\f$
- */
- template<typename DistanceMatrix>
- Rips_complex(const DistanceMatrix& distance_matrix, Filtration_value threshold) {
- compute_proximity_graph(boost::irange((size_t)0, distance_matrix.size()), threshold,
- [&](size_t i, size_t j){return distance_matrix[j][i];});
- }
-
- /** \brief Initializes the simplicial complex from the Rips graph and expands it until a given maximal
- * dimension.
- *
- * \tparam SimplicialComplexForRips must meet `SimplicialComplexForRips` concept.
- *
- * @param[in] complex SimplicialComplexForRips to be created.
- * @param[in] dim_max graph expansion for Rips until this given maximal dimension.
- * @exception std::invalid_argument In debug mode, if `complex.num_vertices()` does not return 0.
- *
- */
- template <typename SimplicialComplexForRips>
- void create_complex(SimplicialComplexForRips& complex, int dim_max) {
- GUDHI_CHECK(complex.num_vertices() == 0,
- std::invalid_argument("Rips_complex::create_complex - simplicial complex is not empty"));
-
- // insert the proximity graph in the simplicial complex
- complex.insert_graph(rips_skeleton_graph_);
- // expand the graph until dimension dim_max
- complex.expansion(dim_max);
- }
-
- private:
- /** \brief Computes the proximity graph of the points.
- *
- * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the
- * distance function between points u and v is smaller than threshold.
- *
- * \tparam ForwardPointRange furnishes `.begin()` and `.end()`
- * methods.
- *
- * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where
- * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`.
- */
- template< typename ForwardPointRange, typename Distance >
- void compute_proximity_graph(const ForwardPointRange& points, Filtration_value threshold,
- Distance distance) {
- std::vector< std::pair< Vertex_handle, Vertex_handle > > edges;
- std::vector< Filtration_value > edges_fil;
-
- // Compute the proximity graph of the points.
- // If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the
- // distance function between points u and v is smaller than threshold.
- // --------------------------------------------------------------------------------------------
- // Creates the vector of edges and its filtration values (returned by distance function)
- Vertex_handle idx_u = 0;
- for (auto it_u = std::begin(points); it_u != std::end(points); ++it_u, ++idx_u) {
- Vertex_handle idx_v = idx_u + 1;
- for (auto it_v = it_u + 1; it_v != std::end(points); ++it_v, ++idx_v) {
- Filtration_value fil = distance(*it_u, *it_v);
- if (fil <= threshold) {
- edges.emplace_back(idx_u, idx_v);
- edges_fil.push_back(fil);
- }
- }
- }
-
- // --------------------------------------------------------------------------------------------
- // Creates the proximity graph from edges and sets the property with the filtration value.
- // Number of points is labeled from 0 to idx_u-1
- // --------------------------------------------------------------------------------------------
- // Do not use : rips_skeleton_graph_ = OneSkeletonGraph(...) -> deep copy of the graph (boost graph is not
- // move-enabled)
- rips_skeleton_graph_.~OneSkeletonGraph();
- new(&rips_skeleton_graph_)OneSkeletonGraph(edges.begin(), edges.end(), edges_fil.begin(), idx_u);
-
- auto vertex_prop = boost::get(vertex_filtration_t(), rips_skeleton_graph_);
-
- using vertex_iterator = typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator;
- vertex_iterator vi, vi_end;
- for (std::tie(vi, vi_end) = boost::vertices(rips_skeleton_graph_);
- vi != vi_end; ++vi) {
- boost::put(vertex_prop, *vi, 0.);
- }
- }
-
- private:
- OneSkeletonGraph rips_skeleton_graph_;
-};
-
-} // namespace rips_complex
-
-} // namespace Gudhi
-
-#endif // RIPS_COMPLEX_H_
diff --git a/include/gudhi/Simple_object_pool.h b/include/gudhi/Simple_object_pool.h
deleted file mode 100644
index 47283521..00000000
--- a/include/gudhi/Simple_object_pool.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Marc Glisse
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLE_OBJECT_POOL_H_
-#define SIMPLE_OBJECT_POOL_H_
-
-#include <boost/pool/pool.hpp>
-#include <utility>
-
-namespace Gudhi {
-
-/** \private
- * This is a simpler version of boost::object_pool, that requires
- * that users explicitly destroy all objects. This lets the
- * performance scale much better, see
- * https://svn.boost.org/trac/boost/ticket/3789 .
- */
-template <class T>
-class Simple_object_pool : protected boost::pool<boost::default_user_allocator_malloc_free> {
- protected:
- typedef boost::pool<boost::default_user_allocator_malloc_free> Base;
- typedef T* pointer;
-
- Base& base() {
- return *this;
- }
-
- Base const& base()const {
- return *this;
- }
-
- public:
- typedef T element_type;
- typedef boost::default_user_allocator_malloc_free user_allocator;
- typedef typename Base::size_type size_type;
- typedef typename Base::difference_type difference_type;
-
- template<class...U>
- Simple_object_pool(U&&...u) : Base(sizeof (T), std::forward<U>(u)...) { }
-
- template<class...U>
- pointer construct(U&&...u) {
- void* p = base().malloc BOOST_PREVENT_MACRO_SUBSTITUTION();
- assert(p);
- try {
- new(p) T(std::forward<U>(u)...);
- } catch (...) {
- base().free BOOST_PREVENT_MACRO_SUBSTITUTION(p);
- throw;
- }
- return static_cast<pointer> (p);
- }
-
- void destroy(pointer p) {
- p->~T();
- base().free BOOST_PREVENT_MACRO_SUBSTITUTION(p);
- }
-};
-
-} // namespace Gudhi
-
-#endif // SIMPLE_OBJECT_POOL_H_
diff --git a/include/gudhi/Simplex_tree.h b/include/gudhi/Simplex_tree.h
deleted file mode 100644
index 3ab23c12..00000000
--- a/include/gudhi/Simplex_tree.h
+++ /dev/null
@@ -1,1483 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLEX_TREE_H_
-#define SIMPLEX_TREE_H_
-
-#include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h>
-#include <gudhi/Simplex_tree/Simplex_tree_siblings.h>
-#include <gudhi/Simplex_tree/Simplex_tree_iterators.h>
-#include <gudhi/Simplex_tree/indexing_tag.h>
-
-#include <gudhi/reader_utils.h>
-#include <gudhi/graph_simplicial_complex.h>
-#include <gudhi/Debug_utils.h>
-
-#include <boost/container/flat_map.hpp>
-#include <boost/iterator/transform_iterator.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/range/adaptor/reversed.hpp>
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_sort.h>
-#endif
-
-#include <utility>
-#include <vector>
-#include <functional> // for greater<>
-#include <stdexcept>
-#include <limits> // Inf
-#include <initializer_list>
-#include <algorithm> // for std::max
-#include <cstdint> // for std::uint32_t
-#include <iterator> // for std::distance
-
-namespace Gudhi {
-
-struct Simplex_tree_options_full_featured;
-
-/**
- * \class Simplex_tree Simplex_tree.h gudhi/Simplex_tree.h
- * \brief Simplex Tree data structure for representing simplicial complexes.
- *
- * \details Every simplex \f$[v_0, \cdots ,v_d]\f$ admits a canonical orientation
- * induced by the order relation on vertices \f$ v_0 < \cdots < v_d \f$.
- *
- * Details may be found in \cite boissonnatmariasimplextreealgorithmica.
- *
- * \implements FilteredComplex
- *
- */
-
-template<typename SimplexTreeOptions = Simplex_tree_options_full_featured>
-class Simplex_tree {
- public:
- typedef SimplexTreeOptions Options;
- typedef typename Options::Indexing_tag Indexing_tag;
- /** \brief Type for the value of the filtration function.
- *
- * Must be comparable with <. */
- typedef typename Options::Filtration_value Filtration_value;
- /** \brief Key associated to each simplex.
- *
- * Must be an integer type. */
- typedef typename Options::Simplex_key Simplex_key;
- /** \brief Type for the vertex handle.
- *
- * Must be a signed integer type. It admits a total order <. */
- typedef typename Options::Vertex_handle Vertex_handle;
-
- /* Type of node in the simplex tree. */
- typedef Simplex_tree_node_explicit_storage<Simplex_tree> Node;
- /* Type of dictionary Vertex_handle -> Node for traversing the simplex tree. */
- // Note: this wastes space when Vertex_handle is 32 bits and Node is aligned on 64 bits. It would be better to use a
- // flat_set (with our own comparator) where we can control the layout of the struct (put Vertex_handle and
- // Simplex_key next to each other).
- typedef typename boost::container::flat_map<Vertex_handle, Node> Dictionary;
-
- /* \brief Set of nodes sharing a same parent in the simplex tree. */
- /* \brief Set of nodes sharing a same parent in the simplex tree. */
- typedef Simplex_tree_siblings<Simplex_tree, Dictionary> Siblings;
-
- struct Key_simplex_base_real {
- Key_simplex_base_real() : key_(-1) {}
- void assign_key(Simplex_key k) { key_ = k; }
- Simplex_key key() const { return key_; }
- private:
- Simplex_key key_;
- };
- struct Key_simplex_base_dummy {
- Key_simplex_base_dummy() {}
- // Undefined so it will not link
- void assign_key(Simplex_key);
- Simplex_key key() const;
- };
- typedef typename std::conditional<Options::store_key, Key_simplex_base_real, Key_simplex_base_dummy>::type
- Key_simplex_base;
-
- struct Filtration_simplex_base_real {
- Filtration_simplex_base_real() : filt_(0) {}
- void assign_filtration(Filtration_value f) { filt_ = f; }
- Filtration_value filtration() const { return filt_; }
- private:
- Filtration_value filt_;
- };
- struct Filtration_simplex_base_dummy {
- Filtration_simplex_base_dummy() {}
- void assign_filtration(Filtration_value GUDHI_CHECK_code(f)) { GUDHI_CHECK(f == 0, "filtration value specified for a complex that does not store them"); }
- Filtration_value filtration() const { return 0; }
- };
- typedef typename std::conditional<Options::store_filtration, Filtration_simplex_base_real,
- Filtration_simplex_base_dummy>::type Filtration_simplex_base;
-
- public:
- /** \brief Handle type to a simplex contained in the simplicial complex represented
- * by the simplex tree. */
- typedef typename Dictionary::iterator Simplex_handle;
-
- private:
- typedef typename Dictionary::iterator Dictionary_it;
- typedef typename Dictionary_it::value_type Dit_value_t;
-
- struct return_first {
- Vertex_handle operator()(const Dit_value_t& p_sh) const {
- return p_sh.first;
- }
- };
-
- public:
- /** \name Range and iterator types
- *
- * The naming convention is Container_content_(iterator/range). A Container_content_range is
- * essentially an object on which the methods begin() and end() can be called. They both return
- * an object of type Container_content_iterator, and allow the traversal of the range
- * [ begin();end() ).
- * @{ */
-
- /** \brief Iterator over the vertices of the simplicial complex.
- *
- * 'value_type' is Vertex_handle. */
- typedef boost::transform_iterator<return_first, Dictionary_it> Complex_vertex_iterator;
- /** \brief Range over the vertices of the simplicial complex. */
- typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
- /** \brief Iterator over the vertices of a simplex.
- *
- * 'value_type' is Vertex_handle. */
- typedef Simplex_tree_simplex_vertex_iterator<Simplex_tree> Simplex_vertex_iterator;
- /** \brief Range over the vertices of a simplex. */
- typedef boost::iterator_range<Simplex_vertex_iterator> Simplex_vertex_range;
- /** \brief Range over the cofaces of a simplex. */
- typedef std::vector<Simplex_handle> Cofaces_simplex_range;
- /** \brief Iterator over the simplices of the boundary of a simplex.
- *
- * 'value_type' is Simplex_handle. */
- typedef Simplex_tree_boundary_simplex_iterator<Simplex_tree> Boundary_simplex_iterator;
- /** \brief Range over the simplices of the boundary of a simplex. */
- typedef boost::iterator_range<Boundary_simplex_iterator> Boundary_simplex_range;
- /** \brief Iterator over the simplices of the simplicial complex.
- *
- * 'value_type' is Simplex_handle. */
- typedef Simplex_tree_complex_simplex_iterator<Simplex_tree> Complex_simplex_iterator;
- /** \brief Range over the simplices of the simplicial complex. */
- typedef boost::iterator_range<Complex_simplex_iterator> Complex_simplex_range;
- /** \brief Iterator over the simplices of the skeleton of the simplicial complex, for a given
- * dimension.
- *
- * 'value_type' is Simplex_handle. */
- typedef Simplex_tree_skeleton_simplex_iterator<Simplex_tree> Skeleton_simplex_iterator;
- /** \brief Range over the simplices of the skeleton of the simplicial complex, for a given
- * dimension. */
- typedef boost::iterator_range<Skeleton_simplex_iterator> Skeleton_simplex_range;
- /** \brief Range over the simplices of the simplicial complex, ordered by the filtration. */
- typedef std::vector<Simplex_handle> Filtration_simplex_range;
- /** \brief Iterator over the simplices of the simplicial complex, ordered by the filtration.
- *
- * 'value_type' is Simplex_handle. */
- typedef typename Filtration_simplex_range::const_iterator Filtration_simplex_iterator;
-
- /* @} */ // end name range and iterator types
- /** \name Range and iterator methods
- * @{ */
-
- /** \brief Returns a range over the vertices of the simplicial complex.
- * The order is increasing according to < on Vertex_handles.*/
- Complex_vertex_range complex_vertex_range() {
- return Complex_vertex_range(
- boost::make_transform_iterator(root_.members_.begin(), return_first()),
- boost::make_transform_iterator(root_.members_.end(), return_first()));
- }
-
- /** \brief Returns a range over the simplices of the simplicial complex.
- *
- * In the Simplex_tree, the tree is traverse in a depth-first fashion.
- * Consequently, simplices are ordered according to lexicographic order on the list of
- * Vertex_handles of a simplex, read in increasing < order for Vertex_handles. */
- Complex_simplex_range complex_simplex_range() {
- return Complex_simplex_range(Complex_simplex_iterator(this),
- Complex_simplex_iterator());
- }
-
- /** \brief Returns a range over the simplices of the dim-skeleton of the simplicial complex.
- *
- * The \f$d\f$-skeleton of a simplicial complex \f$\mathbf{K}\f$ is the simplicial complex containing the
- * simplices of \f$\mathbf{K}\f$ of dimension at most \f$d\f$.
- *
- * @param[in] dim The maximal dimension of the simplices in the skeleton.
- *
- * The simplices are ordered according to lexicographic order on the list of
- * Vertex_handles of a simplex, read in increasing < order for Vertex_handles. */
- Skeleton_simplex_range skeleton_simplex_range(int dim) {
- return Skeleton_simplex_range(Skeleton_simplex_iterator(this, dim),
- Skeleton_simplex_iterator());
- }
-
- /** \brief Returns a range over the simplices of the simplicial complex,
- * in the order of the filtration.
- *
- * The filtration is a monotonic function \f$ f: \mathbf{K} \rightarrow \mathbb{R} \f$, i.e. if two simplices
- * \f$\tau\f$ and \f$\sigma\f$ satisfy \f$\tau \subseteq \sigma\f$ then
- * \f$f(\tau) \leq f(\sigma)\f$.
- *
- * The method returns simplices ordered according to increasing filtration values. Ties are
- * resolved by considering inclusion relation (subsimplices appear before their cofaces). If two
- * simplices have same filtration value but are not comparable w.r.t. inclusion, lexicographic
- * order is used.
- *
- * The filtration must be valid. If the filtration has not been initialized yet, the
- * method initializes it (i.e. order the simplices). If the complex has changed since the last time the filtration
- * was initialized, please call `initialize_filtration()` to recompute it. */
- Filtration_simplex_range const& filtration_simplex_range(Indexing_tag = Indexing_tag()) {
- if (filtration_vect_.empty()) {
- initialize_filtration();
- }
- return filtration_vect_;
- }
-
- /** \brief Returns a range over the vertices of a simplex.
- *
- * The order in which the vertices are visited is the decreasing order for < on Vertex_handles,
- * which is consequenlty
- * equal to \f$(-1)^{\text{dim} \sigma}\f$ the canonical orientation on the simplex.
- */
- Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) {
- assert(sh != null_simplex()); // Empty simplex
- return Simplex_vertex_range(Simplex_vertex_iterator(this, sh),
- Simplex_vertex_iterator(this));
- }
-
- /** \brief Returns a range over the simplices of the boundary of a simplex.
- *
- * The boundary of a simplex is the set of codimension \f$1\f$ subsimplices of the simplex.
- * If the simplex is \f$[v_0, \cdots ,v_d]\f$, with canonical orientation
- * induced by \f$ v_0 < \cdots < v_d \f$, the iterator enumerates the
- * simplices of the boundary in the order:
- * \f$[v_0,\cdots,\widehat{v_i},\cdots,v_d]\f$ for \f$i\f$ from \f$0\f$ to \f$d\f$,
- * where \f$\widehat{v_i}\f$ means that the vertex \f$v_i\f$ is omitted.
- *
- * We note that the alternate sum of the simplices given by the iterator
- * gives \f$(-1)^{\text{dim} \sigma}\f$ the chains corresponding to the boundary
- * of the simplex.
- *
- * @param[in] sh Simplex for which the boundary is computed. */
- template<class SimplexHandle>
- Boundary_simplex_range boundary_simplex_range(SimplexHandle sh) {
- return Boundary_simplex_range(Boundary_simplex_iterator(this, sh),
- Boundary_simplex_iterator(this));
- }
-
- /** @} */ // end range and iterator methods
- /** \name Constructor/Destructor
- * @{ */
-
- /** \brief Constructs an empty simplex tree. */
- Simplex_tree()
- : null_vertex_(-1),
- root_(nullptr, null_vertex_),
- filtration_vect_(),
- dimension_(-1) { }
-
- /** \brief User-defined copy constructor reproduces the whole tree structure. */
- Simplex_tree(const Simplex_tree& simplex_source)
- : null_vertex_(simplex_source.null_vertex_),
- root_(nullptr, null_vertex_ , simplex_source.root_.members_),
- filtration_vect_(),
- dimension_(simplex_source.dimension_) {
- auto root_source = simplex_source.root_;
- rec_copy(&root_, &root_source);
- }
-
- /** \brief depth first search, inserts simplices when reaching a leaf. */
- void rec_copy(Siblings *sib, Siblings *sib_source) {
- for (auto sh = sib->members().begin(), sh_source = sib_source->members().begin();
- sh != sib->members().end(); ++sh, ++sh_source) {
- if (has_children(sh_source)) {
- Siblings * newsib = new Siblings(sib, sh_source->first);
- newsib->members_.reserve(sh_source->second.children()->members().size());
- for (auto & child : sh_source->second.children()->members())
- newsib->members_.emplace_hint(newsib->members_.end(), child.first, Node(newsib, child.second.filtration()));
- rec_copy(newsib, sh_source->second.children());
- sh->second.assign_children(newsib);
- }
- }
- }
-
- /** \brief User-defined move constructor moves the whole tree structure. */
- Simplex_tree(Simplex_tree && old)
- : null_vertex_(std::move(old.null_vertex_)),
- root_(std::move(old.root_)),
- filtration_vect_(std::move(old.filtration_vect_)),
- dimension_(std::move(old.dimension_)) {
- old.dimension_ = -1;
- old.root_ = Siblings(nullptr, null_vertex_);
- }
-
- /** \brief Destructor; deallocates the whole tree structure. */
- ~Simplex_tree() {
- for (auto sh = root_.members().begin(); sh != root_.members().end(); ++sh) {
- if (has_children(sh)) {
- rec_delete(sh->second.children());
- }
- }
- }
- /** @} */ // end constructor/destructor
- private:
- // Recursive deletion
- void rec_delete(Siblings * sib) {
- for (auto sh = sib->members().begin(); sh != sib->members().end(); ++sh) {
- if (has_children(sh)) {
- rec_delete(sh->second.children());
- }
- }
- delete sib;
- }
-
- public:
- /** \brief Checks if two simplex trees are equal. */
- bool operator==(Simplex_tree& st2) {
- if ((null_vertex_ != st2.null_vertex_) ||
- (dimension_ != st2.dimension_))
- return false;
- return rec_equal(&root_, &st2.root_);
- }
-
- /** \brief Checks if two simplex trees are different. */
- bool operator!=(Simplex_tree& st2) {
- return (!(*this == st2));
- }
-
- private:
- /** rec_equal: Checks recursively whether or not two simplex trees are equal, using depth first search. */
- bool rec_equal(Siblings* s1, Siblings* s2) {
- if (s1->members().size() != s2->members().size())
- return false;
- for (auto sh1 = s1->members().begin(), sh2 = s2->members().begin();
- (sh1 != s1->members().end() && sh2 != s2->members().end()); ++sh1, ++sh2) {
- if (sh1->first != sh2->first || sh1->second.filtration() != sh2->second.filtration())
- return false;
- if (has_children(sh1) != has_children(sh2))
- return false;
- // Recursivity on children only if both have children
- else if (has_children(sh1))
- if (!rec_equal(sh1->second.children(), sh2->second.children()))
- return false;
- }
- return true;
- }
-
- public:
- /** \brief Returns the key associated to a simplex.
- *
- * The filtration must be initialized.
- * \pre SimplexTreeOptions::store_key
- */
- static Simplex_key key(Simplex_handle sh) {
- return sh->second.key();
- }
-
- /** \brief Returns the simplex that has index idx in the filtration.
- *
- * The filtration must be initialized.
- * \pre SimplexTreeOptions::store_key
- */
- Simplex_handle simplex(Simplex_key idx) const {
- return filtration_vect_[idx];
- }
-
- /** \brief Returns the filtration value of a simplex.
- *
- * Called on the null_simplex, it returns infinity.
- * If SimplexTreeOptions::store_filtration is false, returns 0.
- */
- static Filtration_value filtration(Simplex_handle sh) {
- if (sh != null_simplex()) {
- return sh->second.filtration();
- } else {
- return std::numeric_limits<Filtration_value>::infinity();
- }
- }
-
- /** \brief Sets the filtration value of a simplex.
- * \exception std::invalid_argument In debug mode, if sh is a null_simplex.
- */
- void assign_filtration(Simplex_handle sh, Filtration_value fv) {
- GUDHI_CHECK(sh != null_simplex(),
- std::invalid_argument("Simplex_tree::assign_filtration - cannot assign filtration on null_simplex"));
- sh->second.assign_filtration(fv);
- }
-
- /** \brief Returns a Simplex_handle different from all Simplex_handles
- * associated to the simplices in the simplicial complex.
- *
- * One can call filtration(null_simplex()). */
- static Simplex_handle null_simplex() {
- return Dictionary_it(nullptr);
- }
-
- /** \brief Returns a key different for all keys associated to the
- * simplices of the simplicial complex. */
- static Simplex_key null_key() {
- return -1;
- }
-
- /** \brief Returns a Vertex_handle different from all Vertex_handles associated
- * to the vertices of the simplicial complex. */
- Vertex_handle null_vertex() const {
- return null_vertex_;
- }
-
- /** \brief Returns the number of vertices in the complex. */
- size_t num_vertices() const {
- return root_.members_.size();
- }
-
- public:
- /** \brief returns the number of simplices in the simplex_tree. */
- size_t num_simplices() {
- return num_simplices(&root_);
- }
-
- private:
- /** \brief returns the number of simplices in the simplex_tree. */
- size_t num_simplices(Siblings * sib) {
- auto sib_begin = sib->members().begin();
- auto sib_end = sib->members().end();
- size_t simplices_number = sib_end - sib_begin;
- for (auto sh = sib_begin; sh != sib_end; ++sh) {
- if (has_children(sh)) {
- simplices_number += num_simplices(sh->second.children());
- }
- }
- return simplices_number;
- }
-
- public:
- /** \brief Returns the dimension of a simplex.
- *
- * Must be different from null_simplex().*/
- int dimension(Simplex_handle sh) {
- Siblings * curr_sib = self_siblings(sh);
- int dim = 0;
- while (curr_sib != nullptr) {
- ++dim;
- curr_sib = curr_sib->oncles();
- }
- return dim - 1;
- }
-
- /** \brief Returns an upper bound on the dimension of the simplicial complex. */
- int upper_bound_dimension() const {
- return dimension_;
- }
-
- /** \brief Returns the dimension of the simplicial complex.
- \details This function is not constant time because it can recompute dimension if required (can be triggered by
- `remove_maximal_simplex()` or `prune_above_filtration()`).
- */
- int dimension() {
- if (dimension_to_be_lowered_)
- lower_upper_bound_dimension();
- return dimension_;
- }
-
- /** \brief Returns true if the node in the simplex tree pointed by
- * sh has children.*/
- template<class SimplexHandle>
- bool has_children(SimplexHandle sh) const {
- // Here we rely on the root using null_vertex(), which cannot match any real vertex.
- return (sh->second.children()->parent() == sh->first);
- }
-
- /** \brief Given a range of Vertex_handles, returns the Simplex_handle
- * of the simplex in the simplicial complex containing the corresponding
- * vertices. Return null_simplex() if the simplex is not in the complex.
- *
- * The type InputVertexRange must be a range of <CODE>Vertex_handle</CODE>
- * on which we can call std::begin() function
- */
- template<class InputVertexRange = std::initializer_list<Vertex_handle>>
- Simplex_handle find(const InputVertexRange & s) {
- auto first = std::begin(s);
- auto last = std::end(s);
-
- if (first == last)
- return null_simplex(); // ----->>
-
- // Copy before sorting
- std::vector<Vertex_handle> copy(first, last);
- std::sort(std::begin(copy), std::end(copy));
- return find_simplex(copy);
- }
-
- private:
- /** Find function, with a sorted range of vertices. */
- Simplex_handle find_simplex(const std::vector<Vertex_handle> & simplex) {
- Siblings * tmp_sib = &root_;
- Dictionary_it tmp_dit;
- auto vi = simplex.begin();
- if (Options::contiguous_vertices) {
- // Equivalent to the first iteration of the normal loop
- GUDHI_CHECK(contiguous_vertices(), "non-contiguous vertices");
- Vertex_handle v = *vi++;
- if(v < 0 || v >= static_cast<Vertex_handle>(root_.members_.size()))
- return null_simplex();
- tmp_dit = root_.members_.begin() + v;
- if (vi == simplex.end())
- return tmp_dit;
- if (!has_children(tmp_dit))
- return null_simplex();
- tmp_sib = tmp_dit->second.children();
- }
- for (;;) {
- tmp_dit = tmp_sib->members_.find(*vi++);
- if (tmp_dit == tmp_sib->members_.end())
- return null_simplex();
- if (vi == simplex.end())
- return tmp_dit;
- if (!has_children(tmp_dit))
- return null_simplex();
- tmp_sib = tmp_dit->second.children();
- }
- }
-
- /** \brief Returns the Simplex_handle corresponding to the 0-simplex
- * representing the vertex with Vertex_handle v. */
- Simplex_handle find_vertex(Vertex_handle v) {
- if (Options::contiguous_vertices) {
- assert(contiguous_vertices());
- return root_.members_.begin() + v;
- } else {
- return root_.members_.find(v);
- }
- }
-
- public:
- /** \private \brief Test if the vertices have contiguous numbering: 0, 1, etc. */
- bool contiguous_vertices() const {
- if (root_.members_.empty()) return true;
- if (root_.members_.begin()->first != 0) return false;
- if (std::prev(root_.members_.end())->first != static_cast<Vertex_handle>(root_.members_.size() - 1)) return false;
- return true;
- }
-
- private:
- /** \brief Inserts a simplex represented by a vector of vertex.
- * @param[in] simplex vector of Vertex_handles, representing the vertices of the new simplex. The vector must be
- * sorted by increasing vertex handle order.
- * @param[in] filtration the filtration value assigned to the new simplex.
- * @return If the new simplex is inserted successfully (i.e. it was not in the
- * simplicial complex yet) the bool is set to true and the Simplex_handle is the handle assigned
- * to the new simplex.
- * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion
- * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration',
- * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the
- * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to
- * null_simplex.
- *
- */
- std::pair<Simplex_handle, bool> insert_vertex_vector(const std::vector<Vertex_handle>& simplex,
- Filtration_value filtration) {
- Siblings * curr_sib = &root_;
- std::pair<Simplex_handle, bool> res_insert;
- auto vi = simplex.begin();
- for (; vi != simplex.end() - 1; ++vi) {
- GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
- res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
- if (!(has_children(res_insert.first))) {
- res_insert.first->second.assign_children(new Siblings(curr_sib, *vi));
- }
- curr_sib = res_insert.first->second.children();
- }
- GUDHI_CHECK(*vi != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
- res_insert = curr_sib->members_.emplace(*vi, Node(curr_sib, filtration));
- if (!res_insert.second) {
- // if already in the complex
- if (res_insert.first->second.filtration() > filtration) {
- // if filtration value modified
- res_insert.first->second.assign_filtration(filtration);
- return res_insert;
- }
- // if filtration value unchanged
- return std::pair<Simplex_handle, bool>(null_simplex(), false);
- }
- // otherwise the insertion has succeeded - size is a size_type
- if (static_cast<int>(simplex.size()) - 1 > dimension_) {
- // Update dimension if needed
- dimension_ = static_cast<int>(simplex.size()) - 1;
- }
- return res_insert;
- }
-
- public:
- /** \brief Insert a simplex, represented by a range of Vertex_handles, in the simplicial complex.
- *
- * @param[in] simplex range of Vertex_handles, representing the vertices of the new simplex
- * @param[in] filtration the filtration value assigned to the new simplex.
- * @return If the new simplex is inserted successfully (i.e. it was not in the
- * simplicial complex yet) the bool is set to true and the Simplex_handle is the handle assigned
- * to the new simplex.
- * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion
- * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration',
- * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the
- * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to
- * null_simplex.
- *
- * All subsimplices do not necessary need to be already in the simplex tree to proceed to an
- * insertion. However, the property of being a simplicial complex will be violated. This allows
- * us to insert a stream of simplices contained in a simplicial complex without considering any
- * order on them.
- *
- * The filtration value
- * assigned to the new simplex must preserve the monotonicity of the filtration.
- *
- * The type InputVertexRange must be a range for which .begin() and
- * .end() return input iterators, with 'value_type' Vertex_handle. */
- template<class InputVertexRange = std::initializer_list<Vertex_handle>>
- std::pair<Simplex_handle, bool> insert_simplex(const InputVertexRange & simplex,
- Filtration_value filtration = 0) {
- auto first = std::begin(simplex);
- auto last = std::end(simplex);
-
- if (first == last)
- return std::pair<Simplex_handle, bool>(null_simplex(), true); // ----->>
-
- // Copy before sorting
- std::vector<Vertex_handle> copy(first, last);
- std::sort(std::begin(copy), std::end(copy));
- return insert_vertex_vector(copy, filtration);
- }
-
- /** \brief Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of
- * Vertex_handles, in the simplicial complex.
- *
- * @param[in] Nsimplex range of Vertex_handles, representing the vertices of the new N-simplex
- * @param[in] filtration the filtration value assigned to the new N-simplex.
- * @return If the new simplex is inserted successfully (i.e. it was not in the
- * simplicial complex yet) the bool is set to true and the Simplex_handle is the handle assigned
- * to the new simplex.
- * If the insertion fails (the simplex is already there), the bool is set to false. If the insertion
- * fails and the simplex already in the complex has a filtration value strictly bigger than 'filtration',
- * we assign this simplex with the new value 'filtration', and set the Simplex_handle field of the
- * output pair to the Simplex_handle of the simplex. Otherwise, we set the Simplex_handle part to
- * null_simplex.
- */
- template<class InputVertexRange = std::initializer_list<Vertex_handle>>
- std::pair<Simplex_handle, bool> insert_simplex_and_subfaces(const InputVertexRange& Nsimplex,
- Filtration_value filtration = 0) {
- auto first = std::begin(Nsimplex);
- auto last = std::end(Nsimplex);
-
- if (first == last)
- return { null_simplex(), true }; // ----->>
-
- // Copy before sorting
- // Thread local is not available on XCode version < V.8 - It will slow down computation
-#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- thread_local
-#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- std::vector<Vertex_handle> copy;
- copy.clear();
- copy.insert(copy.end(), first, last);
- std::sort(std::begin(copy), std::end(copy));
- GUDHI_CHECK_code(
- for (Vertex_handle v : copy)
- GUDHI_CHECK(v != null_vertex(), "cannot use the dummy null_vertex() as a real vertex");
- )
-
- return insert_simplex_and_subfaces_sorted(copy, filtration);
- }
-
- private:
- /// Same as insert_simplex_and_subfaces but assumes that the range of vertices is sorted
- template<class ForwardVertexRange = std::initializer_list<Vertex_handle>>
- std::pair<Simplex_handle, bool> insert_simplex_and_subfaces_sorted(const ForwardVertexRange& Nsimplex, Filtration_value filt = 0) {
- auto first = std::begin(Nsimplex);
- auto last = std::end(Nsimplex);
- if (first == last)
- return { null_simplex(), true }; // FIXME: false would make more sense to me.
- GUDHI_CHECK(std::is_sorted(first, last), "simplex vertices listed in unsorted order");
- // Update dimension if needed. We could wait to see if the insertion succeeds, but I doubt there is much to gain.
- dimension_ = (std::max)(dimension_, static_cast<int>(std::distance(first, last)) - 1);
- return rec_insert_simplex_and_subfaces_sorted(root(), first, last, filt);
- }
- // To insert {1,2,3,4}, we insert {2,3,4} twice, once at the root, and once below 1.
- template<class ForwardVertexIterator>
- std::pair<Simplex_handle, bool> rec_insert_simplex_and_subfaces_sorted(Siblings* sib, ForwardVertexIterator first, ForwardVertexIterator last, Filtration_value filt) {
- // An alternative strategy would be:
- // - try to find the complete simplex, if found (and low filtration) exit
- // - insert all the vertices at once in sib
- // - loop over those (new or not) simplices, with a recursive call(++first, last)
- Vertex_handle vertex_one = *first;
- auto&& dict = sib->members();
- auto insertion_result = dict.emplace(vertex_one, Node(sib, filt));
- Simplex_handle simplex_one = insertion_result.first;
- bool one_is_new = insertion_result.second;
- if (!one_is_new) {
- if (filtration(simplex_one) > filt) {
- assign_filtration(simplex_one, filt);
- } else {
- // FIXME: this interface makes no sense, and it doesn't seem to be tested.
- insertion_result.first = null_simplex();
- }
- }
- if (++first == last) return insertion_result;
- if (!has_children(simplex_one))
- // TODO: have special code here, we know we are building the whole subtree from scratch.
- simplex_one->second.assign_children(new Siblings(sib, vertex_one));
- auto res = rec_insert_simplex_and_subfaces_sorted(simplex_one->second.children(), first, last, filt);
- // No need to continue if the full simplex was already there with a low enough filtration value.
- if (res.first != null_simplex()) rec_insert_simplex_and_subfaces_sorted(sib, first, last, filt);
- return res;
- }
-
- public:
- /** \brief Assign a value 'key' to the key of the simplex
- * represented by the Simplex_handle 'sh'. */
- void assign_key(Simplex_handle sh, Simplex_key key) {
- sh->second.assign_key(key);
- }
-
- /** Returns the two Simplex_handle corresponding to the endpoints of
- * and edge. sh must point to a 1-dimensional simplex. This is an
- * optimized version of the boundary computation. */
- std::pair<Simplex_handle, Simplex_handle> endpoints(Simplex_handle sh) {
- assert(dimension(sh) == 1);
- return { find_vertex(sh->first), find_vertex(self_siblings(sh)->parent()) };
- }
-
- /** Returns the Siblings containing a simplex.*/
- template<class SimplexHandle>
- Siblings* self_siblings(SimplexHandle sh) {
- if (sh->second.children()->parent() == sh->first)
- return sh->second.children()->oncles();
- else
- return sh->second.children();
- }
-
- public:
- /** Returns a pointer to the root nodes of the simplex tree. */
- Siblings * root() {
- return &root_;
- }
-
- /** \brief Set a dimension for the simplicial complex.
- * \details This function must be used with caution because it disables dimension recomputation when required
- * (this recomputation can be triggered by `remove_maximal_simplex()` or `prune_above_filtration()`).
- */
- void set_dimension(int dimension) {
- dimension_to_be_lowered_ = false;
- dimension_ = dimension;
- }
-
- public:
- /** \brief Initializes the filtrations, i.e. sort the
- * simplices according to their order in the filtration and initializes all Simplex_keys.
- *
- * After calling this method, filtration_simplex_range() becomes valid, and each simplex is
- * assigned a Simplex_key corresponding to its order in the filtration (from 0 to m-1 for a
- * simplicial complex with m simplices).
- *
- * Will be automatically called when calling filtration_simplex_range()
- * if the filtration has never been initialized yet. */
- void initialize_filtration() {
- filtration_vect_.clear();
- filtration_vect_.reserve(num_simplices());
- for (Simplex_handle sh : complex_simplex_range())
- filtration_vect_.push_back(sh);
-
- /* We use stable_sort here because with libstdc++ it is faster than sort.
- * is_before_in_filtration is now a total order, but we used to call
- * stable_sort for the following heuristic:
- * The use of a depth-first traversal of the simplex tree, provided by
- * complex_simplex_range(), combined with a stable sort is meant to
- * optimize the order of simplices with same filtration value. The
- * heuristic consists in inserting the cofaces of a simplex as soon as
- * possible.
- */
-#ifdef GUDHI_USE_TBB
- tbb::parallel_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
-#else
- std::stable_sort(filtration_vect_.begin(), filtration_vect_.end(), is_before_in_filtration(this));
-#endif
- }
-
- private:
- /** Recursive search of cofaces
- * This function uses DFS
- *\param vertices contains a list of vertices, which represent the vertices of the simplex not found yet.
- *\param curr_nbVertices represents the number of vertices of the simplex we reached by going through the tree.
- *\param cofaces contains a list of Simplex_handle, representing all the cofaces asked.
- *\param star true if we need the star of the simplex
- *\param nbVertices number of vertices of the cofaces we search
- * Prefix actions : When the bottom vertex matches with the current vertex in the tree, we remove the bottom vertex from vertices.
- * Infix actions : Then we call or not the recursion.
- * Postfix actions : Finally, we add back the removed vertex into vertices, and remove this vertex from curr_nbVertices so that we didn't change the parameters.
- * If the vertices list is empty, we need to check if curr_nbVertices matches with the dimension of the cofaces asked.
- */
- void rec_coface(std::vector<Vertex_handle> &vertices, Siblings *curr_sib, int curr_nbVertices,
- std::vector<Simplex_handle>& cofaces, bool star, int nbVertices) {
- if (!(star || curr_nbVertices <= nbVertices)) // dimension of actual simplex <= nbVertices
- return;
- for (Simplex_handle simplex = curr_sib->members().begin(); simplex != curr_sib->members().end(); ++simplex) {
- if (vertices.empty()) {
- // If we reached the end of the vertices, and the simplex has more vertices than the given simplex
- // => we found a coface
-
- // Add a coface if we wan't the star or if the number of vertices of the current simplex matches with nbVertices
- bool addCoface = (star || curr_nbVertices == nbVertices);
- if (addCoface)
- cofaces.push_back(simplex);
- if ((!addCoface || star) && has_children(simplex)) // Rec call
- rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
- } else {
- if (simplex->first == vertices.back()) {
- // If curr_sib matches with the top vertex
- bool equalDim = (star || curr_nbVertices == nbVertices); // dimension of actual simplex == nbVertices
- bool addCoface = vertices.size() == 1 && equalDim;
- if (addCoface)
- cofaces.push_back(simplex);
- if ((!addCoface || star) && has_children(simplex)) {
- // Rec call
- Vertex_handle tmp = vertices.back();
- vertices.pop_back();
- rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
- vertices.push_back(tmp);
- }
- } else if (simplex->first > vertices.back()) {
- return;
- } else {
- // (simplex->first < vertices.back()
- if (has_children(simplex))
- rec_coface(vertices, simplex->second.children(), curr_nbVertices + 1, cofaces, star, nbVertices);
- }
- }
- }
- }
-
- public:
- /** \brief Compute the star of a n simplex
- * \param simplex represent the simplex of which we search the star
- * \return Vector of Simplex_handle, empty vector if no cofaces found.
- */
-
- Cofaces_simplex_range star_simplex_range(const Simplex_handle simplex) {
- return cofaces_simplex_range(simplex, 0);
- }
-
- /** \brief Compute the cofaces of a n simplex
- * \param simplex represent the n-simplex of which we search the n+codimension cofaces
- * \param codimension The function returns the n+codimension-cofaces of the n-simplex. If codimension = 0,
- * return all cofaces (equivalent of star function)
- * \return Vector of Simplex_handle, empty vector if no cofaces found.
- */
-
- Cofaces_simplex_range cofaces_simplex_range(const Simplex_handle simplex, int codimension) {
- Cofaces_simplex_range cofaces;
- // codimension must be positive or null integer
- assert(codimension >= 0);
- Simplex_vertex_range rg = simplex_vertex_range(simplex);
- std::vector<Vertex_handle> copy(rg.begin(), rg.end());
- if (codimension + static_cast<int>(copy.size()) > dimension_ + 1 ||
- (codimension == 0 && static_cast<int>(copy.size()) > dimension_)) // n+codimension greater than dimension_
- return cofaces;
- // must be sorted in decreasing order
- assert(std::is_sorted(copy.begin(), copy.end(), std::greater<Vertex_handle>()));
- bool star = codimension == 0;
- rec_coface(copy, &root_, 1, cofaces, star, codimension + static_cast<int>(copy.size()));
- return cofaces;
- }
-
- private:
- /** \brief Returns true iff the list of vertices of sh1
- * is smaller than the list of vertices of sh2 w.r.t.
- * lexicographic order on the lists read in reverse.
- *
- * It defines a StrictWeakOrdering on simplices. The Simplex_vertex_iterators
- * must traverse the Vertex_handle in decreasing order. Reverse lexicographic order satisfy
- * the property that a subsimplex of a simplex is always strictly smaller with this order. */
- bool reverse_lexicographic_order(Simplex_handle sh1, Simplex_handle sh2) {
- Simplex_vertex_range rg1 = simplex_vertex_range(sh1);
- Simplex_vertex_range rg2 = simplex_vertex_range(sh2);
- Simplex_vertex_iterator it1 = rg1.begin();
- Simplex_vertex_iterator it2 = rg2.begin();
- while (it1 != rg1.end() && it2 != rg2.end()) {
- if (*it1 == *it2) {
- ++it1;
- ++it2;
- } else {
- return *it1 < *it2;
- }
- }
- return ((it1 == rg1.end()) && (it2 != rg2.end()));
- }
-
- /** \brief StrictWeakOrdering, for the simplices, defined by the filtration.
- *
- * It corresponds to the partial order
- * induced by the filtration values, with ties resolved using reverse lexicographic order.
- * Reverse lexicographic order has the property to always consider the subsimplex of a simplex
- * to be smaller. The filtration function must be monotonic. */
- struct is_before_in_filtration {
- explicit is_before_in_filtration(Simplex_tree * st)
- : st_(st) { }
-
- bool operator()(const Simplex_handle sh1, const Simplex_handle sh2) const {
- // Not using st_->filtration(sh1) because it uselessly tests for null_simplex.
- if (sh1->second.filtration() != sh2->second.filtration()) {
- return sh1->second.filtration() < sh2->second.filtration();
- }
- // is sh1 a proper subface of sh2
- return st_->reverse_lexicographic_order(sh1, sh2);
- }
-
- Simplex_tree * st_;
- };
-
- public:
- /** \brief Inserts a 1-skeleton in an empty Simplex_tree.
- *
- * The Simplex_tree must contain no simplex when the method is
- * called.
- *
- * Inserts all vertices and edges given by a OneSkeletonGraph.
- * OneSkeletonGraph must be a model of
- * <a href="http://www.boost.org/doc/libs/1_65_1/libs/graph/doc/EdgeListGraph.html">boost::EdgeListGraph</a>
- * and <a href="http://www.boost.org/doc/libs/1_65_1/libs/graph/doc/PropertyGraph.html">boost::PropertyGraph</a>.
- *
- * The vertex filtration value is accessible through the property tag
- * vertex_filtration_t.
- * The edge filtration value is accessible through the property tag
- * edge_filtration_t.
- *
- * boost::graph_traits<OneSkeletonGraph>::vertex_descriptor
- * must be Vertex_handle.
- * boost::graph_traits<OneSkeletonGraph>::directed_category
- * must be undirected_tag.
- *
- * If an edge appears with multiplicity, the function will arbitrarily pick
- * one representative to read the filtration value. */
- template<class OneSkeletonGraph>
- void insert_graph(const OneSkeletonGraph& skel_graph) {
- // the simplex tree must be empty
- assert(num_simplices() == 0);
-
- if (boost::num_vertices(skel_graph) == 0) {
- return;
- }
- if (num_edges(skel_graph) == 0) {
- dimension_ = 0;
- } else {
- dimension_ = 1;
- }
-
- root_.members_.reserve(boost::num_vertices(skel_graph));
-
- typename boost::graph_traits<OneSkeletonGraph>::vertex_iterator v_it,
- v_it_end;
- for (std::tie(v_it, v_it_end) = boost::vertices(skel_graph); v_it != v_it_end;
- ++v_it) {
- root_.members_.emplace_hint(
- root_.members_.end(), *v_it,
- Node(&root_, boost::get(vertex_filtration_t(), skel_graph, *v_it)));
- }
- typename boost::graph_traits<OneSkeletonGraph>::edge_iterator e_it,
- e_it_end;
- for (std::tie(e_it, e_it_end) = boost::edges(skel_graph); e_it != e_it_end;
- ++e_it) {
- auto u = source(*e_it, skel_graph);
- auto v = target(*e_it, skel_graph);
- if (u == v) throw "Self-loops are not simplicial";
- // We cannot skip edges with the wrong orientation and expect them to
- // come a second time with the right orientation, that does not always
- // happen in practice. emplace() should be a NOP when an element with the
- // same key is already there, so seeing the same edge multiple times is
- // ok.
- // Should we actually forbid multiple edges? That would be consistent
- // with rejecting self-loops.
- if (v < u) std::swap(u, v);
- auto sh = find_vertex(u);
- if (!has_children(sh)) {
- sh->second.assign_children(new Siblings(&root_, sh->first));
- }
-
- sh->second.children()->members().emplace(v,
- Node(sh->second.children(), boost::get(edge_filtration_t(), skel_graph, *e_it)));
- }
- }
-
- /** \brief Expands the Simplex_tree containing only its one skeleton
- * until dimension max_dim.
- *
- * The expanded simplicial complex until dimension \f$d\f$
- * attached to a graph \f$G\f$ is the maximal simplicial complex of
- * dimension at most \f$d\f$ admitting the graph \f$G\f$ as \f$1\f$-skeleton.
- * The filtration value assigned to a simplex is the maximal filtration
- * value of one of its edges.
- *
- * The Simplex_tree must contain no simplex of dimension bigger than
- * 1 when calling the method. */
- void expansion(int max_dim) {
- dimension_ = max_dim;
- for (Dictionary_it root_it = root_.members_.begin();
- root_it != root_.members_.end(); ++root_it) {
- if (has_children(root_it)) {
- siblings_expansion(root_it->second.children(), max_dim - 1);
- }
- }
- dimension_ = max_dim - dimension_;
- }
-
- private:
- /** \brief Recursive expansion of the simplex tree.*/
- void siblings_expansion(Siblings * siblings, // must contain elements
- int k) {
- if (dimension_ > k) {
- dimension_ = k;
- }
- if (k == 0)
- return;
- Dictionary_it next = siblings->members().begin();
- ++next;
-
-#ifdef GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- thread_local
-#endif // GUDHI_CAN_USE_CXX11_THREAD_LOCAL
- std::vector<std::pair<Vertex_handle, Node> > inter;
- for (Dictionary_it s_h = siblings->members().begin();
- s_h != siblings->members().end(); ++s_h, ++next) {
- Simplex_handle root_sh = find_vertex(s_h->first);
- if (has_children(root_sh)) {
- intersection(
- inter, // output intersection
- next, // begin
- siblings->members().end(), // end
- root_sh->second.children()->members().begin(),
- root_sh->second.children()->members().end(),
- s_h->second.filtration());
- if (inter.size() != 0) {
- Siblings * new_sib = new Siblings(siblings, // oncles
- s_h->first, // parent
- inter); // boost::container::ordered_unique_range_t
- inter.clear();
- s_h->second.assign_children(new_sib);
- siblings_expansion(new_sib, k - 1);
- } else {
- // ensure the children property
- s_h->second.assign_children(siblings);
- inter.clear();
- }
- }
- }
- }
-
- /** \brief Intersects Dictionary 1 [begin1;end1) with Dictionary 2 [begin2,end2)
- * and assigns the maximal possible Filtration_value to the Nodes. */
- static void intersection(std::vector<std::pair<Vertex_handle, Node> >& intersection,
- Dictionary_it begin1, Dictionary_it end1,
- Dictionary_it begin2, Dictionary_it end2,
- Filtration_value filtration_) {
- if (begin1 == end1 || begin2 == end2)
- return; // ----->>
- while (true) {
- if (begin1->first == begin2->first) {
- Filtration_value filt = (std::max)({begin1->second.filtration(), begin2->second.filtration(), filtration_});
- intersection.emplace_back(begin1->first, Node(nullptr, filt));
- if (++begin1 == end1 || ++begin2 == end2)
- return; // ----->>
- } else if (begin1->first < begin2->first) {
- if (++begin1 == end1)
- return;
- } else /* begin1->first > begin2->first */ {
- if (++begin2 == end2)
- return; // ----->>
- }
- }
- }
-
- public:
- /** \brief Expands a simplex tree containing only a graph. Simplices corresponding to cliques in the graph are added
- * incrementally, faces before cofaces, unless the simplex has dimension larger than `max_dim` or `block_simplex`
- * returns true for this simplex.
- *
- * @param[in] max_dim Expansion maximal dimension value.
- * @param[in] block_simplex Blocker oracle. Its concept is <CODE>bool block_simplex(Simplex_handle sh)</CODE>
- *
- * The function identifies a candidate simplex whose faces are all already in the complex, inserts
- * it with a filtration value corresponding to the maximum of the filtration values of the faces, then calls
- * `block_simplex` on a `Simplex_handle` for this new simplex. If `block_simplex` returns true, the simplex is
- * removed, otherwise it is kept. Note that the evaluation of `block_simplex` is a good time to update the
- * filtration value of the simplex if you want a customized value. The algorithm then proceeds with the next
- * candidate.
- *
- * @warning several candidates of the same dimension may be inserted simultaneously before calling `block_simplex`,
- * so if you examine the complex in `block_simplex`, you may hit a few simplices of the same dimension that have not
- * been vetted by `block_simplex` yet, or have already been rejected but not yet removed.
- */
- template< typename Blocker >
- void expansion_with_blockers(int max_dim, Blocker block_simplex) {
- // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
- for (auto& simplex : boost::adaptors::reverse(root_.members())) {
- if (has_children(&simplex)) {
- siblings_expansion_with_blockers(simplex.second.children(), max_dim, max_dim - 1, block_simplex);
- }
- }
- }
-
- private:
- /** \brief Recursive expansion with blockers of the simplex tree.*/
- template< typename Blocker >
- void siblings_expansion_with_blockers(Siblings* siblings, int max_dim, int k, Blocker block_simplex) {
- if (dimension_ < max_dim - k) {
- dimension_ = max_dim - k;
- }
- if (k == 0)
- return;
- // No need to go deeper
- if (siblings->members().size() < 2)
- return;
- // Reverse loop starting before the last one for 'next' to be the last one
- for (auto simplex = siblings->members().rbegin() + 1; simplex != siblings->members().rend(); simplex++) {
- std::vector<std::pair<Vertex_handle, Node> > intersection;
- for(auto next = siblings->members().rbegin(); next != simplex; next++) {
- bool to_be_inserted = true;
- Filtration_value filt = simplex->second.filtration();
- // If all the boundaries are present, 'next' needs to be inserted
- for (Simplex_handle border : boundary_simplex_range(simplex)) {
- Simplex_handle border_child = find_child(border, next->first);
- if (border_child == null_simplex()) {
- to_be_inserted=false;
- break;
- }
- filt = (std::max)(filt, filtration(border_child));
- }
- if (to_be_inserted) {
- intersection.emplace_back(next->first, Node(nullptr, filt));
- }
- }
- if (intersection.size() != 0) {
- // Reverse the order to insert
- Siblings * new_sib = new Siblings(siblings, // oncles
- simplex->first, // parent
- boost::adaptors::reverse(intersection)); // boost::container::ordered_unique_range_t
- std::vector<Vertex_handle> blocked_new_sib_vertex_list;
- // As all intersections are inserted, we can call the blocker function on all new_sib members
- for (auto new_sib_member = new_sib->members().begin();
- new_sib_member != new_sib->members().end();
- new_sib_member++) {
- bool blocker_result = block_simplex(new_sib_member);
- // new_sib member has been blocked by the blocker function
- // add it to the list to be removed - do not perform it while looping on it
- if (blocker_result) {
- blocked_new_sib_vertex_list.push_back(new_sib_member->first);
- }
- }
- if (blocked_new_sib_vertex_list.size() == new_sib->members().size()) {
- // Specific case where all have to be deleted
- delete new_sib;
- // ensure the children property
- simplex->second.assign_children(siblings);
- } else {
- for (auto& blocked_new_sib_member : blocked_new_sib_vertex_list) {
- new_sib->members().erase(blocked_new_sib_member);
- }
- // ensure recursive call
- simplex->second.assign_children(new_sib);
- siblings_expansion_with_blockers(new_sib, max_dim, k - 1, block_simplex);
- }
- } else {
- // ensure the children property
- simplex->second.assign_children(siblings);
- }
- }
- }
-
- /* \private Returns the Simplex_handle composed of the vertex list (from the Simplex_handle), plus the given
- * Vertex_handle if the Vertex_handle is found in the Simplex_handle children list.
- * Returns null_simplex() if it does not exist
- */
- Simplex_handle find_child(Simplex_handle sh, Vertex_handle vh) const {
- if (!has_children(sh))
- return null_simplex();
-
- Simplex_handle child = sh->second.children()->find(vh);
- // Specific case of boost::flat_map does not find, returns boost::flat_map::end()
- // in simplex tree we want a null_simplex()
- if (child == sh->second.children()->members().end())
- return null_simplex();
-
- return child;
- }
-
- public:
- /** \brief Write the hasse diagram of the simplicial complex in os.
- *
- * Each row in the file correspond to a simplex. A line is written:
- * dim idx_1 ... idx_k fil where dim is the dimension of the simplex,
- * idx_1 ... idx_k are the row index (starting from 0) of the simplices of the boundary
- * of the simplex, and fil is its filtration value. */
- void print_hasse(std::ostream& os) {
- os << num_simplices() << " " << std::endl;
- for (auto sh : filtration_simplex_range()) {
- os << dimension(sh) << " ";
- for (auto b_sh : boundary_simplex_range(sh)) {
- os << key(b_sh) << " ";
- }
- os << filtration(sh) << " \n";
- }
- }
-
- public:
- /** \brief This function ensures that each simplex has a higher filtration value than its faces by increasing the
- * filtration values.
- * @return The filtration modification information.
- * \post Some simplex tree functions require the filtration to be valid. `make_filtration_non_decreasing()`
- * function is not launching `initialize_filtration()` but returns the filtration modification information. If the
- * complex has changed , please call `initialize_filtration()` to recompute it.
- */
- bool make_filtration_non_decreasing() {
- bool modified = false;
- // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
- for (auto& simplex : boost::adaptors::reverse(root_.members())) {
- if (has_children(&simplex)) {
- modified |= rec_make_filtration_non_decreasing(simplex.second.children());
- }
- }
- return modified;
- }
-
- private:
- /** \brief Recursively Browse the simplex tree to ensure the filtration is not decreasing.
- * @param[in] sib Siblings to be parsed.
- * @return The filtration modification information in order to trigger initialize_filtration.
- */
- bool rec_make_filtration_non_decreasing(Siblings * sib) {
- bool modified = false;
-
- // Loop must be from the end to the beginning, as higher dimension simplex are always on the left part of the tree
- for (auto& simplex : boost::adaptors::reverse(sib->members())) {
- // Find the maximum filtration value in the border
- Boundary_simplex_range boundary = boundary_simplex_range(&simplex);
- Boundary_simplex_iterator max_border = std::max_element(std::begin(boundary), std::end(boundary),
- [](Simplex_handle sh1, Simplex_handle sh2) {
- return filtration(sh1) < filtration(sh2);
- });
-
- Filtration_value max_filt_border_value = filtration(*max_border);
- if (simplex.second.filtration() < max_filt_border_value) {
- // Store the filtration modification information
- modified = true;
- simplex.second.assign_filtration(max_filt_border_value);
- }
- if (has_children(&simplex)) {
- modified |= rec_make_filtration_non_decreasing(simplex.second.children());
- }
- }
- // Make the modified information to be traced by upper call
- return modified;
- }
-
- public:
- /** \brief Prune above filtration value given as parameter.
- * @param[in] filtration Maximum threshold value.
- * @return The filtration modification information.
- * \post Some simplex tree functions require the filtration to be valid. `prune_above_filtration()`
- * function is not launching `initialize_filtration()` but returns the filtration modification information. If the
- * complex has changed , please call `initialize_filtration()` to recompute it.
- * \post Note that the dimension of the simplicial complex may be lower after calling `prune_above_filtration()`
- * than it was before. However, `upper_bound_dimension()` will return the old value, which remains a valid upper
- * bound. If you care, you can call `dimension()` to recompute the exact dimension.
- */
- bool prune_above_filtration(Filtration_value filtration) {
- return rec_prune_above_filtration(root(), filtration);
- }
-
- private:
- bool rec_prune_above_filtration(Siblings* sib, Filtration_value filt) {
- auto&& list = sib->members();
- auto last = std::remove_if(list.begin(), list.end(), [=](Dit_value_t& simplex) {
- if (simplex.second.filtration() <= filt) return false;
- if (has_children(&simplex)) rec_delete(simplex.second.children());
- // dimension may need to be lowered
- dimension_to_be_lowered_ = true;
- return true;
- });
-
- bool modified = (last != list.end());
- if (last == list.begin() && sib != root()) {
- // Removing the whole siblings, parent becomes a leaf.
- sib->oncles()->members()[sib->parent()].assign_children(sib->oncles());
- delete sib;
- // dimension may need to be lowered
- dimension_to_be_lowered_ = true;
- return true;
- } else {
- // Keeping some elements of siblings. Remove the others, and recurse in the remaining ones.
- list.erase(last, list.end());
- for (auto&& simplex : list)
- if (has_children(&simplex))
- modified |= rec_prune_above_filtration(simplex.second.children(), filt);
- }
- return modified;
- }
-
- private:
- /** \brief Deep search simplex tree dimension recompute.
- * @return True if the dimension was modified, false otherwise.
- * \pre Be sure the simplex tree has not a too low dimension value as the deep search stops when the former dimension
- * has been reached (cf. `upper_bound_dimension()` and `set_dimension()` methods).
- */
- bool lower_upper_bound_dimension() {
- // reset automatic detection to recompute
- dimension_to_be_lowered_ = false;
- int new_dimension = -1;
- // Browse the tree from the left to the right as higher dimension cells are more likely on the left part of the tree
- for (Simplex_handle sh : complex_simplex_range()) {
-#ifdef DEBUG_TRACES
- for (auto vertex : simplex_vertex_range(sh)) {
- std::cout << " " << vertex;
- }
- std::cout << std::endl;
-#endif // DEBUG_TRACES
-
- int sh_dimension = dimension(sh);
- if (sh_dimension >= dimension_)
- // Stop browsing as soon as the dimension is reached, no need to go furter
- return false;
- new_dimension = (std::max)(new_dimension, sh_dimension);
- }
- dimension_ = new_dimension;
- return true;
- }
-
-
- public:
- /** \brief Remove a maximal simplex.
- * @param[in] sh Simplex handle on the maximal simplex to remove.
- * \pre Please check the simplex has no coface before removing it.
- * \exception std::invalid_argument In debug mode, if sh has children.
- * \post Be aware that removing is shifting data in a flat_map (initialize_filtration to be done).
- * \post Note that the dimension of the simplicial complex may be lower after calling `remove_maximal_simplex()`
- * than it was before. However, `upper_bound_dimension()` will return the old value, which remains a valid upper
- * bound. If you care, you can call `dimension()` to recompute the exact dimension.
- */
- void remove_maximal_simplex(Simplex_handle sh) {
- // Guarantee the simplex has no children
- GUDHI_CHECK(!has_children(sh),
- std::invalid_argument("Simplex_tree::remove_maximal_simplex - argument has children"));
-
- // Simplex is a leaf, it means the child is the Siblings owning the leaf
- Siblings* child = sh->second.children();
-
- if ((child->size() > 1) || (child == root())) {
- // Not alone, just remove it from members
- // Special case when child is the root of the simplex tree, just remove it from members
- child->erase(sh);
- } else {
- // Sibling is emptied : must be deleted, and its parent must point on his own Sibling
- child->oncles()->members().at(child->parent()).assign_children(child->oncles());
- delete child;
- // dimension may need to be lowered
- dimension_to_be_lowered_ = true;
- }
- }
-
- private:
- Vertex_handle null_vertex_;
- /** \brief Total number of simplices in the complex, without the empty simplex.*/
- /** \brief Set of simplex tree Nodes representing the vertices.*/
- Siblings root_;
- /** \brief Simplices ordered according to a filtration.*/
- std::vector<Simplex_handle> filtration_vect_;
- /** \brief Upper bound on the dimension of the simplicial complex.*/
- int dimension_;
- bool dimension_to_be_lowered_ = false;
-};
-
-// Print a Simplex_tree in os.
-template<typename...T>
-std::ostream& operator<<(std::ostream & os, Simplex_tree<T...> & st) {
- for (auto sh : st.filtration_simplex_range()) {
- os << st.dimension(sh) << " ";
- for (auto v : st.simplex_vertex_range(sh)) {
- os << v << " ";
- }
- os << st.filtration(sh) << "\n"; // TODO(VR): why adding the key ?? not read ?? << " " << st.key(sh) << " \n";
- }
- return os;
-}
-
-template<typename...T>
-std::istream& operator>>(std::istream & is, Simplex_tree<T...> & st) {
- typedef Simplex_tree<T...> ST;
- std::vector<typename ST::Vertex_handle> simplex;
- typename ST::Filtration_value fil;
- int max_dim = -1;
- while (read_simplex(is, simplex, fil)) {
- // read all simplices in the file as a list of vertices
- // Warning : simplex_size needs to be casted in int - Can be 0
- int dim = static_cast<int> (simplex.size() - 1);
- if (max_dim < dim) {
- max_dim = dim;
- }
- // insert every simplex in the simplex tree
- st.insert_simplex(simplex, fil);
- simplex.clear();
- }
- st.set_dimension(max_dim);
-
- return is;
-}
-
-/** Model of SimplexTreeOptions.
- *
- * Maximum number of simplices to compute persistence is <CODE>std::numeric_limits<std::uint32_t>::max()</CODE>
- * (about 4 billions of simplices). */
-struct Simplex_tree_options_full_featured {
- typedef linear_indexing_tag Indexing_tag;
- typedef int Vertex_handle;
- typedef double Filtration_value;
- typedef std::uint32_t Simplex_key;
- static const bool store_key = true;
- static const bool store_filtration = true;
- static const bool contiguous_vertices = false;
-};
-
-/** Model of SimplexTreeOptions, faster than `Simplex_tree_options_full_featured` but note the unsafe
- * `contiguous_vertices` option.
- *
- * Maximum number of simplices to compute persistence is <CODE>std::numeric_limits<std::uint32_t>::max()</CODE>
- * (about 4 billions of simplices). */
-
-struct Simplex_tree_options_fast_persistence {
- typedef linear_indexing_tag Indexing_tag;
- typedef int Vertex_handle;
- typedef float Filtration_value;
- typedef std::uint32_t Simplex_key;
- static const bool store_key = true;
- static const bool store_filtration = true;
- static const bool contiguous_vertices = true;
-};
-
-/** @} */ // end defgroup simplex_tree
-
-} // namespace Gudhi
-
-#endif // SIMPLEX_TREE_H_
diff --git a/include/gudhi/Simplex_tree/Simplex_tree_iterators.h b/include/gudhi/Simplex_tree/Simplex_tree_iterators.h
deleted file mode 100644
index 02c8bb64..00000000
--- a/include/gudhi/Simplex_tree/Simplex_tree_iterators.h
+++ /dev/null
@@ -1,354 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_
-#define SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_
-
-#include <gudhi/Debug_utils.h>
-
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/version.hpp>
-#if BOOST_VERSION >= 105600
-# include <boost/container/static_vector.hpp>
-#endif
-
-#include <vector>
-
-namespace Gudhi {
-
-/* \addtogroup simplex_tree
- * Iterators and range types for the Simplex_tree.
- * @{
- */
-
-/* \brief Iterator over the vertices of a simplex
- * in a SimplexTree.
- *
- * Forward iterator, 'value_type' is SimplexTree::Vertex_handle.*/
-template<class SimplexTree>
-class Simplex_tree_simplex_vertex_iterator : public boost::iterator_facade<
- Simplex_tree_simplex_vertex_iterator<SimplexTree>,
- typename SimplexTree::Vertex_handle const, boost::forward_traversal_tag,
- typename SimplexTree::Vertex_handle const> {
- public:
- typedef typename SimplexTree::Simplex_handle Simplex_handle;
- typedef typename SimplexTree::Siblings Siblings;
- typedef typename SimplexTree::Vertex_handle Vertex_handle;
-
- explicit Simplex_tree_simplex_vertex_iterator(SimplexTree * st)
- : // any end() iterator
- sib_(nullptr),
- v_(st->null_vertex()) {
- }
-
- Simplex_tree_simplex_vertex_iterator(SimplexTree * st, Simplex_handle sh)
- : sib_(st->self_siblings(sh)),
- v_(sh->first) {
- }
-
- private:
- friend class boost::iterator_core_access;
-
- bool equal(Simplex_tree_simplex_vertex_iterator const &other) const {
- return sib_ == other.sib_ && v_ == other.v_;
- }
-
- Vertex_handle const& dereference() const {
- return v_;
- }
-
- void increment() {
- v_ = sib_->parent();
- sib_ = sib_->oncles();
- }
-
- Siblings * sib_;
- Vertex_handle v_;
-};
-
-/*---------------------------------------------------------------------------*/
-/* \brief Iterator over the simplices of the boundary of a
- * simplex.
- *
- * Forward iterator, value_type is SimplexTree::Simplex_handle.*/
-template<class SimplexTree>
-class Simplex_tree_boundary_simplex_iterator : public boost::iterator_facade<
- Simplex_tree_boundary_simplex_iterator<SimplexTree>,
- typename SimplexTree::Simplex_handle const, boost::forward_traversal_tag> {
- public:
- typedef typename SimplexTree::Simplex_handle Simplex_handle;
- typedef typename SimplexTree::Vertex_handle Vertex_handle;
- typedef typename SimplexTree::Siblings Siblings;
-
-// any end() iterator
- explicit Simplex_tree_boundary_simplex_iterator(SimplexTree * st)
- : last_(st->null_vertex()),
- next_(st->null_vertex()),
- sib_(nullptr),
- sh_(st->null_simplex()),
- st_(st) {
- }
-
- template<class SimplexHandle>
- Simplex_tree_boundary_simplex_iterator(SimplexTree * st, SimplexHandle sh)
- : last_(sh->first),
- next_(st->null_vertex()),
- sib_(nullptr),
- sh_(st->null_simplex()),
- st_(st) {
- // Only check once at the beginning instead of for every increment, as this is expensive.
- if (SimplexTree::Options::contiguous_vertices)
- GUDHI_CHECK(st_->contiguous_vertices(), "The set of vertices is not { 0, ..., n } without holes");
- Siblings * sib = st->self_siblings(sh);
- next_ = sib->parent();
- sib_ = sib->oncles();
- if (sib_ != nullptr) {
- if (SimplexTree::Options::contiguous_vertices && sib_->oncles() == nullptr)
- // Only relevant for edges
- sh_ = sib_->members_.begin()+next_;
- else
- sh_ = sib_->find(next_);
- }
- }
-
- private:
- friend class boost::iterator_core_access;
-// valid when iterating along the SAME boundary.
- bool equal(Simplex_tree_boundary_simplex_iterator const& other) const {
- return sh_ == other.sh_;
- }
-
- Simplex_handle const& dereference() const {
- assert(sh_ != st_->null_simplex());
- return sh_;
- }
-
- void increment() {
- if (sib_ == nullptr) {
- sh_ = st_->null_simplex();
- return;
- }
-
- Siblings * for_sib = sib_;
- Siblings * new_sib = sib_->oncles();
- auto rit = suffix_.rbegin();
- if (SimplexTree::Options::contiguous_vertices && new_sib == nullptr) {
- // We reached the root, use a short-cut to find a vertex.
- if (rit == suffix_.rend()) {
- // Segment, this vertex is the last boundary simplex
- sh_ = for_sib->members_.begin()+last_;
- sib_ = nullptr;
- return;
- } else {
- // Dim >= 2, initial step of the descent
- sh_ = for_sib->members_.begin()+*rit;
- for_sib = sh_->second.children();
- ++rit;
- }
- }
- for (; rit != suffix_.rend(); ++rit) {
- sh_ = for_sib->find(*rit);
- for_sib = sh_->second.children();
- }
- sh_ = for_sib->find(last_); // sh_ points to the right simplex now
- suffix_.push_back(next_);
- next_ = sib_->parent();
- sib_ = new_sib;
- }
-
- // Most of the storage should be moved to the range, iterators should be light.
- Vertex_handle last_; // last vertex of the simplex
- Vertex_handle next_; // next vertex to push in suffix_
-#if BOOST_VERSION >= 105600
- // 40 seems a conservative bound on the dimension of a Simplex_tree for now,
- // as it would not fit on the biggest hard-drive.
- boost::container::static_vector<Vertex_handle, 40> suffix_;
- // static_vector still has some overhead compared to a trivial hand-made
- // version using std::aligned_storage, or compared to making suffix_ static.
-#else
- std::vector<Vertex_handle> suffix_;
-#endif
- Siblings * sib_; // where the next search will start from
- Simplex_handle sh_; // current Simplex_handle in the boundary
- SimplexTree * st_; // simplex containing the simplicial complex
-};
-/*---------------------------------------------------------------------------*/
-/* \brief Iterator over the simplices of a simplicial complex.
- *
- * Forward iterator, value_type is SimplexTree::Simplex_handle.*/
-template<class SimplexTree>
-class Simplex_tree_complex_simplex_iterator : public boost::iterator_facade<
- Simplex_tree_complex_simplex_iterator<SimplexTree>,
- typename SimplexTree::Simplex_handle const, boost::forward_traversal_tag> {
- public:
- typedef typename SimplexTree::Simplex_handle Simplex_handle;
- typedef typename SimplexTree::Siblings Siblings;
- typedef typename SimplexTree::Vertex_handle Vertex_handle;
-
-// any end() iterator
- Simplex_tree_complex_simplex_iterator()
- : sib_(nullptr),
- st_(nullptr) {
- }
-
- explicit Simplex_tree_complex_simplex_iterator(SimplexTree * st)
- : sib_(nullptr),
- st_(st) {
- if (st == nullptr || st->root() == nullptr || st->root()->members().empty()) {
- st_ = nullptr;
- } else {
- sh_ = st->root()->members().begin();
- sib_ = st->root();
- while (st->has_children(sh_)) {
- sib_ = sh_->second.children();
- sh_ = sib_->members().begin();
- }
- }
- }
- private:
- friend class boost::iterator_core_access;
-
-// valid when iterating along the SAME boundary.
- bool equal(Simplex_tree_complex_simplex_iterator const& other) const {
- if (other.st_ == nullptr) {
- return (st_ == nullptr);
- }
- if (st_ == nullptr) {
- return false;
- }
- return (&(sh_->second) == &(other.sh_->second));
- }
-
- Simplex_handle const& dereference() const {
- return sh_;
- }
-
-// Depth first traversal.
- void increment() {
- ++sh_;
- if (sh_ == sib_->members().end()) {
- if (sib_->oncles() == nullptr) {
- st_ = nullptr;
- return;
- } // reach the end
- sh_ = sib_->oncles()->members().find(sib_->parent());
- sib_ = sib_->oncles();
- return;
- }
- while (st_->has_children(sh_)) {
- sib_ = sh_->second.children();
- sh_ = sib_->members().begin();
- }
- }
-
- Simplex_handle sh_;
- Siblings * sib_;
- SimplexTree * st_;
-};
-
-/* \brief Iterator over the simplices of the skeleton of a given
- * dimension of the simplicial complex.
- *
- * Forward iterator, value_type is SimplexTree::Simplex_handle.*/
-template<class SimplexTree>
-class Simplex_tree_skeleton_simplex_iterator : public boost::iterator_facade<
- Simplex_tree_skeleton_simplex_iterator<SimplexTree>,
- typename SimplexTree::Simplex_handle const, boost::forward_traversal_tag> {
- public:
- typedef typename SimplexTree::Simplex_handle Simplex_handle;
- typedef typename SimplexTree::Siblings Siblings;
- typedef typename SimplexTree::Vertex_handle Vertex_handle;
-
-// any end() iterator
- Simplex_tree_skeleton_simplex_iterator()
- : sib_(nullptr),
- st_(nullptr),
- dim_skel_(0),
- curr_dim_(0) {
- }
-
- Simplex_tree_skeleton_simplex_iterator(SimplexTree * st, int dim_skel)
- : sib_(nullptr),
- st_(st),
- dim_skel_(dim_skel),
- curr_dim_(0) {
- if (st == nullptr || st->root() == nullptr || st->root()->members().empty()) {
- st_ = nullptr;
- } else {
- sh_ = st->root()->members().begin();
- sib_ = st->root();
- while (st->has_children(sh_) && curr_dim_ < dim_skel_) {
- sib_ = sh_->second.children();
- sh_ = sib_->members().begin();
- ++curr_dim_;
- }
- }
- }
- private:
- friend class boost::iterator_core_access;
-
-// valid when iterating along the SAME boundary.
- bool equal(Simplex_tree_skeleton_simplex_iterator const& other) const {
- if (other.st_ == nullptr) {
- return (st_ == nullptr);
- }
- if (st_ == nullptr) {
- return false;
- }
- return (&(sh_->second) == &(other.sh_->second));
- }
-
- Simplex_handle const& dereference() const {
- return sh_;
- }
-
-// Depth first traversal of the skeleton.
- void increment() {
- ++sh_;
- if (sh_ == sib_->members().end()) {
- if (sib_->oncles() == nullptr) {
- st_ = nullptr;
- return;
- } // reach the end
- sh_ = sib_->oncles()->members().find(sib_->parent());
- sib_ = sib_->oncles();
- --curr_dim_;
- return;
- }
- while (st_->has_children(sh_) && curr_dim_ < dim_skel_) {
- sib_ = sh_->second.children();
- sh_ = sib_->members().begin();
- ++curr_dim_;
- }
- }
-
- Simplex_handle sh_;
- Siblings * sib_;
- SimplexTree * st_;
- int dim_skel_;
- int curr_dim_;
-};
-
-/* @} */ // end addtogroup simplex_tree
-} // namespace Gudhi
-
-#endif // SIMPLEX_TREE_SIMPLEX_TREE_ITERATORS_H_
diff --git a/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h b/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h
deleted file mode 100644
index 3a75ec72..00000000
--- a/include/gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_
-#define SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_
-
-#include <vector>
-
-namespace Gudhi {
-
-/* \addtogroup simplex_tree
- * Represents a node of a Simplex_tree.
- * @{
- */
-
-/*
- * \brief Node of a simplex tree with filtration value
- * and simplex key.
- *
- * It stores explicitely its own filtration value and its own Simplex_key.
- */
-template<class SimplexTree>
-struct Simplex_tree_node_explicit_storage : SimplexTree::Filtration_simplex_base, SimplexTree::Key_simplex_base {
- typedef typename SimplexTree::Siblings Siblings;
- typedef typename SimplexTree::Filtration_value Filtration_value;
- typedef typename SimplexTree::Simplex_key Simplex_key;
-
- Simplex_tree_node_explicit_storage(Siblings * sib = nullptr,
- Filtration_value filtration = 0)
- : children_(sib) {
- this->assign_filtration(filtration);
- }
-
- /*
- * Assign children to the node
- */
- void assign_children(Siblings * children) {
- children_ = children;
- }
-
- /* Careful -> children_ can be NULL*/
- Siblings * children() {
- return children_;
- }
-
- private:
- Siblings * children_;
-};
-
-/* @} */ // end addtogroup simplex_tree
-} // namespace Gudhi
-
-#endif // SIMPLEX_TREE_SIMPLEX_TREE_NODE_EXPLICIT_STORAGE_H_
diff --git a/include/gudhi/Simplex_tree/Simplex_tree_siblings.h b/include/gudhi/Simplex_tree/Simplex_tree_siblings.h
deleted file mode 100644
index ab2ca707..00000000
--- a/include/gudhi/Simplex_tree/Simplex_tree_siblings.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_
-#define SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_
-
-#include <gudhi/Simplex_tree/Simplex_tree_node_explicit_storage.h>
-
-#include <boost/container/flat_map.hpp>
-
-#include <utility>
-#include <vector>
-
-namespace Gudhi {
-
-/* \addtogroup simplex_tree
- * Represents a set of node of a Simplex_tree that share the same parent.
- * @{
- */
-
-/* \brief Data structure to store a set of nodes in a SimplexTree sharing
- * the same parent node.*/
-template<class SimplexTree, class MapContainer>
-class Simplex_tree_siblings {
-// private:
-// friend SimplexTree;
- public:
- template<class T> friend class Simplex_tree_simplex_vertex_iterator;
- template<class T> friend class Simplex_tree_boundary_simplex_iterator;
- template<class T> friend class Simplex_tree_complex_simplex_iterator;
- template<class T> friend class Simplex_tree_skeleton_simplex_iterator;
-
- typedef typename SimplexTree::Vertex_handle Vertex_handle;
- typedef typename SimplexTree::Filtration_value Filtration_value;
- typedef typename SimplexTree::Node Node;
- typedef MapContainer Dictionary;
- typedef typename MapContainer::iterator Dictionary_it;
-
- /* Default constructor.*/
- Simplex_tree_siblings()
- : oncles_(nullptr),
- parent_(-1),
- members_() {
- }
-
- /* Constructor with values.*/
- Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent)
- : oncles_(oncles),
- parent_(parent),
- members_() {
- }
-
- /* \brief Constructor with initialized set of members.
- *
- * 'members' must be sorted and unique.*/
- template<typename RandomAccessVertexRange>
- Simplex_tree_siblings(Simplex_tree_siblings * oncles, Vertex_handle parent, const RandomAccessVertexRange & members)
- : oncles_(oncles),
- parent_(parent),
- members_(boost::container::ordered_unique_range, members.begin(),
- members.end()) {
- for (auto& map_el : members_) {
- map_el.second.assign_children(this);
- }
- }
-
- /*
- * \brief Inserts a Node in the set of siblings nodes.
- *
- * If already present, assigns the minimal filtration value
- * between input filtration_value and the value already
- * present in the node.
- */
- void insert(Vertex_handle v, Filtration_value filtration_value) {
- auto ins = members_.emplace(v, Node(this, filtration_value));
- if (!ins.second && filtration(ins.first) > filtration_value)
- ins.first->second.assign_filtration(filtration_value);
- }
-
- Dictionary_it find(Vertex_handle v) {
- return members_.find(v);
- }
-
- Simplex_tree_siblings * oncles() {
- return oncles_;
- }
-
- Vertex_handle parent() const {
- return parent_;
- }
-
- Dictionary & members() {
- return members_;
- }
-
- size_t size() const {
- return members_.size();
- }
-
- void erase(const Dictionary_it iterator) {
- members_.erase(iterator);
- }
-
- Simplex_tree_siblings * oncles_;
- Vertex_handle parent_;
- Dictionary members_;
-};
-
-/* @} */ // end addtogroup simplex_tree
-} // namespace Gudhi
-
-#endif // SIMPLEX_TREE_SIMPLEX_TREE_SIBLINGS_H_
diff --git a/include/gudhi/Simplex_tree/indexing_tag.h b/include/gudhi/Simplex_tree/indexing_tag.h
deleted file mode 100644
index ec4461f3..00000000
--- a/include/gudhi/Simplex_tree/indexing_tag.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SIMPLEX_TREE_INDEXING_TAG_H_
-#define SIMPLEX_TREE_INDEXING_TAG_H_
-
-namespace Gudhi {
-
-/** \brief Tag for a linear ordering of simplices.
- *
- * \implements IndexingTag
- */
-struct linear_indexing_tag {
-};
-
-/* \brief Tag for a zigzag ordering of simplices. */
-// struct zigzag_indexing_tag {};
-} // namespace Gudhi
-
-#endif // SIMPLEX_TREE_INDEXING_TAG_H_
diff --git a/include/gudhi/Skeleton_blocker.h b/include/gudhi/Skeleton_blocker.h
deleted file mode 100644
index e8b6fde8..00000000
--- a/include/gudhi/Skeleton_blocker.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_H_
-#define SKELETON_BLOCKER_H_
-
-#include <gudhi/Skeleton_blocker_complex.h>
-#include <gudhi/Skeleton_blocker_geometric_complex.h>
-#include <gudhi/Skeleton_blocker_simplifiable_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h>
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h>
-
-#include <gudhi/Debug_utils.h>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/** \defgroup skbl Skeleton-Blocker
-@{
-
-\author David Salinas
-
-\section skblintroduction Introduction
-The Skeleton-Blocker data-structure proposes a light encoding for simplicial complexes by storing only an *implicit* representation of its
-simplices
-\cite socg_blockers_2011,\cite blockers2012.
-Intuitively, it just stores the 1-skeleton of a simplicial complex with a graph and the set of its "missing faces" that
-is very small in practice (see next section for a formal definition).
-This data-structure handles all simplicial complexes operations such as
- as simplex enumeration or simplex removal but operations that are particularly efficient
- are operations that do not require simplex enumeration such as edge iteration, link computation or simplex contraction.
-
-
-\section skbldefinitions Definitions
-
-We recall briefly classical definitions of simplicial complexes
- \cite Munkres-elementsalgtop1984.
-An abstract simplex is a finite non-empty set and its dimension is its number of elements minus 1.
-Whenever \f$\tau \subset \sigma\f$ and \f$\tau \neq \emptyset \f$, \f$ \tau \f$ is called a face of
-\f$ \sigma\f$ and \f$ \sigma\f$ is called a coface of \f$ \tau \f$ . Furthermore,
-when \f$ \tau \neq \sigma\f$ we say that \f$ \tau\f$ is a proper-face of \f$ \sigma\f$.
-An abstract simplicial complex is a set of simplices that contains all the faces of its simplices.
-The 1-skeleton of a simplicial complex (or its graph) consists of its elements of dimension lower than 2.
-
- *\image html "ds_representation.png" "Skeleton-blocker representation" width=20cm
-
-
-To encode, a simplicial complex, one can encodes all its simplices.
-In case when this number gets too large,
-a lighter and implicit version consists of encoding only its graph plus some elements called missing faces or blockers.
-A blocker is a simplex of dimension greater than 1
-that does not belong to the complex but whose all proper faces does.
-
-
-Remark that for a clique complex (i.e. a simplicial complex whose simplices are cliques of its graph), the set of blockers
-is empty and the data-structure is then particularly sparse.
-One famous example of clique-complex is the Rips complex which is intensively used
-in topological data-analysis.
-In practice, the set of blockers of a simplicial complex
-remains also small when simplifying a Rips complex with edge contractions
-but also for most of the simplicial complexes used in topological data-analysis such as Delaunay, Cech or Witness complexes.
-For instance, the numbers of blockers is depicted for random 3-dimensional spheres embedded into \f$R^4\f$
-in next figure. Storing the graph and blockers of such simplicial complexes is much compact in this case than storing
-their simplices.
-
-
- *\image html "blockers_curve.png" "Number of blockers of random triangulations of 3-spheres" width=10cm
-
-
-
-
-\section API
-
-\subsection Overview
-
-Two main classes of this package are Skeleton_blocker_complex and Skeleton_blocker_geometric_complex.
-The first one can be used to represent an abstract simplicial complex and supports most used
-operations in a simplicial complex such as :
-
-\li vertex/edge/simplex enumeration
-\li simplifications operations such as remove star, add star (e.g. general form of collapse),
-edge contractions
-
-The class Skeleton_blocker_geometric_complex supports the same methods as Skeleton_blocker_complex
-and point access in addition.
-
-
-
-\subsection skblvisitor Visitor
-
-The class Skeleton_blocker_complex has a visitor that is called when usual operations such as adding an edge or remove a vertex are called.
-You may want to use this visitor to compute statistics or to update another data-structure (for instance this visitor is heavily used in the \ref contr package).
-
-
-
-
-\section skblexample Example
-
-
-\subsection Iterating Iterating through vertices, edges, blockers and simplices
-
-Iteration through vertices, edges, simplices or blockers is straightforward with c++11 for range loops.
-Note that simplex iteration with this implicit data-structure just takes
-a few more time compared to iteration via an explicit representation
-such as the Simplex Tree. The following example computes the Euler Characteristic
-of a simplicial complex.
-
- \code{.cpp}
- typedef Skeleton_blocker_complex<Skeleton_blocker_simple_traits> Complex;
- typedef Complex::Vertex_handle Vertex_handle;
- typedef Complex::Simplex Simplex;
-
- const int n = 15;
-
- // build a full complex with 10 vertices and 2^n-1 simplices
- Complex complex;
- for(int i=0;i<n;i++)
- complex.add_vertex();
- for(int i=0;i<n;i++)
- for(int j=0;j<i;j++)
- complex.add_edge_without_blockers(Vertex_handle(i),Vertex_handle(j));
-
- // this is just to illustrate iterators, to count number of vertices
- // or edges, complex.num_vertices() and complex.num_edges() are
- // more appropriated!
- unsigned num_vertices = 0;
- for(auto v : complex.vertex_range()){
- ++num_vertices;
- }
-
- unsigned num_edges = 0;
- for(auto e : complex.edge_range())
- ++num_edges;
-
- unsigned euler = 0;
- unsigned num_simplices = 0;
- // we use a reference to a simplex instead of a copy
- // value here because a simplex is a set of integers
- // and copying it cost time
- for(const Simplex & s : complex.star_simplex_range()){
- ++num_simplices;
- if(s.dimension()%2 == 0)
- euler += 1;
- else
- euler -= 1;
- }
- std::cout << "Saw "<<num_vertices<<" vertices, "<<num_edges<<" edges and "<<num_simplices<<" simplices"<<std::endl;
- std::cout << "The Euler Characteristic is "<<euler<<std::endl;
- \endcode
-
-
-\verbatim
-./SkeletonBlockerIteration
-Saw 15 vertices, 105 edges and 32767 simplices
-The Euler Characteristic is 1
- 0.537302s wall, 0.530000s user + 0.000000s system = 0.530000s CPU (98.6%)
-\endverbatim
-
-
-\subsection s Constructing a skeleton-blockers from a list of maximal faces or from a list of faces
-
- \code{.cpp}
- std::vector<Simplex> simplices;
-
- //add 4 triangles of a tetrahedron 0123
- simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1),Vertex_handle(2)));
- simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2),Vertex_handle(3)));
- simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(2)));
- simplices.push_back(Simplex(Vertex_handle(3),Vertex_handle(0),Vertex_handle(1)));
-
- Complex complex;
- //get complex from top faces
- make_complex_from_top_faces(complex,simplices.begin(),simplices.end());
-
- std::cout << "Simplices:"<<std::endl;
- for(const Simplex & s : complex.star_simplex_range())
- std::cout << s << " ";
- std::cout << std::endl;
-
- //One blocker as simplex 0123 is not in the complex but all its proper faces are.
- std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl;
-
- //now build a complex from its full list of simplices
- simplices.clear();
- simplices.push_back(Simplex(Vertex_handle(0)));
- simplices.push_back(Simplex(Vertex_handle(1)));
- simplices.push_back(Simplex(Vertex_handle(2)));
- simplices.push_back(Simplex(Vertex_handle(0),Vertex_handle(1)));
- simplices.push_back(Simplex(Vertex_handle(1),Vertex_handle(2)));
- simplices.push_back(Simplex(Vertex_handle(2),Vertex_handle(0)));
- complex = Complex(simplices.begin(),simplices.end());
-
- std::cout << "Simplices:"<<std::endl;
- for(const Simplex & s : complex.star_simplex_range())
- std::cout << s << " ";
- std::cout << std::endl;
-
- //One blocker as simplex 012 is not in the complex but all its proper faces are.
- std::cout << "Blockers: "<<complex.blockers_to_string()<<std::endl;
- \endcode
-\verbatim
-./SkeletonBlockerFromSimplices
-Simplices:
-{0} {0,1} {0,2} {0,3} {0,1,2} {0,1,3} {0,2,3} {1} {1,2} {1,3} {1,2,3} {2} {2,3} {3}
-Blockers: {0,1,2,3}
-
-Simplices:
-{0} {0,1} {0,2} {1} {1,2} {2}
-Blockers: {0,1,2}
-\endverbatim
-
-
-\section Acknowledgements
-The author wishes to thank Dominique Attali and André Lieutier for
-their collaboration to write the two initial papers
-\cite socg_blockers_2011,\cite blockers2012
- about this data-structure
- and also Dominique for leaving him use a prototype.
-
-@} */
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h
deleted file mode 100644
index 6c6a8638..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-// TODO(DS): to be constified
-
-/**
- *@class Skeleton_blocker_complex_visitor
- *@brief Interface for a visitor of a simplicial complex.
- */
-template<typename Vertex_handle>
-class Skeleton_blocker_complex_visitor {
- public:
- virtual ~Skeleton_blocker_complex_visitor() { }
-
- virtual void on_add_vertex(Vertex_handle) = 0;
- virtual void on_remove_vertex(Vertex_handle) = 0;
-
- virtual void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) = 0;
- virtual void on_remove_edge(Vertex_handle a, Vertex_handle b) = 0;
-
- /**
- * @brief Called when an edge changes, during the contraction of
- * an edge
- */
- virtual void on_changed_edge(Vertex_handle a, Vertex_handle b) = 0;
-
- /**
- * @brief Called when performing an edge contraction when
- * an edge bx is replaced by an edge ax (not already present).
- * Precisely, this methods is called this way in contract_edge :
- * add_edge_without_blockers(a,x)
- * on_swaped_edge(a,b,x)
- * remove_edge(b,x)
- */
- virtual void on_swaped_edge(Vertex_handle a, Vertex_handle b,
- Vertex_handle x) = 0;
- virtual void on_add_blocker(
- const Skeleton_blocker_simplex<Vertex_handle>&) = 0;
- virtual void on_delete_blocker(
- const Skeleton_blocker_simplex<Vertex_handle>*) = 0;
-};
-
-/**
- *@class Dummy_complex_visitor
- *@brief A dummy visitor of a simplicial complex that does nothing
- *
- */
-template<typename Vertex_handle>
-class Dummy_complex_visitor : public Skeleton_blocker_complex_visitor<
-Vertex_handle> {
- public:
- void on_add_vertex(Vertex_handle) { }
-
- void on_remove_vertex(Vertex_handle) { }
-
- void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) { }
-
- void on_remove_edge(Vertex_handle a, Vertex_handle b) { }
-
- void on_changed_edge(Vertex_handle a, Vertex_handle b) { }
-
- void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) { }
-
- void on_add_blocker(const Skeleton_blocker_simplex<Vertex_handle>&) { }
-
- void on_delete_blocker(const Skeleton_blocker_simplex<Vertex_handle>*) { }
-};
-
-/**
- *@class Print_complex_visitor
- *@brief A visitor that prints the visit information.
- *
- */
-template<typename Vertex_handle>
-class Print_complex_visitor : public Skeleton_blocker_complex_visitor<
-Vertex_handle> {
- public:
- void on_add_vertex(Vertex_handle v) {
- std::cerr << "on_add_vertex:" << v << std::endl;
- }
-
- void on_remove_vertex(Vertex_handle v) {
- std::cerr << "on_remove_vertex:" << v << std::endl;
- }
-
- void on_add_edge_without_blockers(Vertex_handle a, Vertex_handle b) {
- std::cerr << "on_add_edge_without_blockers:" << a << "," << b << std::endl;
- }
-
- void on_remove_edge(Vertex_handle a, Vertex_handle b) {
- std::cerr << "on_remove_edge:" << a << "," << b << std::endl;
- }
-
- void on_changed_edge(Vertex_handle a, Vertex_handle b) {
- std::cerr << "on_changed_edge:" << a << "," << b << std::endl;
- }
-
- void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) {
- std::cerr << "on_swaped_edge:" << a << "," << b << "," << x << std::endl;
- }
-
- void on_add_blocker(const Skeleton_blocker_simplex<Vertex_handle>& b) {
- std::cerr << "on_add_blocker:" << b << std::endl;
- }
-
- void on_delete_blocker(const Skeleton_blocker_simplex<Vertex_handle>* b) {
- std::cerr << "on_delete_blocker:" << b << std::endl;
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_COMPLEX_VISITOR_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h
deleted file mode 100644
index feab7b3f..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
-
-#include <gudhi/Skeleton_blocker_link_complex.h>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-template<class ComplexType> class Skeleton_blocker_sub_complex;
-
-/**
- * \brief Class representing the link of a simplicial complex encoded by a skeleton/blockers pair.
- * It computes only vertices greater than the simplex used to build the link.
- */
-template<typename ComplexType>
-class Skeleton_blocker_link_superior : public Skeleton_blocker_link_complex<
-ComplexType> {
- typedef typename ComplexType::Edge_handle Edge_handle;
-
- typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
-
- public:
- typedef typename ComplexType::Vertex_handle Vertex_handle;
- typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
- typedef typename ComplexType::Simplex Simplex;
- typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
- typedef typename ComplexType::BlockerMap BlockerMap;
- typedef typename ComplexType::BlockerPair BlockerPair;
- typedef typename ComplexType::BlockerMapIterator BlockerMapIterator;
- typedef typename ComplexType::BlockerMapConstIterator BlockerMapConstIterator;
- typedef typename ComplexType::Simplex::Simplex_vertex_const_iterator AddressSimplexConstIterator;
- typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator IdSimplexConstIterator;
-
- Skeleton_blocker_link_superior()
- : Skeleton_blocker_link_complex<ComplexType>(true) { }
-
- Skeleton_blocker_link_superior(const ComplexType & parent_complex,
- Simplex& alpha_parent_adress)
- : Skeleton_blocker_link_complex<ComplexType>(parent_complex,
- alpha_parent_adress, true) { }
-
- Skeleton_blocker_link_superior(const ComplexType & parent_complex,
- Vertex_handle a_parent_adress)
- : Skeleton_blocker_link_complex<ComplexType>(parent_complex,
- a_parent_adress, true) { }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_LINK_SUPERIOR_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h
deleted file mode 100644
index 56009daf..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_off_io.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
-
-#include <gudhi/Off_reader.h>
-
-#include <string>
-#include <vector>
-#include <map>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- *@brief Off reader visitor that can be passed to Off_reader to read a Skeleton_blocker_complex.
- */
-template<typename Complex>
-class Skeleton_blocker_off_flag_visitor_reader {
- Complex& complex_;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Point Point;
-
- const bool load_only_points_;
-
- public:
- explicit Skeleton_blocker_off_flag_visitor_reader(Complex& complex, bool load_only_points = false) :
- complex_(complex),
- load_only_points_(load_only_points) { }
-
- void init(int dim, int num_vertices, int num_faces, int num_edges) {
- // TODO(DS): do an assert to check that this number are correctly read
- // TODO(DS): reserve size for vector points
- }
-
- void point(const std::vector<double>& point) {
- complex_.add_vertex(Point(point.begin(), point.end()));
- }
-
- void maximal_face(const std::vector<int>& face) {
- if (!load_only_points_) {
- for (size_t i = 0; i < face.size(); ++i)
- for (size_t j = i + 1; j < face.size(); ++j) {
- complex_.add_edge_without_blockers(Vertex_handle(face[i]), Vertex_handle(face[j]));
- }
- }
- }
-
- void done() { }
-};
-
-/**
- *@brief Off reader visitor that can be passed to Off_reader to read a Skeleton_blocker_complex.
- */
-template<typename Complex>
-class Skeleton_blocker_off_visitor_reader {
- Complex& complex_;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Simplex Simplex;
- typedef typename Complex::Point Point;
-
- const bool load_only_points_;
- std::vector<Point> points_;
- std::vector<Simplex> maximal_faces_;
-
- public:
- explicit Skeleton_blocker_off_visitor_reader(Complex& complex, bool load_only_points = false) :
- complex_(complex),
- load_only_points_(load_only_points) { }
-
- void init(int dim, int num_vertices, int num_faces, int num_edges) {
- maximal_faces_.reserve(num_faces);
- points_.reserve(num_vertices);
- }
-
- void point(const std::vector<double>& point) {
- points_.emplace_back(point.begin(), point.end());
- }
-
- void maximal_face(const std::vector<int>& face) {
- if (!load_only_points_) {
- Simplex s;
- for (auto x : face)
- s.add_vertex(Vertex_handle(x));
- maximal_faces_.emplace_back(s);
- }
- }
-
- void done() {
- complex_ = make_complex_from_top_faces<Complex>(maximal_faces_.begin(), maximal_faces_.end(),
- points_.begin(), points_.end());
- }
-};
-
-/**
- *@brief Class that allows to load a Skeleton_blocker_complex from an off file.
- */
-template<typename Complex>
-class Skeleton_blocker_off_reader {
- public:
- /**
- * name_file : file to read
- * read_complex : complex that will receive the file content
- * read_only_points : specify true if only the points must be read
- */
- Skeleton_blocker_off_reader(const std::string & name_file, Complex& read_complex,
- bool read_only_points = false, bool is_flag = false) : valid_(false) {
- std::ifstream stream(name_file);
- if (stream.is_open()) {
- if (is_flag || read_only_points) {
- Skeleton_blocker_off_flag_visitor_reader<Complex> off_visitor(read_complex, read_only_points);
- Off_reader off_reader(stream);
- valid_ = off_reader.read(off_visitor);
- } else {
- Skeleton_blocker_off_visitor_reader<Complex> off_visitor(read_complex, read_only_points);
- Off_reader off_reader(stream);
- valid_ = off_reader.read(off_visitor);
- }
- }
- }
-
- /**
- * return true if reading did not meet problems.
- */
- bool is_valid() const {
- return valid_;
- }
-
- private:
- bool valid_;
-};
-
-template<typename Complex>
-class Skeleton_blocker_off_writer {
- public:
- /**
- * name_file : file where the off will be written
- * save_complex : complex that be outputted in the file
- * for now only save triangles.
- */
- Skeleton_blocker_off_writer(const std::string & name_file, const Complex& save_complex) {
- typedef typename Complex::Vertex_handle Vertex_handle;
-
- std::ofstream stream(name_file);
- if (stream.is_open()) {
- stream << "OFF\n";
- size_t num_triangles = std::distance(save_complex.triangle_range().begin(), save_complex.triangle_range().end());
- stream << save_complex.num_vertices() << " " << num_triangles << " 0 \n";
-
- // in case the complex has deactivated some vertices, eg only has vertices 0 2 5 7 for instance
- // we compute a map from 0 2 5 7 to 0 1 2 3
- std::map<Vertex_handle, size_t> vertex_num;
- size_t current_vertex = 0;
-
- for (auto v : save_complex.vertex_range()) {
- vertex_num[v] = current_vertex++;
- const auto& pt(save_complex.point(v));
- for (auto x : pt)
- stream << x << " ";
- stream << std::endl;
- }
-
- for (const auto & t : save_complex.triangle_range()) {
- stream << "3 ";
- for (auto x : t)
- stream << vertex_num[x] << " ";
- stream << std::endl;
- }
- stream.close();
- } else {
- std::cerr << "could not open file " << name_file << std::endl;
- }
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_OFF_IO_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h
deleted file mode 100644
index 22c1668e..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_geometric_traits.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h>
-
-#include <string>
-#include <sstream>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * @extends SkeletonBlockerGeometricDS
- * @ingroup skbl
- * @brief Simple traits that is a model of SkeletonBlockerGeometricDS and
- * can be passed as a template argument to Skeleton_blocker_geometric_complex
- */
-template<typename GeometryTrait>
-struct Skeleton_blocker_simple_geometric_traits :
-public Skeleton_blocker_simple_traits {
- public:
- typedef GeometryTrait GT;
- typedef typename GT::Point Point;
- typedef typename Skeleton_blocker_simple_traits::Root_vertex_handle Root_vertex_handle;
- typedef typename Skeleton_blocker_simple_traits::Graph_vertex Simple_vertex;
-
- /**
- * @brief Vertex with a point attached.
- */
- class Simple_geometric_vertex : public Simple_vertex {
- template<class ComplexGeometricTraits> friend class Skeleton_blocker_geometric_complex;
- private:
- Point point_;
-
- Point& point() {
- return point_;
- }
-
- const Point& point() const {
- return point_;
- }
- };
-
- class Simple_geometric_edge :
- public Skeleton_blocker_simple_traits::Graph_edge {
- int index_;
- public:
- Simple_geometric_edge()
- : Skeleton_blocker_simple_traits::Graph_edge(),
- index_(-1) { }
-
- /**
- * @brief Allows to modify the index of the edge.
- * The indices of the edge are used to store heap information
- * in the edge contraction algorithm.
- */
- int& index() {
- return index_;
- }
-
- int index() const {
- return index_;
- }
- };
-
- typedef Simple_geometric_vertex Graph_vertex;
- typedef Skeleton_blocker_simple_traits::Graph_edge Graph_edge;
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_GEOMETRIC_TRAITS_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h
deleted file mode 100644
index 144f1fd0..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simple_traits.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
-
-#include <string>
-#include <sstream>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * @extends SkeletonBlockerDS
- * @ingroup skbl
- * @brief Simple traits that is a model of SkeletonBlockerDS and
- * can be passed as a template argument to Skeleton_blocker_complex
- */
-struct Skeleton_blocker_simple_traits {
- /**
- * @brief Global and local handle similar to <a href="http://www.boost.org/doc/libs/1_38_0/libs/graph/doc/subgraph.html">boost subgraphs</a>.
- * Vertices are stored in a vector.
- * For the root simplicial complex, the local and global descriptors are the same.
- * For a subcomplex L and one of its vertices 'v', the local descriptor of 'v' is its position in
- * the vertex vector of the subcomplex L whereas its global descriptor is the position of 'v'
- * in the vertex vector of the root simplicial complex.
- */
- struct Root_vertex_handle {
- typedef int boost_vertex_handle;
-
- explicit Root_vertex_handle(boost_vertex_handle val = -1)
- : vertex(val) { }
- boost_vertex_handle vertex;
-
- bool operator!=(const Root_vertex_handle& other) const {
- return !(this->vertex == other.vertex);
- }
-
- bool operator==(const Root_vertex_handle& other) const {
- return this->vertex == other.vertex;
- }
-
- bool operator<(const Root_vertex_handle& other) const {
- return this->vertex < other.vertex;
- }
-
- friend std::ostream& operator<<(std::ostream& o,
- const Root_vertex_handle & v) {
- o << v.vertex;
- return o;
- }
- };
-
- struct Vertex_handle {
- typedef int boost_vertex_handle;
-
- explicit Vertex_handle(boost_vertex_handle val = -1)
- : vertex(val) { }
-
- operator int() const {
- return static_cast<int> (vertex);
- }
-
- boost_vertex_handle vertex;
-
- bool operator==(const Vertex_handle& other) const {
- return this->vertex == other.vertex;
- }
-
- bool operator!=(const Vertex_handle& other) const {
- return this->vertex != other.vertex;
- }
-
- bool operator<(const Vertex_handle& other) const {
- return this->vertex < other.vertex;
- }
-
- friend std::ostream& operator<<(std::ostream& o, const Vertex_handle & v) {
- o << v.vertex;
- return o;
- }
- };
-
- class Graph_vertex {
- bool is_active_;
- Root_vertex_handle id_;
-
- public:
- virtual ~Graph_vertex() { }
-
- void activate() {
- is_active_ = true;
- }
-
- void deactivate() {
- is_active_ = false;
- }
-
- bool is_active() const {
- return is_active_;
- }
-
- void set_id(Root_vertex_handle i) {
- id_ = i;
- }
-
- Root_vertex_handle get_id() const {
- return id_;
- }
-
- virtual std::string to_string() const {
- std::ostringstream res;
- res << id_;
- return res.str();
- }
-
- friend std::ostream& operator<<(std::ostream& o, const Graph_vertex & v) {
- o << v.to_string();
- return o;
- }
- };
-
- class Graph_edge {
- Root_vertex_handle a_;
- Root_vertex_handle b_;
- int index_;
-
- public:
- Graph_edge()
- : a_(-1),
- b_(-1),
- index_(-1) { }
-
- int& index() {
- return index_;
- }
-
- int index() const {
- return index_;
- }
-
- void setId(Root_vertex_handle a, Root_vertex_handle b) {
- a_ = a;
- b_ = b;
- }
-
- Root_vertex_handle first() const {
- return a_;
- }
-
- Root_vertex_handle second() const {
- return b_;
- }
-
- friend std::ostream& operator<<(std::ostream& o, const Graph_edge & v) {
- o << "(" << v.a_ << "," << v.b_ << " - id = " << v.index();
- return o;
- }
- };
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLE_TRAITS_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h
deleted file mode 100644
index d7193157..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h
+++ /dev/null
@@ -1,374 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
-
-#include <cassert>
-#include <iostream>
-#include <set>
-#include <vector>
-#include <initializer_list>
-#include <string>
-#include <algorithm>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- *@brief Abstract simplex used in Skeleton blockers data-structure.
- *
- * An abstract simplex is represented as an ordered set of T elements,
- * each element representing a vertex.
- *
- * The element representing a vertex can be SkeletonBlockerDS::Vertex_handle or SkeletonBlockerDS::Root_vertex_handle.
- *
- *
- */
-template<typename T>
-
-class Skeleton_blocker_simplex {
- private:
- std::set<T> simplex_set;
-
- public:
- typedef typename T::boost_vertex_handle boost_vertex_handle;
-
- typedef T Vertex_handle;
-
- typedef typename std::set<T>::const_iterator Simplex_vertex_const_iterator;
- typedef typename std::set<T>::iterator Simplex_vertex_iterator;
-
- /** @name Constructors / Destructors / Initialization
- */
- //@{
-
- void clear() {
- simplex_set.clear();
- }
-
- Skeleton_blocker_simplex(std::initializer_list<T>& list) {
- std::for_each(list.begin(), list.end(), [&] (T const& elt) {
- add_vertex(elt);
- });
- }
-
- template<typename ... Args>
- explicit Skeleton_blocker_simplex(Args ... args) {
- add_vertices(args...);
- }
-
- template<typename ... Args>
- void add_vertices(T v, Args ... args) {
- add_vertex(v);
- add_vertices(args...);
- }
-
- void add_vertices(T v) {
- add_vertex(v);
- }
-
- void add_vertices() { }
-
- /**
- * Initialize a simplex with a string such as {0,1,2}
- */
- explicit Skeleton_blocker_simplex(std::string token) {
- clear();
- if ((token[0] == '{') && (token[token.size() - 1] == '}')) {
- token.erase(0, 1);
- token.erase(token.size() - 1, 1);
- while (token.size() != 0) {
- int coma_position = token.find_first_of(',');
- // cout << "coma_position:"<<coma_position<<endl;
- std::string n = token.substr(0, coma_position);
- // cout << "token:"<<token<<endl;
- token.erase(0, n.size() + 1);
- add_vertex((T) (atoi(n.c_str())));
- }
- }
- }
-
- //@}
-
- /** @name Simplex manipulation
- */
- //@{
- /**
- * Add the vertex v to the simplex:
- * Note that adding two times the same vertex is
- * the same that adding it once.
- */
- void add_vertex(T v) {
- simplex_set.insert(v);
- }
-
- /**
- * Remove the vertex v from the simplex:
- */
- void remove_vertex(T v) {
- simplex_set.erase(v);
- }
-
- /**
- * Intersects the simplex with the simplex a.
- */
- void intersection(const Skeleton_blocker_simplex & a) {
- std::vector<T> v;
- v.reserve((std::min)(simplex_set.size(), a.simplex_set.size()));
-
- set_intersection(simplex_set.begin(), simplex_set.end(),
- a.simplex_set.begin(), a.simplex_set.end(),
- std::back_inserter(v));
- clear();
- for (auto i : v)
- simplex_set.insert(i);
- }
-
- /**
- * Substracts a from the simplex.
- */
- void difference(const Skeleton_blocker_simplex & a) {
- std::vector<T> v;
- v.reserve(simplex_set.size());
-
- set_difference(simplex_set.begin(), simplex_set.end(),
- a.simplex_set.begin(), a.simplex_set.end(),
- std::back_inserter(v));
-
- clear();
- for (auto i : v)
- simplex_set.insert(i);
- }
-
- /**
- * Add vertices of a to the simplex.
- */
- void union_vertices(const Skeleton_blocker_simplex & a) {
- std::vector<T> v;
- v.reserve(simplex_set.size() + a.simplex_set.size());
-
- set_union(simplex_set.begin(), simplex_set.end(), a.simplex_set.begin(),
- a.simplex_set.end(), std::back_inserter(v));
- clear();
- simplex_set.insert(v.begin(), v.end());
- }
-
- typename std::set<T>::const_iterator begin() const {
- return simplex_set.cbegin();
- }
-
- typename std::set<T>::const_iterator end() const {
- return simplex_set.cend();
- }
-
- typename std::set<T>::const_reverse_iterator rbegin() const {
- return simplex_set.crbegin();
- }
-
- typename std::set<T>::const_reverse_iterator rend() const {
- return simplex_set.crend();
- }
-
- typename std::set<T>::iterator begin() {
- return simplex_set.begin();
- }
-
- typename std::set<T>::iterator end() {
- return simplex_set.end();
- }
-
- //@}
-
- /** @name Queries
- */
- //@{
- /**
- * Returns the dimension of the simplex.
- */
- int dimension() const {
- return (simplex_set.size() - 1);
- }
-
- bool empty() const {
- return simplex_set.empty();
- }
-
- /**
- * Returns the first and smallest vertex of the simplex.
- *
- * Be careful : assumes the simplex is non-empty.
- */
- T first_vertex() const {
- assert(!empty());
- return *(begin());
- }
-
- /**
- * Returns the last and greatest vertex of the simplex.
- *
- * Be careful : assumes the simplex is non-empty.
- */
- T last_vertex() const {
- assert(!empty());
- return *(simplex_set.rbegin());
- }
-
- /**
- * @return true iff the simplex contains the simplex a.
- */
- bool contains(const Skeleton_blocker_simplex & a) const {
- return includes(simplex_set.cbegin(), simplex_set.cend(),
- a.simplex_set.cbegin(), a.simplex_set.cend());
- }
-
- /**
- * @return true iff the simplex contains the difference \f$ a \setminus b \f$.
- */
- bool contains_difference(const Skeleton_blocker_simplex& a,
- const Skeleton_blocker_simplex& b) const {
- auto first1 = begin();
- auto last1 = end();
-
- auto first2 = a.begin();
- auto last2 = a.end();
-
- while (first2 != last2) {
- // we ignore vertices of b
- if (b.contains(*first2)) {
- ++first2;
- } else {
- if ((first1 == last1) || (*first2 < *first1))
- return false;
- if (!(*first1 < *first2))
- ++first2;
- ++first1;
- }
- }
- return true;
- }
-
- /**
- * @return true iff the simplex contains the difference \f$ a \setminus \{ x \} \f$.
- */
- bool contains_difference(const Skeleton_blocker_simplex& a, T x) const {
- auto first1 = begin();
- auto last1 = end();
-
- auto first2 = a.begin();
- auto last2 = a.end();
-
- while (first2 != last2) {
- // we ignore vertices x
- if (x == *first2) {
- ++first2;
- } else {
- if ((first1 == last1) || (*first2 < *first1))
- return false;
- if (!(*first1 < *first2))
- ++first2;
- ++first1;
- }
- }
- return true;
- }
-
- /**
- * @return true iff the simplex contains the difference \f$ a \setminus \{ x,y \} \f$.
- */
- bool contains_difference(const Skeleton_blocker_simplex& a, T x, T y) const {
- auto first1 = begin();
- auto last1 = end();
-
- auto first2 = a.begin();
- auto last2 = a.end();
-
- while (first2 != last2) {
- // we ignore vertices of x,y
- if (x == *first2 || y == *first2) {
- ++first2;
- } else {
- if ((first1 == last1) || (*first2 < *first1))
- return false;
- if (!(*first1 < *first2))
- ++first2;
- ++first1;
- }
- }
- return true;
- }
-
- bool contains(T v) const {
- return (simplex_set.find(v) != simplex_set.end());
- }
-
- bool disjoint(const Skeleton_blocker_simplex& a) const {
- std::vector<T> v;
- v.reserve(std::min(simplex_set.size(), a.simplex_set.size()));
-
- set_intersection(simplex_set.cbegin(), simplex_set.cend(),
- a.simplex_set.cbegin(), a.simplex_set.cend(),
- std::back_inserter(v));
-
- return (v.size() == 0);
- }
-
- bool operator==(const Skeleton_blocker_simplex& other) const {
- return (this->simplex_set == other.simplex_set);
- }
-
- bool operator!=(const Skeleton_blocker_simplex& other) const {
- return (this->simplex_set != other.simplex_set);
- }
-
- bool operator<(const Skeleton_blocker_simplex& other) const {
- return (std::lexicographical_compare(this->simplex_set.begin(),
- this->simplex_set.end(), other.begin(),
- other.end()));
- }
-
- //@}
-
- friend std::ostream& operator<<(std::ostream& o,
- const Skeleton_blocker_simplex & sigma) {
- bool first = true;
- o << "{";
- for (auto i : sigma) {
- if (first)
- first = false;
- else
- o << ",";
- o << i;
- }
- o << "}";
- return o;
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SIMPLEX_H_
diff --git a/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h b/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h
deleted file mode 100644
index dbfb4042..00000000
--- a/include/gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
-#define SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
-
-#include <gudhi/Skeleton_blocker_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
-#include <gudhi/Debug_utils.h>
-
-#include <map>
-#include <vector>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * @brief Simplicial subcomplex of a complex represented by a skeleton/blockers pair.
- * @extends Skeleton_blocker_complex
- * @details Stores a subcomplex of a simplicial complex.
- * To simplify explanations below, we will suppose that :
- * - K is the root simplicial complex
- * - L is a subcomplex of K.
- *
- * One vertex of K may exists in L but with a different address.
- * To be able to locate the vertices in K from vertices of L, the class
- * stores a map 'adresses' between vertices of K and vertices of L.
- *
- * Note that the type for handle of vertices of L is 'Vertex_handle' and
- * the type for handle of vertices of K is 'Root_vertex_handle'.
- *
- * The template ComplexType is type of the root complex. It allows to know
- * if the subcomplex is geometric or not.
- * It has to be either 'Skeleton_blockers_complex' or 'Skeleton_blockers_geometric_complex'.
- *
- */
-template<typename ComplexType>
-class Skeleton_blocker_sub_complex : public ComplexType {
- protected:
- template<class T> friend class Skeleton_blocker_link_complex;
-
- typedef typename ComplexType::Graph Graph;
- typedef typename ComplexType::Edge_handle Edge_handle;
-
- typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
-
- public:
- using ComplexType::add_vertex;
- using ComplexType::add_edge_without_blockers;
- using ComplexType::add_blocker;
-
- typedef typename ComplexType::Vertex_handle Vertex_handle;
- typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
- typedef typename ComplexType::Simplex Simplex;
- typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
-
- protected:
- /**
- * @brief Determines whether all proper faces of simplex 'sigma' belong to 'link1' \cup 'link2'
- * where 'link1' and 'link2' are subcomplexes of the same complex of type ComplexType
- */
- typedef std::map<Root_vertex_handle, Vertex_handle> IdAddressMap;
- typedef typename IdAddressMap::value_type AddressPair;
- typedef typename IdAddressMap::iterator IdAddressMapIterator;
- typedef typename IdAddressMap::const_iterator IdAddressMapConstIterator;
- std::map<Root_vertex_handle, Vertex_handle> adresses;
-
- public:
- /**
- * Add a vertex 'global' of K to L. When added to L, this vertex will receive
- * another number, addresses(global), its local adress.
- * return the adress where the vertex lay on L.
- * The vertex corresponding to 'global' must not be already present
- * in the complex.
- */
- Vertex_handle add_vertex(Root_vertex_handle global) {
- assert(!this->contains_vertex(global));
- Vertex_handle address(boost::add_vertex(this->skeleton));
- this->num_vertices_++;
- (*this)[address].activate();
- (*this)[address].set_id(global);
- adresses.insert(AddressPair(global, address));
- this->degree_.push_back(0);
- return address;
- }
-
- /**
- * Add an edge (v1_root,v2_root) to the sub-complex.
- * It assumes that both vertices corresponding to v1_root and v2_root are present
- * in the sub-complex.
- */
- void add_edge_without_blockers(Root_vertex_handle v1_root, Root_vertex_handle v2_root) {
- auto v1_sub(this->get_address(v1_root));
- auto v2_sub(this->get_address(v2_root));
- assert(v1_sub && v2_sub);
- this->ComplexType::add_edge_without_blockers(*v1_sub, *v2_sub);
- }
-
- /**
- * Add a blocker to the sub-complex.
- * It assumes that all vertices of blocker_root are present
- * in the sub-complex.
- */
- void add_blocker(const Root_simplex_handle& blocker_root) {
- auto blocker_sub = this->get_address(blocker_root);
- assert(blocker_sub);
- this->add_blocker(new Simplex(*blocker_sub));
- }
-
- public:
- /**
- * Constructs the restricted complex of 'parent_complex' to
- * vertices of 'simplex'.
- */
- void make_restricted_complex(const ComplexType & parent_complex,
- const Simplex& simplex) {
- this->clear();
- // add vertices to the sub complex
- for (auto x : simplex) {
- assert(parent_complex.contains_vertex(x));
- auto x_local = this->add_vertex(parent_complex[x].get_id());
- (*this)[x_local] = parent_complex[x];
- }
-
- // add edges to the sub complex
- for (auto x : simplex) {
- // x_neigh is the neighbor of x intersected with vertices_simplex
- Simplex x_neigh;
- parent_complex.add_neighbours(x, x_neigh, true);
- x_neigh.intersection(simplex);
- for (auto y : x_neigh) {
- this->add_edge_without_blockers(parent_complex[x].get_id(), parent_complex[y].get_id());
- }
- }
-
- // add blockers to the sub complex
- for (auto blocker : parent_complex.const_blocker_range()) {
- // check if it is the first time we encounter the blocker
- if (simplex.contains(*blocker)) {
- Root_simplex_handle blocker_root(parent_complex.get_id(*(blocker)));
- Simplex blocker_restr(
- *(this->get_simplex_address(blocker_root)));
- this->add_blocker(new Simplex(blocker_restr));
- }
- }
- }
-
- void clear() {
- adresses.clear();
- ComplexType::clear();
- }
-
- /**
- * Compute the local vertex in L corresponding to the vertex global in K.
- * runs in O(log n) if n = num_vertices()
- */
- boost::optional<Vertex_handle> get_address(Root_vertex_handle global) const {
- boost::optional < Vertex_handle > res;
- IdAddressMapConstIterator it = adresses.find(global);
- if (it == adresses.end())
- res.reset();
- else
- res = (*it).second;
- return res;
- }
-
- // /**
- // * Allocates a simplex in L corresponding to the simplex s in K
- // * with its local adresses and returns an AddressSimplex.
- // */
- // boost::optional<Simplex> get_address(const Root_simplex_handle & s) const;
-
- // private:
- /**
- * same as get_address except that it will return a simplex in any case.
- * The vertices that were not found are not added.
- */
- // @remark should be private but problem with VS
-
- std::vector<boost::optional<Vertex_handle> > get_addresses(
- const Root_simplex_handle & s) const {
- std::vector < boost::optional<Vertex_handle> > res;
- for (auto i : s) {
- res.push_back(get_address(i));
- }
- return res;
- }
-};
-
-/**
- * @remark remarque perte de temps a creer un nouveau simplexe a chaque fois
- * alors qu'on pourrait utiliser a la place de 'addresses_sigma_in_link'
- * un simplex avec des valeurs sp�ciales ComplexDS::null_vertex par exemple
- * pour indiquer qu'un vertex n'appartient pas au complex
- */
-template<typename ComplexType>
-bool proper_face_in_union(
- Skeleton_blocker_sub_complex<ComplexType> & link,
- std::vector<boost::optional<typename ComplexType::Vertex_handle> > & addresses_sigma_in_link,
- std::size_t vertex_to_be_ignored) {
- // we test that all vertices of 'addresses_sigma_in_link' but 'vertex_to_be_ignored'
- // are in link1 if it is the case we construct the corresponding simplex
- bool vertices_sigma_are_in_link = true;
- typename ComplexType::Simplex sigma_in_link;
- for (std::size_t i = 0; i < addresses_sigma_in_link.size(); ++i) {
- if (i != vertex_to_be_ignored) {
- if (!addresses_sigma_in_link[i]) {
- vertices_sigma_are_in_link = false;
- break;
- } else {
- sigma_in_link.add_vertex(*addresses_sigma_in_link[i]);
- }
- }
- }
- // If one of vertices of the simplex is not in the complex then it returns false
- // Otherwise, it tests if the simplex is in the complex
- return vertices_sigma_are_in_link && link.contains(sigma_in_link);
-}
-
-// Remark: this function should be friend in order to leave get_adresses private
-// however doing so seemes currently not possible due to a visual studio bug c2668
-// "the compiler does not support partial ordering of template functions as specified in the C++ Standard"
-// http://www.serkey.com/error-c2668-ambiguous-call-to-overloaded-function-bb45ft.html
-
-template<typename ComplexType>
-bool proper_faces_in_union(
- Skeleton_blocker_simplex<typename ComplexType::Root_vertex_handle> & sigma,
- Skeleton_blocker_sub_complex<ComplexType> & link1,
- Skeleton_blocker_sub_complex<ComplexType> & link2) {
- typedef typename ComplexType::Vertex_handle Vertex_handle;
- std::vector < boost::optional<Vertex_handle> > addresses_sigma_in_link1 =
- link1.get_addresses(sigma);
- std::vector < boost::optional<Vertex_handle> > addresses_sigma_in_link2 =
- link2.get_addresses(sigma);
-
- for (std::size_t current_index = 0; current_index < addresses_sigma_in_link1.size();
- ++current_index) {
- if (!proper_face_in_union(link1, addresses_sigma_in_link1, current_index)
- && !proper_face_in_union(link2, addresses_sigma_in_link2,
- current_index)) {
- return false;
- }
- }
- return true;
-}
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SKELETON_BLOCKER_SUB_COMPLEX_H_
diff --git a/include/gudhi/Skeleton_blocker/internal/Top_faces.h b/include/gudhi/Skeleton_blocker/internal/Top_faces.h
deleted file mode 100644
index f80ca4fe..00000000
--- a/include/gudhi/Skeleton_blocker/internal/Top_faces.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
-#define SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
-
-#include <list>
-#include <vector>
-#include <set>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-template<typename SimplexHandle>
-std::list<SimplexHandle> subfaces(SimplexHandle top_face) {
- std::list<SimplexHandle> res;
- if (top_face.dimension() == -1) return res;
- if (top_face.dimension() == 0) {
- res.push_back(top_face);
- return res;
- } else {
- auto first_vertex = top_face.first_vertex();
- top_face.remove_vertex(first_vertex);
- res = subfaces(top_face);
- std::list<SimplexHandle> copy = res;
- for (auto& simplex : copy) {
- simplex.add_vertex(first_vertex);
- }
- res.push_back(SimplexHandle(first_vertex));
- res.splice(res.end(), copy);
- return res;
- }
-}
-
-/**
- * add all faces of top_face in simplices_per_dimension
- */
-template<typename SimplexHandle>
-void register_faces(std::vector< std::set<SimplexHandle> >& simplices_per_dimension,
- const SimplexHandle& top_face) {
- std::list<SimplexHandle> subfaces_list = subfaces(top_face);
- for (auto& simplex : subfaces_list) {
- simplices_per_dimension[simplex.dimension()].insert(simplex);
- }
-}
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_INTERNAL_TOP_FACES_H_
diff --git a/include/gudhi/Skeleton_blocker/internal/Trie.h b/include/gudhi/Skeleton_blocker/internal/Trie.h
deleted file mode 100644
index 7a5d38eb..00000000
--- a/include/gudhi/Skeleton_blocker/internal/Trie.h
+++ /dev/null
@@ -1,269 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef SKELETON_BLOCKER_INTERNAL_TRIE_H_
-#define SKELETON_BLOCKER_INTERNAL_TRIE_H_
-
-#include <memory>
-#include <vector>
-#include <deque>
-#include <set>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-template<typename SimplexHandle>
-struct Trie {
- typedef SimplexHandle Simplex;
- typedef typename SimplexHandle::Vertex_handle Vertex_handle;
-
- Vertex_handle v;
- std::vector<std::shared_ptr<Trie> > childs;
- // std::vector<std::unique_ptr<Trie> > childs; -> use of deleted function
- private:
- const Trie* parent_;
-
- public:
- Trie() : parent_(0) { }
-
- Trie(Vertex_handle v_) : v(v_), parent_(0) { }
-
- Trie(Vertex_handle v_, Trie* parent) : v(v_), parent_(parent) { }
-
- bool operator==(const Trie& other) const {
- return (v == other.v);
- }
-
- void add_child(Trie* child) {
- if (child) {
- std::shared_ptr<Trie> ptr_to_add(child);
- childs.push_back(ptr_to_add);
- child->parent_ = this;
- }
- }
-
- typedef typename Simplex::Simplex_vertex_const_iterator Simplex_vertex_const_iterator;
-
- Trie* make_trie(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) {
- if (s_it == s_end) {
- return 0;
- } else {
- Trie* res = new Trie(*s_it);
- Trie* child = make_trie(++s_it, s_end);
- res->add_child(child);
- return res;
- }
- }
-
- private:
- // go down recursively in the tree while advancing the simplex iterator.
- // when it reaches a leaf, it inserts the remaining that is not present
- void add_simplex_helper(Simplex_vertex_const_iterator s_it, Simplex_vertex_const_iterator s_end) {
- assert(*s_it == v);
- ++s_it;
- if (s_it == s_end) return;
- if (!is_leaf()) {
- for (auto child : childs) {
- if (child->v == *s_it)
- return child->add_simplex_helper(s_it, s_end);
- }
- // s_it is not found and needs to be inserted
- }
- // not leaf -> remaining of s needs to be inserted
- Trie * son_with_what_remains_of_s(make_trie(s_it, s_end));
- add_child(son_with_what_remains_of_s);
- return;
- }
-
- void maximal_faces_helper(std::vector<Simplex>& res) const {
- if (is_leaf()) res.push_back(simplex());
- else
- for (auto child : childs)
- child->maximal_faces_helper(res);
- }
-
- public:
- /**
- * adds the simplex to the trie
- */
- void add_simplex(const Simplex& s) {
- if (s.empty()) return;
- assert(v == s.first_vertex());
- add_simplex_helper(s.begin(), s.end());
- }
-
- std::vector<Simplex> maximal_faces() const {
- std::vector<Simplex> res;
- maximal_faces_helper(res);
- return res;
- }
-
- /**
- * Goes to the root in the trie to consitute simplex
- */
- void add_vertices_up_to_the_root(Simplex& res) const {
- res.add_vertex(v);
- if (parent_)
- parent_->add_vertices_up_to_the_root(res);
- }
-
- Simplex simplex() const {
- Simplex res;
- add_vertices_up_to_the_root(res);
- return res;
- }
-
- bool is_leaf() const {
- return childs.empty();
- }
-
- bool is_root() const {
- return parent_ == 0;
- }
-
- const Trie* parent() {
- return parent_;
- }
-
- void remove_leaf() {
- assert(is_leaf());
- if (!is_root())
- parent_->childs.erase(this);
- }
-
- /**
- * true iff the simplex corresponds to one node in the trie
- */
- bool contains(const Simplex& s) const {
- Trie const* current = this;
- if (s.empty()) return true;
- if (current->v != s.first_vertex()) return false;
- auto s_pos = s.begin();
- ++s_pos;
- while (s_pos != s.end() && current != 0) {
- bool found = false;
- for (const auto child : current->childs) {
- if (child->v == *s_pos) {
- ++s_pos;
- current = child.get();
- found = true;
- break;
- }
- }
- if (!found) return false;
- }
- return current != 0;
- }
-
- Trie* go_bottom_left() {
- if (is_leaf())
- return this;
- else
- return (*childs.begin())->go_bottom_left();
- }
-
- friend std::ostream& operator<<(std::ostream& stream, const Trie& trie) {
- stream << "T( " << trie.v << " ";
- for (auto t : trie.childs)
- stream << *t;
- stream << ")";
- return stream;
- }
-};
-
-template<typename SimplexHandle>
-struct Tries {
- typedef typename SimplexHandle::Vertex_handle Vertex_handle;
- typedef SimplexHandle Simplex;
-
- typedef Trie<Simplex> STrie;
-
- template<typename SimpleHandleOutputIterator>
- Tries(unsigned num_vertices, SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end) :
- cofaces_(num_vertices, 0) {
- for (auto i = 0u; i < num_vertices; ++i)
- cofaces_[i] = new STrie(Vertex_handle(i));
- for (auto s_it = simplex_begin; s_it != simplex_end; ++s_it) {
- if (s_it->dimension() >= 1)
- cofaces_[s_it->first_vertex()]->add_simplex(*s_it);
- }
- }
-
- ~Tries() {
- for (STrie* t : cofaces_)
- delete t;
- }
-
- // return a simplex that consists in all u such uv is an edge and u>v
-
- Simplex positive_neighbors(Vertex_handle v) const {
- Simplex res;
- for (auto child : cofaces_[v]->childs)
- res.add_vertex(child->v);
- return res;
- }
-
- bool contains(const Simplex& s) const {
- auto first_v = s.first_vertex();
- return cofaces_[first_v]->contains(s);
- }
-
- friend std::ostream& operator<<(std::ostream& stream, const Tries& tries) {
- for (auto trie : tries.cofaces_)
- stream << *trie << std::endl;
- return stream;
- }
-
- // init_next_dimension must be called first
-
- std::vector<Simplex> next_dimension_simplices() const {
- std::vector<Simplex> res;
- while (!(to_see_.empty()) && (to_see_.front()->simplex().dimension() == current_dimension_)) {
- res.emplace_back(to_see_.front()->simplex());
- for (auto child : to_see_.front()->childs)
- to_see_.push_back(child.get());
- to_see_.pop_front();
- }
- ++current_dimension_;
- return res;
- }
-
- void init_next_dimension() const {
- for (auto trie : cofaces_)
- to_see_.push_back(trie);
- }
-
- private:
- mutable std::deque<STrie*> to_see_;
- mutable int current_dimension_ = 0;
- std::vector<STrie*> cofaces_;
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_INTERNAL_TRIE_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h
deleted file mode 100644
index 95c5f7ef..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
-
-#include <boost/iterator/iterator_facade.hpp>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * @brief Iterator through the blockers of a vertex.
- */
-// ReturnType = const Simplex* or Simplex*
-// MapIteratorType = BlockerMapConstIterator or BlockerMapIterator
-
-template<typename MapIteratorType, typename ReturnType>
-class Blocker_iterator_internal : public boost::iterator_facade<
-Blocker_iterator_internal<MapIteratorType, ReturnType>,
-ReturnType,
-boost::forward_traversal_tag,
-ReturnType
-> {
- private:
- MapIteratorType current_position;
- MapIteratorType end_of_map;
-
- public:
- Blocker_iterator_internal() : current_position() { }
-
- Blocker_iterator_internal(MapIteratorType position, MapIteratorType end_of_map_) :
- current_position(position), end_of_map(end_of_map_) { }
-
- bool equal(const Blocker_iterator_internal& other) const {
- return current_position == other.current_position;
- }
-
- void increment() {
- goto_next_blocker();
- }
-
- ReturnType dereference() const {
- return (current_position->second);
- }
-
- private:
- /**
- * Let the current pair be (v,sigma) where v is a vertex and sigma is a blocker.
- * If v is not the first vertex of sigma then we already have seen sigma as a blocker
- * and we look for the next one.
- */
- void goto_next_blocker() {
- do {
- ++current_position;
- } while (!(current_position == end_of_map) && !first_time_blocker_is_seen());
- }
-
- bool first_time_blocker_is_seen() const {
- return current_position->first == current_position->second->first_vertex();
- }
-};
-
-/**
- * @brief Iterator through the blockers of a vertex
- */
-// ReturnType = const Simplex* or Simplex*
-// MapIteratorType = BlockerMapConstIterator or BlockerMapIterator
-
-template<typename MapIteratorType, typename ReturnType>
-class Blocker_iterator_around_vertex_internal : public boost::iterator_facade<
-Blocker_iterator_around_vertex_internal<MapIteratorType, ReturnType>,
-ReturnType,
-boost::forward_traversal_tag,
-ReturnType
-> {
- private:
- MapIteratorType current_position_;
-
- public:
- Blocker_iterator_around_vertex_internal() : current_position_() { }
-
- Blocker_iterator_around_vertex_internal(MapIteratorType position) :
- current_position_(position) { }
-
- Blocker_iterator_around_vertex_internal& operator=(Blocker_iterator_around_vertex_internal other) {
- this->current_position_ = other.current_position_;
- return *this;
- }
-
- bool equal(const Blocker_iterator_around_vertex_internal& other) const {
- return current_position_ == other.current_position_;
- }
-
- void increment() {
- current_position_++;
- }
-
- ReturnType dereference() const {
- return (current_position_->second);
- }
-
- MapIteratorType current_position() {
- return this->current_position_;
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_BLOCKERS_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h
deleted file mode 100644
index 5c725aae..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
-
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/graph/adjacency_list.hpp>
-
-#include <utility> // for pair<>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-template<typename SkeletonBlockerComplex>
-class Edge_around_vertex_iterator : public boost::iterator_facade <Edge_around_vertex_iterator<SkeletonBlockerComplex>
-, typename SkeletonBlockerComplex::Edge_handle const, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Edge_handle const> {
- friend class boost::iterator_core_access;
-
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Edge_handle Edge_handle;
-
- private:
- const Complex* complex;
- Vertex_handle v;
-
- boost_adjacency_iterator current_;
- boost_adjacency_iterator end_;
-
- public:
- Edge_around_vertex_iterator() : complex(NULL) { }
-
- Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) :
- complex(complex_),
- v(v_) {
- tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
- }
-
- /**
- * returns an iterator to the end
- */
- Edge_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, int end) :
- complex(complex_),
- v(v_) {
- tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
- set_end();
- }
-
- bool equal(const Edge_around_vertex_iterator& other) const {
- return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_);
- }
-
- void increment() {
- if (current_ != end_)
- ++current_;
- }
-
- Edge_handle dereference() const {
- return *(*complex)[std::make_pair(v, static_cast<Vertex_handle> (*current_))];
- }
-
- private:
- // remove this ugly hack
- void set_end() {
- current_ = end_;
- }
-};
-
-/**
- *@brief Iterator on the edges of a simplicial complex.
- *
- */
-template<typename SkeletonBlockerComplex>
-class Edge_iterator : public boost::iterator_facade <Edge_iterator<SkeletonBlockerComplex>
-, typename SkeletonBlockerComplex::Edge_handle const
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Edge_handle const> {
- friend class boost::iterator_core_access;
-
- public:
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::boost_edge_iterator boost_edge_iterator;
- typedef typename Complex::Edge_handle Edge_handle;
-
- const Complex* complex;
- std::pair<boost_edge_iterator, boost_edge_iterator> edge_iterator;
-
- Edge_iterator() : complex(NULL) { }
-
- Edge_iterator(const SkeletonBlockerComplex* complex_) :
- complex(complex_),
- edge_iterator(boost::edges(complex_->skeleton)) { }
-
- /**
- * return an iterator to the end
- */
- Edge_iterator(const SkeletonBlockerComplex* complex_, int end) :
- complex(complex_),
- edge_iterator(boost::edges(complex_->skeleton)) {
- edge_iterator.first = edge_iterator.second;
- }
-
- bool equal(const Edge_iterator& other) const {
- return (complex == other.complex) && (edge_iterator == other.edge_iterator);
- }
-
- void increment() {
- if (edge_iterator.first != edge_iterator.second) {
- ++(edge_iterator.first);
- }
- }
-
- Edge_handle dereference() const {
- return (*(edge_iterator.first));
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_EDGES_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h
deleted file mode 100644
index 8054e64f..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h
+++ /dev/null
@@ -1,32 +0,0 @@
- /* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
-
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h>
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_edges_iterators.h>
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_blockers_iterators.h>
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h>
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h>
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h
deleted file mode 100644
index e2024652..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_simplices_iterators.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
-
-#include <gudhi/Skeleton_blocker_link_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h>
-#include <gudhi/Skeleton_blocker/internal/Trie.h>
-#include <gudhi/Debug_utils.h>
-
-#include <boost/iterator/iterator_facade.hpp>
-
-#include <memory>
-#include <list>
-#include <iostream>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * Link may be Skeleton_blocker_link_complex<SkeletonBlockerComplex> to iterate over all
- * simplices around a vertex OR
- * Skeleton_blocker_superior_link_complex<SkeletonBlockerComplex> to iterate over all
- * superior vertices around a vertex.
- * The iteration is done by computing a trie with the link and doing a breadth-first traversal
- * of the trie.
- */
-template<typename SkeletonBlockerComplex, typename Link>
-class Simplex_around_vertex_iterator :
-public boost::iterator_facade < Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link>
-, typename SkeletonBlockerComplex::Simplex
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Simplex
-> {
- friend class boost::iterator_core_access;
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Edge_handle Edge_handle;
- typedef typename Complex::Simplex Simplex;
-
- // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion
- typedef typename Link::Vertex_handle Link_vertex_handle;
-
- typedef typename Gudhi::skeleton_blocker::Trie<Simplex> Trie;
-
- private:
- const Complex* complex;
- Vertex_handle v;
- std::shared_ptr<Link> link_v;
- std::shared_ptr<Trie> trie;
- // TODO(DS): use a deque instead
- std::list<Trie*> nodes_to_be_seen;
-
- public:
- Simplex_around_vertex_iterator() : complex(0) { }
-
- Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_) :
- complex(complex_),
- v(v_),
- link_v(new Link(*complex_, v_)),
- trie(new Trie(v_)) {
- compute_trie_and_nodes_to_be_seen();
- }
-
- // TODO(DS): avoid useless copy
- // TODO(DS): currently just work if copy begin iterator
- Simplex_around_vertex_iterator(const Simplex_around_vertex_iterator& other) :
- complex(other.complex),
- v(other.v),
- link_v(other.link_v),
- trie(other.trie),
- nodes_to_be_seen(other.nodes_to_be_seen) {
- if (!other.is_end()) {
- }
- }
-
- /**
- * returns an iterator to the end
- */
- Simplex_around_vertex_iterator(const Complex* complex_, Vertex_handle v_, bool end) :
- complex(complex_),
- v(v_) {
- set_end();
- }
-
- private:
- void compute_trie_and_nodes_to_be_seen() {
- // once we go through every simplices passing through v0
- // we remove v0. That way, it prevents from passing a lot of times
- // though edges leaving v0.
- // another solution would have been to provides an adjacency iterator
- // to superior vertices that avoids lower ones.
- while (!link_v->empty()) {
- auto v0 = *(link_v->vertex_range().begin());
- trie->add_child(build_trie(v0, trie.get()));
- link_v->remove_vertex(v0);
- }
- nodes_to_be_seen.push_back(trie.get());
- }
-
- Trie* build_trie(Link_vertex_handle link_vh, Trie* parent) {
- Trie* res = new Trie(parent_vertex(link_vh), parent);
- for (Link_vertex_handle nv : link_v->vertex_range(link_vh)) {
- if (link_vh < nv) {
- Simplex simplex_node_plus_nv(res->simplex());
- simplex_node_plus_nv.add_vertex(parent_vertex(nv));
- if (complex->contains(simplex_node_plus_nv)) {
- res->add_child(build_trie(nv, res));
- }
- }
- }
- return res;
- }
-
- bool is_node_in_complex(Trie* trie) {
- return true;
- }
-
- Vertex_handle parent_vertex(Link_vertex_handle link_vh) const {
- return complex->convert_handle_from_another_complex(*link_v, link_vh);
- }
-
- public:
- friend std::ostream& operator<<(std::ostream& stream, const Simplex_around_vertex_iterator& savi) {
- stream << savi.trie << std::endl;
- stream << "(" << savi.nodes_to_be_seen.size() << ") nodes to see\n";
- return stream;
- }
-
- bool equal(const Simplex_around_vertex_iterator& other) const {
- bool same_complex = (complex == other.complex);
- if (!same_complex)
- return false;
-
- if (!(v == other.v))
- return false;
-
- bool both_empty = nodes_to_be_seen.empty() && other.nodes_to_be_seen.empty();
- if (both_empty)
- return true;
-
- bool both_non_empty = !nodes_to_be_seen.empty() && !other.nodes_to_be_seen.empty();
-
- // one is empty the other is not
- if (!both_non_empty) return false;
-
- bool same_node = (**(nodes_to_be_seen.begin()) == **(other.nodes_to_be_seen.begin()));
- return same_node;
- }
-
- void increment() {
- assert(!is_end());
- Trie* first_node = nodes_to_be_seen.front();
-
- nodes_to_be_seen.pop_front();
-
- for (auto childs : first_node->childs) {
- nodes_to_be_seen.push_back(childs.get());
- }
- }
-
- Simplex dereference() const {
- assert(!nodes_to_be_seen.empty());
- Trie* first_node = nodes_to_be_seen.front();
- return first_node->simplex();
- }
-
- Simplex get_trie_address() const {
- assert(!nodes_to_be_seen.empty());
- return nodes_to_be_seen.front();
- }
-
- private:
- void set_end() {
- nodes_to_be_seen.clear();
- }
-
- bool is_end() const {
- return nodes_to_be_seen.empty();
- }
-};
-
-template<typename SkeletonBlockerComplex>
-class Simplex_iterator :
-public boost::iterator_facade < Simplex_iterator<SkeletonBlockerComplex>
-, typename SkeletonBlockerComplex::Simplex
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Simplex
-> {
- typedef Skeleton_blocker_link_superior<SkeletonBlockerComplex> Link;
-
- friend class boost::iterator_core_access;
-
- template<class SkBlDS> friend class Skeleton_blocker_complex;
-
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Edge_handle Edge_handle;
- typedef typename Complex::Simplex Simplex;
- typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator;
- typedef typename Link::Vertex_handle Link_vertex_handle;
-
- private:
- const Complex* complex_;
- Complex_vertex_iterator current_vertex_;
-
- typedef Simplex_around_vertex_iterator<SkeletonBlockerComplex, Link> SAVI;
- SAVI current_simplex_around_current_vertex_;
- SAVI simplices_around_current_vertex_end_;
-
- public:
- Simplex_iterator() : complex_(0) { }
-
- Simplex_iterator(const Complex* complex) :
- complex_(complex),
- current_vertex_(complex->vertex_range().begin()),
- current_simplex_around_current_vertex_(complex, *current_vertex_),
- simplices_around_current_vertex_end_(complex, *current_vertex_, true) {
- // should not be called if the complex is empty
- assert(!complex->empty());
- }
-
- private:
- Simplex_iterator(const Complex* complex, bool end) :
- complex_(complex) {
- set_end();
- }
-
- public:
- Simplex_iterator(const Simplex_iterator& other)
- :
- complex_(other.complex_),
- current_vertex_(other.current_vertex_),
- current_simplex_around_current_vertex_(other.current_simplex_around_current_vertex_),
- simplices_around_current_vertex_end_(other.simplices_around_current_vertex_end_) { }
-
- friend Simplex_iterator make_begin_iterator(const Complex* complex) {
- if (complex->empty())
- return make_end_simplex_iterator(complex);
- else
- return Simplex_iterator(complex);
- }
-
- friend Simplex_iterator make_end_simplex_iterator(const Complex* complex) {
- return Simplex_iterator(complex, true);
- }
-
- bool equal(const Simplex_iterator& other) const {
- if (complex_ != other.complex_) return false;
- if (current_vertex_ != other.current_vertex_) return false;
- if (is_end() && other.is_end()) return true;
- if (current_simplex_around_current_vertex_ != other.current_simplex_around_current_vertex_)
- return false;
- return true;
- }
-
- void increment() {
- if (current_simplex_around_current_vertex_ != simplices_around_current_vertex_end_) {
- current_simplex_around_current_vertex_.increment();
- if (current_simplex_around_current_vertex_ == simplices_around_current_vertex_end_)
- goto_next_vertex();
- } else {
- goto_next_vertex();
- }
- }
-
- void goto_next_vertex() {
- current_vertex_.increment();
- if (!is_end()) {
- current_simplex_around_current_vertex_ = SAVI(complex_, *current_vertex_);
- simplices_around_current_vertex_end_ = SAVI(complex_, *current_vertex_, true);
- }
- }
-
- Simplex dereference() const {
- return current_simplex_around_current_vertex_.dereference();
- }
-
- private:
- void set_end() {
- current_vertex_ = complex_->vertex_range().end();
- }
-
- bool is_end() const {
- return (current_vertex_ == complex_->vertex_range().end());
- }
-};
-
-/**
- * Iterator through the maximal faces of the coboundary of a simplex.
- */
-template<typename SkeletonBlockerComplex, typename Link>
-class Simplex_coboundary_iterator :
-public boost::iterator_facade < Simplex_coboundary_iterator<SkeletonBlockerComplex, Link>
-, typename SkeletonBlockerComplex::Simplex, boost::forward_traversal_tag, typename SkeletonBlockerComplex::Simplex> {
- friend class boost::iterator_core_access;
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Edge_handle Edge_handle;
- typedef typename Complex::Simplex Simplex;
- typedef typename Complex::Complex_vertex_iterator Complex_vertex_iterator;
-
- // Link_vertex_handle == Complex_Vertex_handle but this renaming helps avoiding confusion
- typedef typename Link::Vertex_handle Link_vertex_handle;
-
- private:
- const Complex* complex;
- const Simplex& sigma;
- std::shared_ptr<Link> link;
- Complex_vertex_iterator current_vertex;
- Complex_vertex_iterator link_vertex_end;
-
- public:
- Simplex_coboundary_iterator() : complex(0) { }
-
- Simplex_coboundary_iterator(const Complex* complex_, const Simplex& sigma_) :
- complex(complex_),
- sigma(sigma_),
- // need only vertices of the link hence the true flag
- link(new Link(*complex_, sigma_, false, true)) {
- auto link_vertex_range = link->vertex_range();
- current_vertex = link_vertex_range.begin();
- link_vertex_end = link_vertex_range.end();
- }
-
- Simplex_coboundary_iterator(const Simplex_coboundary_iterator& other) :
- complex(other.complex),
- sigma(other.sigma),
- link(other.link),
- current_vertex(other.current_vertex),
- link_vertex_end(other.link_vertex_end) { }
-
- // returns an iterator to the end
- Simplex_coboundary_iterator(const Complex* complex_, const Simplex& sigma_, bool end) :
- complex(complex_),
- sigma(sigma_) {
- // to represent an end iterator without having to build a useless link, we use
- // the convection that link is not initialized.
- }
-
- private:
- Vertex_handle parent_vertex(Link_vertex_handle link_vh) const {
- return complex->convert_handle_from_another_complex(*link, link_vh);
- }
-
- public:
- friend std::ostream& operator<<(std::ostream& stream, const Simplex_coboundary_iterator& sci) {
- return stream;
- }
-
- // assume that iterator points to the same complex and comes from the same simplex
- bool equal(const Simplex_coboundary_iterator& other) const {
- assert(complex == other.complex && sigma == other.sigma);
- if (is_end()) return other.is_end();
- if (other.is_end()) return is_end();
- return *current_vertex == *(other.current_vertex);
- }
-
- void increment() {
- ++current_vertex;
- }
-
- Simplex dereference() const {
- Simplex res(sigma);
- res.add_vertex(parent_vertex(*current_vertex));
- return res;
- }
-
- private:
- bool is_end() const {
- return !link || current_vertex == link_vertex_end;
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_SIMPLICES_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h
deleted file mode 100644
index a834fe1d..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_triangles_iterators.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
-
-#include <boost/iterator/iterator_facade.hpp>
-#include <memory>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * \brief Iterator over the triangles that are
- * adjacent to a vertex of the simplicial complex.
- * \remark Will be removed soon -> dont look
- */
-template<typename Complex, typename LinkType>
-class Triangle_around_vertex_iterator : public boost::iterator_facade
-< Triangle_around_vertex_iterator <Complex, LinkType>
-, typename Complex::Simplex const
-, boost::forward_traversal_tag
-, typename Complex::Simplex const> {
- friend class boost::iterator_core_access;
- template<typename T> friend class Triangle_iterator;
- private:
- typedef typename LinkType::Vertex_handle Vertex_handle;
- typedef typename LinkType::Root_vertex_handle Root_vertex_handle;
- typedef typename LinkType::Simplex Simplex;
- typedef typename Complex::Complex_edge_iterator Complex_edge_iterator_;
-
- const Complex* complex_;
- Vertex_handle v_;
- std::shared_ptr<LinkType> link_;
- Complex_edge_iterator_ current_edge_;
- bool is_end_;
-
- public:
- Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v) :
- complex_(complex), v_(v), link_(new LinkType(*complex, v_)),
- current_edge_(link_->edge_range().begin()),
- is_end_(current_edge_ == link_->edge_range().end()) { }
-
- /**
- * @brief ugly hack to get an iterator to the end
- */
- Triangle_around_vertex_iterator(const Complex* complex, Vertex_handle v, bool is_end) :
- complex_(complex), v_(v), link_(0), is_end_(true) { }
-
- /**
- * @brief ugly hack to get an iterator to the end
- */
- Triangle_around_vertex_iterator() :
- complex_(0), v_(-1), link_(0), is_end_(true) { }
-
- Triangle_around_vertex_iterator(const Triangle_around_vertex_iterator& other) {
- v_ = other.v_;
- complex_ = other.complex_;
- is_end_ = other.is_end_;
-
- if (!is_end_) {
- link_ = other.link_;
- current_edge_ = other.current_edge_;
- }
- }
-
- bool equal(const Triangle_around_vertex_iterator& other) const {
- return (complex_ == other.complex_) && ((finished() && other.finished()) || current_edge_ == other.current_edge_);
- }
-
- Simplex dereference() const {
- Root_vertex_handle v1 = (*link_)[*current_edge_].first();
- Root_vertex_handle v2 = (*link_)[*current_edge_].second();
- return Simplex(v_, *(complex_->get_address(v1)), *(complex_->get_address(v2)));
- }
-
- void increment() {
- ++current_edge_;
- }
-
- private:
- bool finished() const {
- return is_end_ || (current_edge_ == link_->edge_range().end());
- }
-};
-
-/**
- * \brief Iterator over the triangles of the
- * simplicial complex.
- * \remark Will be removed soon -> dont look
- *
- */
-template<typename SkeletonBlockerComplex>
-class Triangle_iterator : public boost::iterator_facade<
-Triangle_iterator <SkeletonBlockerComplex>,
-typename SkeletonBlockerComplex::Simplex const
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Simplex const> {
- friend class boost::iterator_core_access;
- private:
- typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle;
- typedef typename SkeletonBlockerComplex::Root_vertex_handle Root_vertex_handle;
- typedef typename SkeletonBlockerComplex::Simplex Simplex;
- typedef typename SkeletonBlockerComplex::Superior_triangle_around_vertex_iterator STAVI;
- typedef typename SkeletonBlockerComplex::Complex_vertex_iterator Complex_vertex_iterator;
-
- const SkeletonBlockerComplex* complex_;
- Complex_vertex_iterator current_vertex_;
- STAVI current_triangle_;
- bool is_end_;
-
- public:
- /*
- * @remark assume that the complex is non-empty
- */
- Triangle_iterator(const SkeletonBlockerComplex* complex) :
- complex_(complex),
- current_vertex_(complex->vertex_range().begin()),
- current_triangle_(complex, *current_vertex_), // this line is problematic is the complex is empty
- is_end_(false) {
- assert(!complex->empty());
- gotoFirstTriangle();
- }
-
- private:
- // goto to the first triangle or to the end if none
- void gotoFirstTriangle() {
- if (!is_finished() && current_triangle_.finished()) {
- goto_next_vertex();
- }
- }
-
- public:
- /**
- * @brief ugly hack to get an iterator to the end
- * @remark assume that the complex is non-empty
- */
- Triangle_iterator(const SkeletonBlockerComplex* complex, bool is_end) :
- complex_(complex),
- current_vertex_(complex->vertex_range().end()),
- current_triangle_(), // xxx this line is problematic is the complex is empty
- is_end_(true) { }
-
- Triangle_iterator& operator=(const Triangle_iterator & other) {
- complex_ = other.complex_;
- Complex_vertex_iterator current_vertex_;
- STAVI current_triangle_;
- return *this;
- }
-
- bool equal(const Triangle_iterator& other) const {
- bool both_are_finished = is_finished() && other.is_finished();
- bool both_arent_finished = !is_finished() && !other.is_finished();
- // if the two iterators are not finished, they must have the same state
- return (complex_ == other.complex_) && (both_are_finished || ((both_arent_finished) &&
- current_vertex_ == other.current_vertex_ &&
- current_triangle_ == other.current_triangle_));
- }
-
- Simplex dereference() const {
- return *current_triangle_;
- }
-
- private:
- // goto the next vertex that has a triangle pending or the
- // end vertex iterator if none exists
- void goto_next_vertex() {
- // we must have consume all triangles passing through the vertex
- assert(current_triangle_.finished());
- // we must not be done
- assert(!is_finished());
-
- ++current_vertex_;
-
- if (!is_finished()) {
- current_triangle_ = STAVI(complex_, *current_vertex_);
- if (current_triangle_.finished())
- goto_next_vertex();
- }
- }
-
- public:
- void increment() {
- if (!current_triangle_.finished()) {
- ++current_triangle_; // problem here
- if (current_triangle_.finished())
- goto_next_vertex();
- } else {
- assert(!is_finished());
- goto_next_vertex();
- }
- }
-
- private:
- bool is_finished() const {
- return is_end_ || current_vertex_ == complex_->vertex_range().end();
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_TRIANGLES_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h b/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h
deleted file mode 100644
index 3a638ae6..00000000
--- a/include/gudhi/Skeleton_blocker/iterators/Skeleton_blockers_vertices_iterators.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
-#define SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
-
-#include <boost/iterator/iterator_facade.hpp>
-
-#include <utility> // for pair<>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- *@brief Iterator on the vertices of a simplicial complex
- *@remark The increment operator go to the next active vertex.
- *@remark Incrementation increases Vertex_handle.
- */
-template<typename SkeletonBlockerComplex>
-class Vertex_iterator : public boost::iterator_facade< Vertex_iterator <SkeletonBlockerComplex>
-, typename SkeletonBlockerComplex::Vertex_handle const
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Vertex_handle const> {
- friend class boost::iterator_core_access;
-
- typedef typename SkeletonBlockerComplex::boost_vertex_iterator boost_vertex_iterator;
- typedef typename SkeletonBlockerComplex::Vertex_handle Vertex_handle;
- private:
- const SkeletonBlockerComplex* complex;
- std::pair<boost_vertex_iterator, boost_vertex_iterator> vertexIterator;
-
-
- public:
- Vertex_iterator() : complex(NULL) { }
-
- Vertex_iterator(const SkeletonBlockerComplex* complex_) :
- complex(complex_),
- vertexIterator(vertices(complex_->skeleton)) {
- if (!finished() && !is_active()) {
- goto_next_valid();
- }
- }
-
- /**
- * return an iterator to the end.
- */
- Vertex_iterator(const SkeletonBlockerComplex* complex_, int end) :
- complex(complex_), vertexIterator(vertices(complex_->skeleton)) {
- vertexIterator.first = vertexIterator.second;
- }
-
- public:
- void increment() {
- goto_next_valid();
- }
-
- Vertex_handle dereference() const {
- return (Vertex_handle(*(vertexIterator.first)));
- }
-
- bool equal(const Vertex_iterator& other) const {
- return vertexIterator == other.vertexIterator && complex == other.complex;
- }
-
- bool operator<(const Vertex_iterator& other) const {
- return dereference() < other.dereference();
- }
-
- private:
- bool finished() const {
- return vertexIterator.first == vertexIterator.second;
- }
-
- void goto_next_valid() {
- ++vertexIterator.first;
- if (!finished() && !is_active()) {
- goto_next_valid();
- }
- }
-
- bool is_active() const {
- return ((*complex)[Vertex_handle(*vertexIterator.first)]).is_active();
- }
-};
-
-template<typename SkeletonBlockerComplex>
-class Neighbors_vertices_iterator : public boost::iterator_facade < Neighbors_vertices_iterator<SkeletonBlockerComplex>
-, typename SkeletonBlockerComplex::Vertex_handle const
-, boost::forward_traversal_tag
-, typename SkeletonBlockerComplex::Vertex_handle const> {
- friend class boost::iterator_core_access;
-
- typedef SkeletonBlockerComplex Complex;
- typedef typename Complex::boost_adjacency_iterator boost_adjacency_iterator;
- typedef typename Complex::Vertex_handle Vertex_handle;
- typedef typename Complex::Edge_handle Edge_handle;
-
- private:
- const Complex* complex;
- Vertex_handle v;
-
- boost_adjacency_iterator current_;
- boost_adjacency_iterator end_;
-
- public:
- Neighbors_vertices_iterator() : complex(NULL) { }
-
- Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_) :
- complex(complex_),
- v(v_) {
- tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
- }
-
- /**
- * returns an iterator to the end
- */
- Neighbors_vertices_iterator(const Complex* complex_, Vertex_handle v_, int end) :
- complex(complex_),
- v(v_) {
- tie(current_, end_) = adjacent_vertices(v.vertex, complex->skeleton);
- set_end();
- }
-
- void increment() {
- if (current_ != end_)
- ++current_;
- }
-
- Vertex_handle dereference() const {
- return (Vertex_handle(*current_));
- }
-
- bool equal(const Neighbors_vertices_iterator& other) const {
- return (complex == other.complex) && (v == other.v) && (current_ == other.current_) && (end_ == other.end_);
- }
-
- private:
- // TODO(DS): remove this ugly hack
- void set_end() {
- current_ = end_;
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_ITERATORS_SKELETON_BLOCKERS_VERTICES_ITERATORS_H_
diff --git a/include/gudhi/Skeleton_blocker_complex.h b/include/gudhi/Skeleton_blocker_complex.h
deleted file mode 100644
index addd8104..00000000
--- a/include/gudhi/Skeleton_blocker_complex.h
+++ /dev/null
@@ -1,1605 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_COMPLEX_H_
-#define SKELETON_BLOCKER_COMPLEX_H_
-
-#include <gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h>
-#include <gudhi/Skeleton_blocker_link_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h>
-#include <gudhi/Skeleton_blocker/internal/Top_faces.h>
-#include <gudhi/Skeleton_blocker/internal/Trie.h>
-#include <gudhi/Debug_utils.h>
-
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/connected_components.hpp>
-#include <boost/iterator/transform_iterator.hpp>
-#include <boost/range/adaptor/map.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <memory>
-#include <map>
-#include <list>
-#include <set>
-#include <vector>
-#include <string>
-#include <algorithm>
-#include <utility>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- *@class Skeleton_blocker_complex
- *@brief Abstract Simplicial Complex represented with a skeleton/blockers pair.
- *@ingroup skbl
- */
-template<class SkeletonBlockerDS>
-class Skeleton_blocker_complex {
- template<class ComplexType> friend class Vertex_iterator;
- template<class ComplexType> friend class Neighbors_vertices_iterator;
- template<class ComplexType> friend class Edge_iterator;
- template<class ComplexType> friend class Edge_around_vertex_iterator;
-
- template<class ComplexType> friend class Skeleton_blocker_link_complex;
- template<class ComplexType> friend class Skeleton_blocker_link_superior;
- template<class ComplexType> friend class Skeleton_blocker_sub_complex;
-
- public:
- /**
- * @brief The type of stored vertex node, specified by the template SkeletonBlockerDS
- */
- typedef typename SkeletonBlockerDS::Graph_vertex Graph_vertex;
-
- /**
- * @brief The type of stored edge node, specified by the template SkeletonBlockerDS
- */
- typedef typename SkeletonBlockerDS::Graph_edge Graph_edge;
-
- typedef typename SkeletonBlockerDS::Root_vertex_handle Root_vertex_handle;
-
- /**
- * @brief The type of an handle to a vertex of the complex.
- */
- typedef typename SkeletonBlockerDS::Vertex_handle Vertex_handle;
- typedef typename Root_vertex_handle::boost_vertex_handle boost_vertex_handle;
-
- /**
- * @brief A ordered set of integers that represents a simplex.
- */
- typedef Skeleton_blocker_simplex<Vertex_handle> Simplex;
- typedef Skeleton_blocker_simplex<Root_vertex_handle> Root_simplex_handle;
-
- /**
- * @brief Handle to a blocker of the complex.
- */
- typedef Simplex* Blocker_handle;
-
- typedef typename Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_iterator;
- typedef typename Simplex::Simplex_vertex_const_iterator Simplex_handle_iterator;
-
- protected:
- typedef typename boost::adjacency_list<boost::setS, // edges
- boost::vecS, // vertices
- boost::undirectedS, Graph_vertex, Graph_edge> Graph;
- // todo/remark : edges are not sorted, it heavily penalizes computation for SuperiorLink
- // (eg Link with greater vertices)
- // that burdens simplex iteration / complex initialization via list of simplices.
- // to avoid that, one should modify the graph by storing two lists of adjacency for every
- // vertex, the one with superior and the one with lower vertices, that way there is
- // no more extra cost for computation of SuperiorLink
- typedef typename boost::graph_traits<Graph>::vertex_iterator boost_vertex_iterator;
- typedef typename boost::graph_traits<Graph>::edge_iterator boost_edge_iterator;
-
- protected:
- typedef typename boost::graph_traits<Graph>::adjacency_iterator boost_adjacency_iterator;
-
- public:
- /**
- * @brief Handle to an edge of the complex.
- */
- typedef typename boost::graph_traits<Graph>::edge_descriptor Edge_handle;
-
- protected:
- typedef std::multimap<Vertex_handle, Simplex *> BlockerMap;
- typedef typename std::multimap<Vertex_handle, Simplex *>::value_type BlockerPair;
- typedef typename std::multimap<Vertex_handle, Simplex *>::iterator BlockerMapIterator;
- typedef typename std::multimap<Vertex_handle, Simplex *>::const_iterator BlockerMapConstIterator;
-
- protected:
- size_t num_vertices_;
- size_t num_blockers_;
-
- typedef Skeleton_blocker_complex_visitor<Vertex_handle> Visitor;
- // typedef Visitor* Visitor_ptr;
- Visitor* visitor;
-
- /**
- * @details If 'x' is a Vertex_handle of a vertex in the complex then degree[x] = d is its degree.
- *
- * This quantity is updated when adding/removing edge.
- *
- * This is useful because the operation
- * list.size() is done in linear time.
- */
- std::vector<boost_vertex_handle> degree_;
- Graph skeleton; /** 1-skeleton of the simplicial complex. */
-
- /** Each vertex can access to the blockers passing through it. */
- BlockerMap blocker_map_;
-
- public:
- /////////////////////////////////////////////////////////////////////////////
- /** @name Constructors, Destructors
- */
- //@{
-
- /**
- *@brief constructs a simplicial complex with a given number of vertices and a visitor.
- */
- explicit Skeleton_blocker_complex(size_t num_vertices_ = 0, Visitor* visitor_ = NULL)
- : visitor(visitor_) {
- clear();
- for (size_t i = 0; i < num_vertices_; ++i) {
- add_vertex();
- }
- }
-
- private:
- // typedef Trie<Skeleton_blocker_complex<SkeletonBlockerDS>> STrie;
- typedef Trie<Simplex> STrie;
-
- public:
- /**
- * @brief Constructor with a list of simplices.
- * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be computed or not).
- */
- template<typename SimpleHandleOutputIterator>
- Skeleton_blocker_complex(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end,
- bool is_flag_complex = false, Visitor* visitor_ = NULL)
- : num_vertices_(0),
- num_blockers_(0),
- visitor(visitor_) {
- add_vertices_and_edges(simplices_begin, simplices_end);
-
- if (!is_flag_complex)
- // need to compute blockers
- add_blockers(simplices_begin, simplices_end);
- }
-
- private:
- /**
- * Add vertices and edges of a simplex in one pass
- */
- template<typename SimpleHandleOutputIterator>
- void add_vertices_and_edges(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) {
- std::vector<std::pair<Vertex_handle, Vertex_handle>> edges;
- // first pass to add vertices and edges
- int num_vertex = -1;
- for (auto s_it = simplices_begin; s_it != simplices_end; ++s_it) {
- if (s_it->dimension() == 0) num_vertex = (std::max)(num_vertex, s_it->first_vertex().vertex);
- if (s_it->dimension() == 1) edges.emplace_back(s_it->first_vertex(), s_it->last_vertex());
- }
- while (num_vertex-- >= 0) add_vertex();
-
- for (const auto& e : edges)
- add_edge_without_blockers(e.first, e.second);
- }
-
- template<typename SimpleHandleOutputIterator>
- void add_blockers(SimpleHandleOutputIterator simplices_begin, SimpleHandleOutputIterator simplices_end) {
- Tries<Simplex> tries(num_vertices(), simplices_begin, simplices_end);
- tries.init_next_dimension();
- auto simplices(tries.next_dimension_simplices());
-
- while (!simplices.empty()) {
- simplices = tries.next_dimension_simplices();
- for (auto& sigma : simplices) {
- // common_positive_neighbors is the set of vertices u such that
- // for all s in sigma, us is an edge and u>s
- Simplex common_positive_neighbors(tries.positive_neighbors(sigma.last_vertex()));
- for (auto sigma_it = sigma.rbegin(); sigma_it != sigma.rend(); ++sigma_it)
- if (sigma_it != sigma.rbegin())
- common_positive_neighbors.intersection(tries.positive_neighbors(*sigma_it));
-
- for (auto x : common_positive_neighbors) {
- // first test that all edges sx are here for all s in sigma
- bool all_edges_here = true;
- for (auto s : sigma)
- if (!contains_edge(x, s)) {
- all_edges_here = false;
- break;
- }
- if (!all_edges_here) continue;
-
- // all edges of sigma \cup x are here
- // we have a blocker if all proper faces of sigma \cup x
- // are in the complex and if sigma \cup x is not in the complex
- // the first is equivalent at checking if blocks(sigma \cup x) is true
- // as all blockers of lower dimension have already been computed
- sigma.add_vertex(x);
- if (!tries.contains(sigma) && !blocks(sigma))
- add_blocker(sigma);
- sigma.remove_vertex(x);
- }
- }
- }
- }
-
- public:
- // We cannot use the default copy constructor since we need
- // to make a copy of each of the blockers
-
- Skeleton_blocker_complex(const Skeleton_blocker_complex& copy) {
- visitor = NULL;
- degree_ = copy.degree_;
- skeleton = Graph(copy.skeleton);
- num_vertices_ = copy.num_vertices_;
-
- num_blockers_ = 0;
- // we copy the blockers
- for (auto blocker : copy.const_blocker_range()) {
- add_blocker(*blocker);
- }
- }
-
- /**
- */
- Skeleton_blocker_complex& operator=(const Skeleton_blocker_complex& copy) {
- clear();
- visitor = NULL;
- degree_ = copy.degree_;
- skeleton = Graph(copy.skeleton);
- num_vertices_ = copy.num_vertices_;
-
- num_blockers_ = 0;
- // we copy the blockers
- for (auto blocker : copy.const_blocker_range())
- add_blocker(*blocker);
- return *this;
- }
-
- /**
- * return true if both complexes have the same simplices.
- */
- bool operator==(const Skeleton_blocker_complex& other) const {
- if (other.num_vertices() != num_vertices()) return false;
- if (other.num_edges() != num_edges()) return false;
- if (other.num_blockers() != num_blockers()) return false;
-
- for (auto v : vertex_range())
- if (!other.contains_vertex(v)) return false;
-
- for (auto e : edge_range())
- if (!other.contains_edge(first_vertex(e), second_vertex(e))) return false;
-
- for (const auto b : const_blocker_range())
- if (!other.contains_blocker(*b)) return false;
-
- return true;
- }
-
- bool operator!=(const Skeleton_blocker_complex& other) const {
- return !(*this == other);
- }
-
- /**
- * The destructor delete all blockers allocated.
- */
- virtual ~Skeleton_blocker_complex() {
- clear();
- }
-
- /**
- * @details Clears the simplicial complex. After a call to this function,
- * blockers are destroyed. The 1-skeleton and the set of blockers
- * are both empty.
- */
- virtual void clear() {
- // xxx for now the responsabilty of freeing the visitor is for
- // the user
- visitor = NULL;
-
- degree_.clear();
- num_vertices_ = 0;
-
- remove_blockers();
-
- skeleton.clear();
- }
-
- /**
- *@brief allows to change the visitor.
- */
- void set_visitor(Visitor* other_visitor) {
- visitor = other_visitor;
- }
-
- //@}
-
- /////////////////////////////////////////////////////////////////////////////
- /** @name Vertices operations
- */
- //@{
- public:
- /**
- * @brief Return a local Vertex_handle of a vertex given a global one.
- * @remark Assume that the vertex is present in the complex.
- */
- Vertex_handle operator[](Root_vertex_handle global) const {
- auto local(get_address(global));
- assert(local);
- return *local;
- }
-
- /**
- * @brief Return the vertex node associated to local Vertex_handle.
- * @remark Assume that the vertex is present in the complex.
- */
- Graph_vertex& operator[](Vertex_handle address) {
- assert(
- 0 <= address.vertex && address.vertex < boost::num_vertices(skeleton));
- return skeleton[address.vertex];
- }
-
- /**
- * @brief Return the vertex node associated to local Vertex_handle.
- * @remark Assume that the vertex is present in the complex.
- */
- const Graph_vertex& operator[](Vertex_handle address) const {
- assert(
- 0 <= address.vertex && address.vertex < boost::num_vertices(skeleton));
- return skeleton[address.vertex];
- }
-
- /**
- * @brief Adds a vertex to the simplicial complex and returns its Vertex_handle.
- * @remark Vertex representation is contiguous.
- */
- Vertex_handle add_vertex() {
- Vertex_handle address(boost::add_vertex(skeleton));
- num_vertices_++;
- (*this)[address].activate();
- // safe since we now that we are in the root complex and the field 'address' and 'id'
- // are identical for every vertices
- (*this)[address].set_id(Root_vertex_handle(address.vertex));
- degree_.push_back(0);
- if (visitor)
- visitor->on_add_vertex(address);
- return address;
- }
-
- /**
- * @brief Remove a vertex from the simplicial complex
- * @remark It just deactivates the vertex with a boolean flag but does not
- * remove it from vertices from complexity issues.
- */
- void remove_vertex(Vertex_handle address) {
- assert(contains_vertex(address));
- // We remove b
- boost::clear_vertex(address.vertex, skeleton);
- (*this)[address].deactivate();
- num_vertices_--;
- degree_[address.vertex] = -1;
- if (visitor)
- visitor->on_remove_vertex(address);
- }
-
- /**
- */
- bool contains_vertex(Vertex_handle u) const {
- Vertex_handle num_vertices(boost::num_vertices(skeleton));
- if (u.vertex < 0 || u.vertex >= num_vertices)
- return false;
- return (*this)[u].is_active();
- }
-
- /**
- */
- bool contains_vertex(Root_vertex_handle u) const {
- boost::optional<Vertex_handle> address = get_address(u);
- return address && (*this)[*address].is_active();
- }
-
- /**
- * @return true iff the simplicial complex contains all vertices
- * of simplex sigma
- */
- bool contains_vertices(const Simplex & sigma) const {
- for (auto vertex : sigma)
- if (!contains_vertex(vertex))
- return false;
- return true;
- }
-
- /**
- * @brief Given an Id return the address of the vertex having this Id in the complex.
- * @remark For a simplicial complex, the address is the id but it may not be the case for a SubComplex.
- */
- virtual boost::optional<Vertex_handle> get_address(Root_vertex_handle id) const {
- boost::optional<Vertex_handle> res;
- int num_vertices = boost::num_vertices(skeleton);
- if (id.vertex < num_vertices)
- res = Vertex_handle(id.vertex);
- return res;
- }
-
- /**
- * return the id of a vertex of adress local present in the graph
- */
- Root_vertex_handle get_id(Vertex_handle local) const {
- assert(0 <= local.vertex && local.vertex < boost::num_vertices(skeleton));
- return (*this)[local].get_id();
- }
-
- /**
- * @brief Convert an address of a vertex of a complex to the address in
- * the current complex.
- * @details
- * If the current complex is a sub (or sup) complex of 'other', it converts
- * the address of a vertex v expressed in 'other' to the address of the vertex
- * v in the current one.
- * @remark this methods uses Root_vertex_handle to identify the vertex and
- * assumes the vertex is present in the current complex.
- */
- Vertex_handle convert_handle_from_another_complex(const Skeleton_blocker_complex& other,
- Vertex_handle vh_in_other) const {
- auto vh_in_current_complex = get_address(other.get_id(vh_in_other));
- assert(vh_in_current_complex);
- return *vh_in_current_complex;
- }
-
- /**
- * @brief return the graph degree of a vertex.
- */
- int degree(Vertex_handle local) const {
- assert(0 <= local.vertex && local.vertex < boost::num_vertices(skeleton));
- return degree_[local.vertex];
- }
-
- //@}
-
- /////////////////////////////////////////////////////////////////////////////
- /** @name Edges operations
- */
- //@{
- public:
- /**
- * @brief return an edge handle if the two vertices forms
- * an edge in the complex
- */
- boost::optional<Edge_handle> operator[](
- const std::pair<Vertex_handle, Vertex_handle>& ab) const {
- boost::optional<Edge_handle> res;
- std::pair<Edge_handle, bool> edge_pair(
- boost::edge(ab.first.vertex, ab.second.vertex, skeleton));
- if (edge_pair.second)
- res = edge_pair.first;
- return res;
- }
-
- /**
- * @brief returns the stored node associated to an edge
- */
- Graph_edge& operator[](Edge_handle edge_handle) {
- return skeleton[edge_handle];
- }
-
- /**
- * @brief returns the stored node associated to an edge
- */
- const Graph_edge& operator[](Edge_handle edge_handle) const {
- return skeleton[edge_handle];
- }
-
- /**
- * @brief returns the first vertex of an edge
- * @details it assumes that the edge is present in the complex
- */
- Vertex_handle first_vertex(Edge_handle edge_handle) const {
- return static_cast<Vertex_handle> (source(edge_handle, skeleton));
- }
-
- /**
- * @brief returns the first vertex of an edge
- * @details it assumes that the edge is present in the complex
- */
- Vertex_handle second_vertex(Edge_handle edge_handle) const {
- return static_cast<Vertex_handle> (target(edge_handle, skeleton));
- }
-
- /**
- * @brief returns the simplex made with the two vertices of the edge
- * @details it assumes that the edge is present in the complex
-
- */
- Simplex get_vertices(Edge_handle edge_handle) const {
- auto edge((*this)[edge_handle]);
- return Simplex((*this)[edge.first()], (*this)[edge.second()]);
- }
-
- /**
- * @brief Adds an edge between vertices a and b.
- * @details For instance, the complex contains edge 01 and 12, then calling
- * add_edge with vertex 0 and 2 will create a complex containing
- * the edges 01, 12, 20 but not the triangle 012 (and hence this complex
- * will contains a blocker 012).
- */
- Edge_handle add_edge(Vertex_handle a, Vertex_handle b) {
- // if the edge is already there we musnt go further
- // as we may add blockers that should not be here
- if (contains_edge(a, b))
- return *((*this)[std::make_pair(a, b)]);
- auto res = add_edge_without_blockers(a, b);
- add_blockers_after_simplex_insertion(Simplex(a, b));
- return res;
- }
-
- /**
- * @brief Adds all edges of s in the complex.
- */
- void add_edge(const Simplex& s) {
- for (auto i = s.begin(); i != s.end(); ++i)
- for (auto j = i; ++j != s.end(); /**/)
- add_edge(*i, *j);
- }
-
- /**
- * @brief Adds an edge between vertices a and b without blockers.
- * @details For instance, the complex contains edge 01 and 12, then calling
- * add_edge with vertex 0 and 2 will create a complex containing
- * the triangle 012.
- */
- Edge_handle add_edge_without_blockers(Vertex_handle a, Vertex_handle b) {
- assert(contains_vertex(a) && contains_vertex(b));
- assert(a != b);
-
- auto edge_handle((*this)[std::make_pair(a, b)]);
- if (!edge_handle) {
- edge_handle = boost::add_edge(a.vertex, b.vertex, skeleton).first;
- (*this)[*edge_handle].setId(get_id(a), get_id(b));
- degree_[a.vertex]++;
- degree_[b.vertex]++;
- if (visitor)
- visitor->on_add_edge_without_blockers(a, b);
- }
- return *edge_handle;
- }
-
- /**
- * @brief Adds all edges of s in the complex without adding blockers.
- */
- void add_edge_without_blockers(Simplex s) {
- for (auto i = s.begin(); i != s.end(); ++i) {
- for (auto j = i; ++j != s.end(); /**/)
- add_edge_without_blockers(*i, *j);
- }
- }
-
- /**
- * @brief Removes an edge from the simplicial complex and all its cofaces.
- * @details returns the former Edge_handle representing the edge
- */
- virtual Edge_handle remove_edge(Vertex_handle a, Vertex_handle b) {
- bool found;
- Edge_handle edge;
- tie(edge, found) = boost::edge(a.vertex, b.vertex, skeleton);
- if (found) {
- if (visitor)
- visitor->on_remove_edge(a, b);
- boost::remove_edge(a.vertex, b.vertex, skeleton);
- degree_[a.vertex]--;
- degree_[b.vertex]--;
- }
- return edge;
- }
-
- /**
- * @brief Removes edge and its cofaces from the simplicial complex.
- */
- void remove_edge(Edge_handle edge) {
- assert(contains_vertex(first_vertex(edge)));
- assert(contains_vertex(second_vertex(edge)));
- remove_edge(first_vertex(edge), second_vertex(edge));
- }
-
- /**
- * @brief The complex is reduced to its set of vertices.
- * All the edges and blockers are removed.
- */
- void keep_only_vertices() {
- remove_blockers();
-
- for (auto u : vertex_range()) {
- while (this->degree(u) > 0) {
- Vertex_handle v(*(adjacent_vertices(u.vertex, this->skeleton).first));
- this->remove_edge(u, v);
- }
- }
- }
-
- /**
- * @return true iff the simplicial complex contains an edge between
- * vertices a and b
- */
- bool contains_edge(Vertex_handle a, Vertex_handle b) const {
- // if (a.vertex<0 || b.vertex <0) return false;
- return boost::edge(a.vertex, b.vertex, skeleton).second;
- }
-
- /**
- * @return true iff the simplicial complex contains all vertices
- * and all edges of simplex sigma
- */
- bool contains_edges(const Simplex & sigma) const {
- for (auto i = sigma.begin(); i != sigma.end(); ++i) {
- if (!contains_vertex(*i))
- return false;
- for (auto j = i; ++j != sigma.end();) {
- if (!contains_edge(*i, *j))
- return false;
- }
- }
- return true;
- }
- //@}
-
- /////////////////////////////////////////////////////////////////////////////
- /** @name Blockers operations
- */
- //@{
-
- /**
- * @brief Adds the simplex to the set of blockers and
- * returns a Blocker_handle toward it if was not present before and 0 otherwise.
- */
- Blocker_handle add_blocker(const Simplex& blocker) {
- assert(blocker.dimension() > 1);
- if (contains_blocker(blocker)) {
- return 0;
- } else {
- if (visitor)
- visitor->on_add_blocker(blocker);
- Blocker_handle blocker_pt = new Simplex(blocker);
- num_blockers_++;
- auto vertex = blocker_pt->begin();
- while (vertex != blocker_pt->end()) {
- blocker_map_.insert(BlockerPair(*vertex, blocker_pt));
- ++vertex;
- }
- return blocker_pt;
- }
- }
-
- protected:
- /**
- * @brief Adds the simplex to the set of blockers
- */
- void add_blocker(Blocker_handle blocker) {
- if (contains_blocker(*blocker)) {
- // std::cerr << "ATTEMPT TO ADD A BLOCKER ALREADY THERE ---> BLOCKER IGNORED" << endl;
- return;
- } else {
- if (visitor)
- visitor->on_add_blocker(*blocker);
- num_blockers_++;
- auto vertex = blocker->begin();
- while (vertex != blocker->end()) {
- blocker_map_.insert(BlockerPair(*vertex, blocker));
- ++vertex;
- }
- }
- }
-
- protected:
- /**
- * Removes sigma from the blocker map of vertex v
- */
- void remove_blocker(const Blocker_handle sigma, Vertex_handle v) {
- Complex_blocker_around_vertex_iterator blocker;
- for (blocker = blocker_range(v).begin(); blocker != blocker_range(v).end();
- ++blocker) {
- if (*blocker == sigma)
- break;
- }
- if (*blocker != sigma) {
- std::cerr
- << "bug ((*blocker).second == sigma) ie try to remove a blocker not present\n";
- assert(false);
- } else {
- blocker_map_.erase(blocker.current_position());
- }
- }
-
- public:
- /**
- * @brief Removes the simplex from the set of blockers.
- * @remark sigma has to belongs to the set of blockers
- */
- void remove_blocker(const Blocker_handle sigma) {
- for (auto vertex : *sigma)
- remove_blocker(sigma, vertex);
- num_blockers_--;
- }
-
- /**
- * @brief Remove all blockers, in other words, it expand the simplicial
- * complex to the smallest flag complex that contains it.
- */
- void remove_blockers() {
- // Desallocate the blockers
- while (!blocker_map_.empty()) {
- delete_blocker(blocker_map_.begin()->second);
- }
- num_blockers_ = 0;
- blocker_map_.clear();
- }
-
- protected:
- /**
- * Removes the simplex sigma from the set of blockers.
- * sigma has to belongs to the set of blockers
- *
- * @remark contrarily to delete_blockers does not call the destructor
- */
- void remove_blocker(const Simplex& sigma) {
- assert(contains_blocker(sigma));
- for (auto vertex : sigma)
- remove_blocker(sigma, vertex);
- num_blockers_--;
- }
-
- public:
- /**
- * Removes the simplex s from the set of blockers
- * and desallocate s.
- */
- void delete_blocker(Blocker_handle sigma) {
- if (visitor)
- visitor->on_delete_blocker(sigma);
- remove_blocker(sigma);
- delete sigma;
- }
-
- /**
- * @return true iff s is a blocker of the simplicial complex
- */
- bool contains_blocker(const Blocker_handle s) const {
- if (s->dimension() < 2)
- return false;
-
- Vertex_handle a = s->first_vertex();
-
- for (const auto blocker : const_blocker_range(a)) {
- if (s == *blocker)
- return true;
- }
- return false;
- }
-
- /**
- * @return true iff s is a blocker of the simplicial complex
- */
- bool contains_blocker(const Simplex & s) const {
- if (s.dimension() < 2)
- return false;
-
- Vertex_handle a = s.first_vertex();
-
- for (auto blocker : const_blocker_range(a)) {
- if (s == *blocker)
- return true;
- }
- return false;
- }
-
- private:
- /**
- * @return true iff a blocker of the simplicial complex
- * is a face of sigma.
- */
- bool blocks(const Simplex & sigma) const {
- for (auto s : sigma)
- for (auto blocker : const_blocker_range(s))
- if (sigma.contains(*blocker))
- return true;
- return false;
- }
-
- //@}
-
- protected:
- /**
- * @details Adds to simplex the neighbours of v e.g. \f$ n \leftarrow n \cup N(v) \f$.
- * If keep_only_superior is true then only vertices that are greater than v are added.
- */
- virtual void add_neighbours(Vertex_handle v, Simplex & n,
- bool keep_only_superior = false) const {
- boost_adjacency_iterator ai, ai_end;
- for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end;
- ++ai) {
- Vertex_handle value(*ai);
- if (keep_only_superior) {
- if (value > v.vertex) {
- n.add_vertex(value);
- }
- } else {
- n.add_vertex(value);
- }
- }
- }
-
- /**
- * @details Add to simplex res all vertices which are
- * neighbours of alpha: ie \f$ res \leftarrow res \cup N(alpha) \f$.
- *
- * If 'keep_only_superior' is true then only vertices that are greater than alpha are added.
- * todo revoir
- *
- */
- virtual void add_neighbours(const Simplex &alpha, Simplex & res,
- bool keep_only_superior = false) const {
- res.clear();
- auto alpha_vertex = alpha.begin();
- add_neighbours(*alpha_vertex, res, keep_only_superior);
- for (alpha_vertex = (alpha.begin())++; alpha_vertex != alpha.end();
- ++alpha_vertex)
- keep_neighbours(*alpha_vertex, res, keep_only_superior);
- }
-
- /**
- * @details Remove from simplex n all vertices which are
- * not neighbours of v e.g. \f$ res \leftarrow res \cap N(v) \f$.
- * If 'keep_only_superior' is true then only vertices that are greater than v are keeped.
- */
- virtual void keep_neighbours(Vertex_handle v, Simplex& res,
- bool keep_only_superior = false) const {
- Simplex nv;
- add_neighbours(v, nv, keep_only_superior);
- res.intersection(nv);
- }
-
- /**
- * @details Remove from simplex all vertices which are
- * neighbours of v eg \f$ res \leftarrow res \setminus N(v) \f$.
- * If 'keep_only_superior' is true then only vertices that are greater than v are added.
- */
- virtual void remove_neighbours(Vertex_handle v, Simplex & res,
- bool keep_only_superior = false) const {
- Simplex nv;
- add_neighbours(v, nv, keep_only_superior);
- res.difference(nv);
- }
-
- public:
- typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex> Link_complex;
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Link_complex link(Vertex_handle v) const {
- return Link_complex(*this, Simplex(v));
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Link_complex link(Edge_handle edge) const {
- return Link_complex(*this, edge);
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Link_complex link(const Simplex& simplex) const {
- return Link_complex(*this, simplex);
- }
-
- /**
- * @brief Compute the local vertices of 's' in the current complex
- * If one of them is not present in the complex then the return value is uninitialized.
- *
- *
- */
- // xxx rename get_address et place un using dans sub_complex
-
- boost::optional<Simplex> get_simplex_address(
- const Root_simplex_handle& s) const {
- boost::optional<Simplex> res;
-
- Simplex s_address;
- // Root_simplex_const_iterator i;
- for (auto i = s.begin(); i != s.end(); ++i) {
- boost::optional<Vertex_handle> address = get_address(*i);
- if (!address)
- return res;
- else
- s_address.add_vertex(*address);
- }
- res = s_address;
- return res;
- }
-
- /**
- * @brief returns a simplex with vertices which are the id of vertices of the
- * argument.
- */
- Root_simplex_handle get_id(const Simplex& local_simplex) const {
- Root_simplex_handle global_simplex;
- for (auto x = local_simplex.begin(); x != local_simplex.end(); ++x) {
- global_simplex.add_vertex(get_id(*x));
- }
- return global_simplex;
- }
-
- /**
- * @brief returns true iff the simplex s belongs to the simplicial
- * complex.
- */
- virtual bool contains(const Simplex & s) const {
- if (s.dimension() == -1) {
- return false;
- } else if (s.dimension() == 0) {
- return contains_vertex(s.first_vertex());
- } else {
- return (contains_edges(s) && !blocks(s));
- }
- }
-
- /*
- * @brief returnrs true iff the complex is empty.
- */
- bool empty() const {
- return num_vertices() == 0;
- }
-
- /*
- * @brief returns the number of vertices in the complex.
- */
- int num_vertices() const {
- // remark boost::num_vertices(skeleton) counts deactivated vertices
- return num_vertices_;
- }
-
- /*
- * @brief returns the number of edges in the complex.
- * @details currently in O(n)
- */
- // todo cache the value
-
- int num_edges() const {
- return boost::num_edges(skeleton);
- }
-
- int num_triangles() const {
- auto triangles = triangle_range();
- return std::distance(triangles.begin(), triangles.end());
- }
-
- /*
- * @brief returns the number of simplices of a given dimension in the complex.
- */
- size_t num_simplices() const {
- auto simplices = complex_simplex_range();
- return std::distance(simplices.begin(), simplices.end());
- }
-
- /*
- * @brief returns the number of simplices of a given dimension in the complex.
- */
- size_t num_simplices(int dimension) const {
- // TODO(DS): iterator on k-simplices
- size_t res = 0;
- for (const auto& s : complex_simplex_range())
- if (s.dimension() == dimension)
- ++res;
- return res;
- }
-
- /*
- * @brief returns the number of blockers in the complex.
- */
- size_t num_blockers() const {
- return num_blockers_;
- }
-
- /*
- * @brief returns true iff the graph of the 1-skeleton of the complex is complete.
- */
- bool complete() const {
- return (num_vertices() * (num_vertices() - 1)) / 2 == num_edges();
- }
-
- /**
- * @brief returns the number of connected components in the graph of the 1-skeleton.
- */
- int num_connected_components() const {
- int num_vert_collapsed = skeleton.vertex_set().size() - num_vertices();
- std::vector<int> component(skeleton.vertex_set().size());
- return boost::connected_components(this->skeleton, &component[0])
- - num_vert_collapsed;
- }
-
- /**
- * @brief %Test if the complex is a cone.
- * @details Runs in O(n) where n is the number of vertices.
- */
- bool is_cone() const {
- if (num_vertices() == 0)
- return false;
- if (num_vertices() == 1)
- return true;
- for (auto vi : vertex_range()) {
- // xxx todo faire une methode bool is_in_blocker(Vertex_handle)
- if (blocker_map_.find(vi) == blocker_map_.end()) {
- // no blocker passes through the vertex, we just need to
- // check if the current vertex is linked to all others vertices of the complex
- if (degree_[vi.vertex] == num_vertices() - 1)
- return true;
- }
- }
- return false;
- }
-
- //@}
- /** @name Simplification operations
- */
- //@{
-
- /**
- * Returns true iff the blocker 'sigma' is popable.
- * To define popable, let us call 'L' the complex that
- * consists in the current complex without the blocker 'sigma'.
- * A blocker 'sigma' is then "popable" if the link of 'sigma'
- * in L is reducible.
- *
- */
- bool is_popable_blocker(Blocker_handle sigma) const;
-
- /**
- * Removes all the popable blockers of the complex and delete them.
- * @returns the number of popable blockers deleted
- */
- void remove_popable_blockers();
-
- /**
- * Removes all the popable blockers of the complex passing through v and delete them.
- */
- void remove_popable_blockers(Vertex_handle v);
-
- /**
- * @brief Removes all the popable blockers of the complex passing through v and delete them.
- * Also remove popable blockers in the neighborhood if they became popable.
- *
- */
- void remove_all_popable_blockers(Vertex_handle v);
-
- /**
- * Remove the star of the vertex 'v'
- */
- void remove_star(Vertex_handle v);
-
- private:
- /**
- * after removing the star of a simplex, blockers sigma that contains this simplex must be removed.
- * Furthermore, all simplices tau of the form sigma \setminus simplex_to_be_removed must be added
- * whenever the dimension of tau is at least 2.
- */
- void update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed);
-
- public:
- /**
- * Remove the star of the edge connecting vertices a and b.
- * @returns the number of blocker that have been removed
- */
- void remove_star(Vertex_handle a, Vertex_handle b);
-
- /**
- * Remove the star of the edge 'e'.
- */
- void remove_star(Edge_handle e);
-
- /**
- * Remove the star of the simplex 'sigma' which needs to belong to the complex
- */
- void remove_star(const Simplex& sigma);
-
- /**
- * @brief add a simplex and all its faces.
- * @details the simplex must have dimension greater than one (otherwise use add_vertex or add_edge_without_blockers).
- */
- void add_simplex(const Simplex& sigma);
-
- private:
- void add_blockers_after_simplex_insertion(Simplex s);
-
- /**
- * remove all blockers that contains sigma
- */
- void remove_blocker_containing_simplex(const Simplex& sigma);
-
- /**
- * remove all blockers that contains sigma
- */
- void remove_blocker_include_in_simplex(const Simplex& sigma);
-
- public:
- enum simplifiable_status {
- NOT_HOMOTOPY_EQ, MAYBE_HOMOTOPY_EQ, HOMOTOPY_EQ
- };
-
- simplifiable_status is_remove_star_homotopy_preserving(const Simplex& simplex) {
- // todo write a virtual method 'link' in Skeleton_blocker_complex which will be overloaded by the current one of
- // Skeleton_blocker_geometric_complex
- // then call it there to build the link and return the value of link.is_contractible()
- return MAYBE_HOMOTOPY_EQ;
- }
-
- enum contractible_status {
- NOT_CONTRACTIBLE, MAYBE_CONTRACTIBLE, CONTRACTIBLE
- };
-
- /**
- * @brief %Test if the complex is reducible using a strategy defined in the class
- * (by default it tests if the complex is a cone)
- * @details Note that NO could be returned if some invariant ensures that the complex
- * is not a point (for instance if the euler characteristic is different from 1).
- * This function will surely have to return MAYBE in some case because the
- * associated problem is undecidable but it in practice, it can often
- * be solved with the help of geometry.
- */
- virtual contractible_status is_contractible() const {
- if (this->is_cone()) {
- return CONTRACTIBLE;
- } else {
- return MAYBE_CONTRACTIBLE;
- }
- }
- //@}
-
- /** @name Edge contraction operations
- */
- //@{
-
- /**
- * @return If ignore_popable_blockers is true
- * then the result is true iff the link condition at edge ab is satisfied
- * or equivalently iff no blocker contains ab.
- * If ignore_popable_blockers is false then the
- * result is true iff all blocker containing ab are popable.
- */
- bool link_condition(Vertex_handle a, Vertex_handle b, bool ignore_popable_blockers = false) const {
- for (auto blocker : this->const_blocker_range(a))
- if (blocker->contains(b)) {
- // false if ignore_popable_blockers is false
- // otherwise the blocker has to be popable
- return ignore_popable_blockers && is_popable_blocker(blocker);
- }
- return true;
- }
-
- /**
- * @return If ignore_popable_blockers is true
- * then the result is true iff the link condition at edge ab is satisfied
- * or equivalently iff no blocker contains ab.
- * If ignore_popable_blockers is false then the
- * result is true iff all blocker containing ab are popable.
- */
- bool link_condition(Edge_handle e, bool ignore_popable_blockers = false) const {
- const Graph_edge& edge = (*this)[e];
- assert(this->get_address(edge.first()));
- assert(this->get_address(edge.second()));
- Vertex_handle a(*this->get_address(edge.first()));
- Vertex_handle b(*this->get_address(edge.second()));
- return link_condition(a, b, ignore_popable_blockers);
- }
-
- protected:
- /**
- * Compute simplices beta such that a.beta is an order 0 blocker
- * that may be used to construct a new blocker after contracting ab.
- * It requires that the link condition is satisfied.
- */
- void tip_blockers(Vertex_handle a, Vertex_handle b, std::vector<Simplex> & buffer) const;
-
- private:
- /**
- * @brief "Replace" the edge 'bx' by the edge 'ax'.
- * Assume that the edge 'bx' was present whereas 'ax' was not.
- * Precisely, it does not replace edges, but remove 'bx' and then add 'ax'.
- * The visitor 'on_swaped_edge' is called just after edge 'ax' had been added
- * and just before edge 'bx' had been removed. That way, it can
- * eventually access to information of 'ax'.
- */
- void swap_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x);
-
- private:
- /**
- * @brief removes all blockers passing through the edge 'ab'
- */
- void delete_blockers_around_vertex(Vertex_handle v);
-
- /**
- * @brief removes all blockers passing through the edge 'ab'
- */
- void delete_blockers_around_edge(Vertex_handle a, Vertex_handle b);
-
- public:
- /**
- * Contracts the edge.
- * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
- * it removes first all blockers passing through 'ab'
- */
- void contract_edge(Edge_handle edge) {
- contract_edge(this->first_vertex(edge), this->second_vertex(edge));
- }
-
- /**
- * Contracts the edge connecting vertices a and b.
- * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
- * it removes first all blockers passing through 'ab'
- */
- void contract_edge(Vertex_handle a, Vertex_handle b);
-
- private:
- void get_blockers_to_be_added_after_contraction(Vertex_handle a, Vertex_handle b,
- std::set<Simplex>& blockers_to_add);
- /**
- * delete all blockers that passes through a or b
- */
- void delete_blockers_around_vertices(Vertex_handle a, Vertex_handle b);
- void update_edges_after_contraction(Vertex_handle a, Vertex_handle b);
- void notify_changed_edges(Vertex_handle a);
- //@}
-
- public:
- /////////////////////////////////////////////////////////////////////////////
- /** @name Vertex iterators
- */
- //@{
- typedef Vertex_iterator<Skeleton_blocker_complex> Complex_vertex_iterator;
-
- //
- // Range over the vertices of the simplicial complex.
- // Methods .begin() and .end() return a Complex_vertex_iterator.
- //
- typedef boost::iterator_range<Complex_vertex_iterator> Complex_vertex_range;
-
- /**
- * @brief Returns a Complex_vertex_range over all vertices of the complex
- */
- Complex_vertex_range vertex_range() const {
- auto begin = Complex_vertex_iterator(this);
- auto end = Complex_vertex_iterator(this, 0);
- return Complex_vertex_range(begin, end);
- }
-
- typedef Neighbors_vertices_iterator<Skeleton_blocker_complex> Complex_neighbors_vertices_iterator;
-
-
- typedef boost::iterator_range<Complex_neighbors_vertices_iterator> Complex_neighbors_vertices_range;
-
- /**
- * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes trough v
- */
- Complex_neighbors_vertices_range vertex_range(Vertex_handle v) const {
- auto begin = Complex_neighbors_vertices_iterator(this, v);
- auto end = Complex_neighbors_vertices_iterator(this, v, 0);
- return Complex_neighbors_vertices_range(begin, end);
- }
-
- //@}
-
- /** @name Edge iterators
- */
- //@{
-
- typedef Edge_iterator<Skeleton_blocker_complex> Complex_edge_iterator;
-
-
- typedef boost::iterator_range<Complex_edge_iterator> Complex_edge_range;
-
- /**
- * @brief Returns a Complex_edge_range over all edges of the simplicial complex
- */
- Complex_edge_range edge_range() const {
- auto begin = Complex_edge_iterator(this);
- auto end = Complex_edge_iterator(this, 0);
- return Complex_edge_range(begin, end);
- }
-
-
- typedef Edge_around_vertex_iterator<Skeleton_blocker_complex> Complex_edge_around_vertex_iterator;
-
-
- typedef boost::iterator_range <Complex_edge_around_vertex_iterator> Complex_edge_around_vertex_range;
-
- /**
- * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes
- * through 'v'
- */
- Complex_edge_around_vertex_range edge_range(Vertex_handle v) const {
- auto begin = Complex_edge_around_vertex_iterator(this, v);
- auto end = Complex_edge_around_vertex_iterator(this, v, 0);
- return Complex_edge_around_vertex_range(begin, end);
- }
-
- //@}
-
- /** @name Triangles iterators
- */
- //@{
- private:
- typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > Link;
- typedef Skeleton_blocker_link_superior<Skeleton_blocker_complex<SkeletonBlockerDS> > Superior_link;
-
- public:
- typedef Triangle_around_vertex_iterator<Skeleton_blocker_complex, Superior_link>
- Superior_triangle_around_vertex_iterator;
- typedef boost::iterator_range < Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link> >
- Complex_triangle_around_vertex_range;
-
- /**
- * @brief Range over triangles around a vertex of the simplicial complex.
- * Methods .begin() and .end() return a Triangle_around_vertex_iterator.
- *
- */
- Complex_triangle_around_vertex_range triangle_range(Vertex_handle v) const {
- auto begin = Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link>(this, v);
- auto end = Triangle_around_vertex_iterator<Skeleton_blocker_complex, Link>(this, v, 0);
- return Complex_triangle_around_vertex_range(begin, end);
- }
-
- typedef boost::iterator_range<Triangle_iterator<Skeleton_blocker_complex> > Complex_triangle_range;
- typedef Triangle_iterator<Skeleton_blocker_complex> Complex_triangle_iterator;
-
- /**
- * @brief Range over triangles of the simplicial complex.
- * Methods .begin() and .end() return a Triangle_around_vertex_iterator.
- *
- */
- Complex_triangle_range triangle_range() const {
- auto end = Triangle_iterator<Skeleton_blocker_complex>(this, 0);
- if (empty()) {
- return Complex_triangle_range(end, end);
- } else {
- auto begin = Triangle_iterator<Skeleton_blocker_complex>(this);
- return Complex_triangle_range(begin, end);
- }
- }
-
- //@}
-
- /** @name Simplices iterators
- */
- //@{
- typedef Simplex_around_vertex_iterator<Skeleton_blocker_complex, Link> Complex_simplex_around_vertex_iterator;
-
- /**
- * @brief Range over the simplices of the simplicial complex around a vertex.
- * Methods .begin() and .end() return a Complex_simplex_around_vertex_iterator.
- */
- typedef boost::iterator_range < Complex_simplex_around_vertex_iterator > Complex_simplex_around_vertex_range;
-
- /**
- * @brief Returns a Complex_simplex_around_vertex_range over all the simplices around a vertex of the complex
- */
- Complex_simplex_around_vertex_range star_simplex_range(Vertex_handle v) const {
- assert(contains_vertex(v));
- return Complex_simplex_around_vertex_range(
- Complex_simplex_around_vertex_iterator(this, v),
- Complex_simplex_around_vertex_iterator(this, v, true));
- }
- typedef Simplex_coboundary_iterator<Skeleton_blocker_complex, Link> Complex_simplex_coboundary_iterator;
-
- /**
- * @brief Range over the simplices of the coboundary of a simplex.
- * Methods .begin() and .end() return a Complex_simplex_coboundary_iterator.
- */
- typedef boost::iterator_range < Complex_simplex_coboundary_iterator > Complex_coboundary_range;
-
- /**
- * @brief Returns a Complex_simplex_coboundary_iterator over the simplices of the coboundary of a simplex.
- */
- Complex_coboundary_range coboundary_range(const Simplex& s) const {
- assert(contains(s));
- return Complex_coboundary_range(Complex_simplex_coboundary_iterator(this, s),
- Complex_simplex_coboundary_iterator(this, s, true));
- }
-
- // typedef Simplex_iterator<Skeleton_blocker_complex,Superior_link> Complex_simplex_iterator;
- typedef Simplex_iterator<Skeleton_blocker_complex> Complex_simplex_iterator;
-
- typedef boost::iterator_range < Complex_simplex_iterator > Complex_simplex_range;
-
- /**
- * @brief Returns a Complex_simplex_range over all the simplices of the complex
- */
- Complex_simplex_range complex_simplex_range() const {
- Complex_simplex_iterator end(this, true);
- if (empty()) {
- return Complex_simplex_range(end, end);
- } else {
- Complex_simplex_iterator begin(this);
- return Complex_simplex_range(begin, end);
- }
- }
-
- //@}
-
- /** @name Blockers iterators
- */
- //@{
- private:
- /**
- * @brief Iterator over the blockers adjacent to a vertex
- */
- typedef Blocker_iterator_around_vertex_internal<
- typename std::multimap<Vertex_handle, Simplex *>::iterator,
- Blocker_handle>
- Complex_blocker_around_vertex_iterator;
-
- /**
- * @brief Iterator over (constant) blockers adjacent to a vertex
- */
- typedef Blocker_iterator_around_vertex_internal<
- typename std::multimap<Vertex_handle, Simplex *>::const_iterator,
- const Blocker_handle>
- Const_complex_blocker_around_vertex_iterator;
-
- typedef boost::iterator_range <Complex_blocker_around_vertex_iterator> Complex_blocker_around_vertex_range;
- typedef boost::iterator_range <Const_complex_blocker_around_vertex_iterator>
- Const_complex_blocker_around_vertex_range;
-
- public:
- /**
- * @brief Returns a range of the blockers of the complex passing through a vertex
- */
- Complex_blocker_around_vertex_range blocker_range(Vertex_handle v) {
- auto begin = Complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v));
- auto end = Complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v));
- return Complex_blocker_around_vertex_range(begin, end);
- }
-
- /**
- * @brief Returns a range of the blockers of the complex passing through a vertex
- */
- Const_complex_blocker_around_vertex_range const_blocker_range(Vertex_handle v) const {
- auto begin = Const_complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v));
- auto end = Const_complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v));
- return Const_complex_blocker_around_vertex_range(begin, end);
- }
-
- private:
- /**
- * @brief Iterator over the blockers.
- */
- typedef Blocker_iterator_internal<
- typename std::multimap<Vertex_handle, Simplex *>::iterator,
- Blocker_handle>
- Complex_blocker_iterator;
-
- /**
- * @brief Iterator over the (constant) blockers.
- */
- typedef Blocker_iterator_internal<
- typename std::multimap<Vertex_handle, Simplex *>::const_iterator,
- const Blocker_handle>
- Const_complex_blocker_iterator;
-
- typedef boost::iterator_range <Complex_blocker_iterator> Complex_blocker_range;
- typedef boost::iterator_range <Const_complex_blocker_iterator> Const_complex_blocker_range;
-
- public:
- /**
- * @brief Returns a range of the blockers of the complex
- */
- Complex_blocker_range blocker_range() {
- auto begin = Complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end());
- auto end = Complex_blocker_iterator(blocker_map_.end(), blocker_map_.end());
- return Complex_blocker_range(begin, end);
- }
-
- /**
- * @brief Returns a range of the blockers of the complex
- */
- Const_complex_blocker_range const_blocker_range() const {
- auto begin = Const_complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end());
- auto end = Const_complex_blocker_iterator(blocker_map_.end(), blocker_map_.end());
- return Const_complex_blocker_range(begin, end);
- }
-
- //@}
-
- /////////////////////////////////////////////////////////////////////////////
- /** @name Print and IO methods
- */
- //@{
- public:
- std::string to_string() const {
- std::ostringstream stream;
- stream << num_vertices() << " vertices:\n" << vertices_to_string() << std::endl;
- stream << num_edges() << " edges:\n" << edges_to_string() << std::endl;
- stream << num_blockers() << " blockers:\n" << blockers_to_string() << std::endl;
- return stream.str();
- }
-
- std::string vertices_to_string() const {
- std::ostringstream stream;
- for (auto vertex : vertex_range()) {
- stream << "{" << (*this)[vertex].get_id() << "} ";
- }
- stream << std::endl;
- return stream.str();
- }
-
- std::string edges_to_string() const {
- std::ostringstream stream;
- for (auto edge : edge_range())
- stream << "{" << (*this)[edge].first() << "," << (*this)[edge].second() << "} ";
- stream << std::endl;
- return stream.str();
- }
-
- std::string blockers_to_string() const {
- std::ostringstream stream;
-
- for (auto b : const_blocker_range())
- stream << *b << std::endl;
- return stream.str();
- }
- //@}
-};
-
-/**
- * build a simplicial complex from a collection
- * of top faces.
- * return the total number of simplices
- */
-template<typename Complex, typename SimplexHandleIterator>
-Complex make_complex_from_top_faces(SimplexHandleIterator simplices_begin, SimplexHandleIterator simplices_end,
- bool is_flag_complex = false) {
- // TODO(DS): use add_simplex instead! should be more efficient and more elegant :)
- typedef typename Complex::Simplex Simplex;
- std::vector<Simplex> simplices;
- for (auto top_face = simplices_begin; top_face != simplices_end; ++top_face) {
- auto subfaces_topface = subfaces(*top_face);
- simplices.insert(simplices.end(), subfaces_topface.begin(), subfaces_topface.end());
- }
- return Complex(simplices.begin(), simplices.end(), is_flag_complex);
-}
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#include "Skeleton_blocker_simplifiable_complex.h"
-
-#endif // SKELETON_BLOCKER_COMPLEX_H_
diff --git a/include/gudhi/Skeleton_blocker_contractor.h b/include/gudhi/Skeleton_blocker_contractor.h
deleted file mode 100644
index 13086161..00000000
--- a/include/gudhi/Skeleton_blocker_contractor.h
+++ /dev/null
@@ -1,582 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_CONTRACTOR_H_
-#define SKELETON_BLOCKER_CONTRACTOR_H_
-
-// todo remove the queue to be independent from cgald
-#include <gudhi/Contraction/CGAL_queue/Modifiable_priority_queue.h>
-
-#include <gudhi/Contraction/Edge_profile.h>
-#include <gudhi/Contraction/policies/Cost_policy.h>
-#include <gudhi/Contraction/policies/Edge_length_cost.h>
-#include <gudhi/Contraction/policies/Placement_policy.h>
-#include <gudhi/Contraction/policies/First_vertex_placement.h>
-#include <gudhi/Contraction/policies/Valid_contraction_policy.h>
-#include <gudhi/Contraction/policies/Dummy_valid_contraction.h> // xxx remove
-#include <gudhi/Contraction/policies/Link_condition_valid_contraction.h> // xxx remove
-#include <gudhi/Contraction/policies/Contraction_visitor.h>
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h>
-#include <gudhi/Debug_utils.h>
-
-
-#include <boost/scoped_array.hpp>
-#include <boost/scoped_ptr.hpp>
-
-#include <memory>
-#include <cassert>
-#include <list>
-#include <utility> // for pair
-#include <vector>
-
-namespace Gudhi {
-
-namespace contraction {
-
-template <class Profile>
-Placement_policy<Profile>* make_first_vertex_placement() {
- return new First_vertex_placement<Profile>();
-}
-
-template <class Profile>
-Valid_contraction_policy<Profile>* make_link_valid_contraction() {
- return new Link_condition_valid_contraction<Profile>();
-}
-
-/**
- *@brief Visitor to remove popable blockers after an edge contraction.
- */
-template <class Profile>
-class Contraction_visitor_remove_popable : public Contraction_visitor<Profile> {
- public:
- typedef typename Profile::Point Point;
- typedef typename Profile::Complex Complex;
- typedef typename Complex::Vertex_handle Vertex_handle;
-
- void on_contracted(const Profile &profile, boost::optional< Point > placement) override {
- profile.complex().remove_all_popable_blockers(profile.v0_handle());
- }
-};
-
-template <class Profile>
-Contraction_visitor<Profile>* make_remove_popable_blockers_visitor() {
- return new Contraction_visitor_remove_popable<Profile>();
-}
-
-/**
- *@class Skeleton_blocker_contractor
- *@brief Class that allows to contract iteratively edges of a simplicial complex.
- *@ingroup contr
- *
- * @details The simplification algorithm consists in iteratively picking the
- * edge with lowest cost and performing an edge contraction if the contraction is valid.
- * This class is policy based (and much inspired from the edge collapse package of CGAL http://doc.cgal.org/latest/Surface_mesh_simplification/index.html).
- *
- * Policies that can be changed are :
- * - the cost policy : how much cost an edge contraction
- * - the placement policy : where will be placed the contraction point
- * - the valid contraction policy : is the contraction valid. For instance, it can be
- * a topological condition (link condition) or a geometrical condition (normals messed up).
- *
- */
-template<class GeometricSimplifiableComplex, class EdgeProfile = Edge_profile<GeometricSimplifiableComplex>>
-class Skeleton_blocker_contractor : private skeleton_blocker::Dummy_complex_visitor<
-typename GeometricSimplifiableComplex::Vertex_handle> {
- GeometricSimplifiableComplex& complex_;
-
- public:
- typedef typename GeometricSimplifiableComplex::Graph_vertex Graph_vertex;
- typedef typename GeometricSimplifiableComplex::Vertex_handle Vertex_handle;
- typedef typename GeometricSimplifiableComplex::Simplex Simplex;
- typedef typename GeometricSimplifiableComplex::Root_vertex_handle Root_vertex_handle;
- typedef typename GeometricSimplifiableComplex::Graph_edge Graph_edge;
- typedef typename GeometricSimplifiableComplex::Edge_handle Edge_handle;
- typedef typename GeometricSimplifiableComplex::Point Point;
-
- typedef EdgeProfile Profile;
-
-
- typedef Cost_policy<Profile> Cost_policy_;
- typedef Placement_policy<Profile> Placement_policy_;
- typedef Valid_contraction_policy<Profile> Valid_contraction_policy_;
- typedef Contraction_visitor<EdgeProfile> Contraction_visitor_;
- typedef Edge_profile_factory<EdgeProfile> Edge_profile_factory_;
-
-
-
- typedef boost::optional<double> Cost_type;
- typedef boost::optional<Point> Placement_type;
-
- typedef size_t size_type;
-
- typedef Skeleton_blocker_contractor Self;
-
- private:
- struct Compare_id {
- Compare_id() : algorithm_(0) { }
-
- Compare_id(Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
-
- bool operator()(Edge_handle a, Edge_handle b) const {
- return algorithm_->get_undirected_edge_id(a) < algorithm_->get_undirected_edge_id(b);
- }
-
- Self const* algorithm_;
- };
-
- struct Compare_cost {
- Compare_cost() : algorithm_(0) { }
-
- Compare_cost(Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
-
- bool operator()(Edge_handle a, Edge_handle b) const {
- // NOTE: A cost is an optional<> value.
- // Absent optionals are ordered first; that is, "none < T" and "T > none" for any defined T != none.
- // In consequence, edges with undefined costs will be promoted to the top of the priority queue and popped out
- // first.
- return algorithm_->get_data(a).cost() < algorithm_->get_data(b).cost();
- }
-
- Self const* algorithm_;
- };
-
- struct Undirected_edge_id : boost::put_get_helper<size_type, Undirected_edge_id> {
- typedef boost::readable_property_map_tag category;
- typedef size_type value_type;
- typedef size_type reference;
- typedef Edge_handle key_type;
-
- Undirected_edge_id() : algorithm_(0) { }
-
- Undirected_edge_id(Self const* aAlgorithm) : algorithm_(aAlgorithm) { }
-
- size_type operator[](Edge_handle e) const {
- return algorithm_->get_undirected_edge_id(e);
- }
-
- Self const* algorithm_;
- };
-
- typedef CGAL::Modifiable_priority_queue<Edge_handle, Compare_cost, Undirected_edge_id> PQ;
- typedef typename PQ::handle pq_handle;
-
-
- // An Edge_data is associated with EVERY edge in the complex (collapsible or not).
- // It relates the edge with the PQ-handle needed to update the priority queue
- // It also relates the edge with a policy-based cache
-
- class Edge_data {
- public:
- Edge_data() : PQHandle_(), cost_() { }
-
- Cost_type const& cost() const {
- return cost_;
- }
-
- Cost_type & cost() {
- return cost_;
- }
-
- pq_handle PQ_handle() const {
- return PQHandle_;
- }
-
- bool is_in_PQ() const {
- return PQHandle_ != PQ::null_handle();
- }
-
- void set_PQ_handle(pq_handle h) {
- PQHandle_ = h;
- }
-
- void reset_PQ_handle() {
- PQHandle_ = PQ::null_handle();
- }
-
- private:
- pq_handle PQHandle_;
- Cost_type cost_;
- };
- typedef Edge_data* Edge_data_ptr;
- typedef boost::scoped_array<Edge_data> Edge_data_array;
-
- int get_undirected_edge_id(Edge_handle edge) const {
- return complex_[edge].index();
- }
-
- const Edge_data& get_data(Edge_handle edge) const {
- return edge_data_array_[get_undirected_edge_id(edge)];
- }
-
- Edge_data& get_data(Edge_handle edge) {
- return edge_data_array_[get_undirected_edge_id(edge)];
- }
-
- Cost_type get_cost(const Profile & profile) const {
- return (*cost_policy_)(profile, get_placement(profile));
- }
-
- Profile create_profile(Edge_handle edge) const {
- if (edge_profile_factory_)
- return edge_profile_factory_->make_profile(complex_, edge);
- else
- return Profile(complex_, edge);
- }
-
- void insert_in_PQ(Edge_handle edge, Edge_data& data) {
- data.set_PQ_handle(heap_PQ_->push(edge));
- ++current_num_edges_heap_;
- }
-
- void update_in_PQ(Edge_handle edge, Edge_data& data) {
- data.set_PQ_handle(heap_PQ_->update(edge, data.PQ_handle()));
- }
-
- void remove_from_PQ(Edge_handle edge, Edge_data& data) {
- data.set_PQ_handle(heap_PQ_->erase(edge, data.PQ_handle()));
- --current_num_edges_heap_;
- }
-
- boost::optional<Edge_handle> pop_from_PQ() {
- boost::optional<Edge_handle> edge = heap_PQ_->extract_top();
- if (edge)
- get_data(*edge).reset_PQ_handle();
- return edge;
- }
-
- private:
- /**
- * @brief Collect edges.
- *
- * Iterates over all edges of the simplicial complex and
- * 1) inserts them in the priority queue sorted according to the Cost policy.
- * 2) set the id() field of each edge
- */
- void collect_edges() {
- //
- // Loop over all the edges in the complex in the heap
- //
- size_type size = complex_.num_edges();
- DBG("Collecting edges ...");
- DBGMSG("num edges :", size);
-
- edge_data_array_.reset(new Edge_data[size]);
-
- heap_PQ_.reset(new PQ(size, Compare_cost(this), Undirected_edge_id(this)));
-
- std::size_t id = 0;
-
- // xxx do a parralel for
- for (auto edge : complex_.edge_range()) {
- complex_[edge].index() = id++;
- Profile const& profile = create_profile(edge);
- Edge_data& data = get_data(edge);
- data.cost() = get_cost(profile);
- ++initial_num_edges_heap_;
- insert_in_PQ(edge, data);
- if (contraction_visitor_) contraction_visitor_->on_collected(profile, data.cost());
- }
-
- DBG("Edges collected.");
- }
-
- bool should_stop(double lCost, const Profile &profile) const {
- return false;
- }
-
- boost::optional<Point> get_placement(const Profile& profile) const {
- return (*placement_policy_)(profile);
- }
-
- bool is_contraction_valid(Profile const& profile, Placement_type placement) const {
- if (!valid_contraction_policy_) return true;
- return (*valid_contraction_policy_)(profile, placement);
- }
-
-
- public:
- /**
- * \brief Contract edges.
- *
- * While the heap is not empty, it extracts the edge with the minimum
- * cost in the heap then try to contract it.
- * It stops when the Stop policy says so or when the number of contractions
- * given by 'num_max_contractions' is reached (if this number is positive).
- */
- void contract_edges(int num_max_contractions = -1) {
- DBG("\n\nContract edges");
- int num_contraction = 0;
-
- bool unspecified_num_contractions = (num_max_contractions == -1);
- //
- // Pops and processes each edge from the PQ
- //
- boost::optional<Edge_handle> edge;
- while ((edge = pop_from_PQ()) && ((num_contraction < num_max_contractions) || (unspecified_num_contractions))) {
- Profile const& profile = create_profile(*edge);
- Cost_type cost(get_data(*edge).cost());
- if (contraction_visitor_) contraction_visitor_->on_selected(profile, cost, 0, 0);
-
- DBGMSG("\n\n---- Pop edge - num vertices :", complex_.num_vertices());
-
- if (cost) {
- DBGMSG("sqrt(cost):", std::sqrt(*cost));
- if (should_stop(*cost, profile)) {
- if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
- DBG("should_stop");
- break;
- }
- Placement_type placement = get_placement(profile);
- if (is_contraction_valid(profile, placement) && placement) {
- DBG("contraction_valid");
- contract_edge(profile, placement);
- ++num_contraction;
- } else {
- DBG("contraction not valid");
- if (contraction_visitor_) contraction_visitor_->on_non_valid(profile);
- }
- } else {
- DBG("uncomputable cost");
- }
- }
- if (contraction_visitor_) contraction_visitor_->on_stop_condition_reached();
- }
-
- bool is_in_heap(Edge_handle edge) const {
- if (heap_PQ_->empty()) {
- return false;
- } else {
- return edge_data_array_[get_undirected_edge_id(edge)].is_in_PQ();
- }
- }
-
- bool is_heap_empty() const {
- return heap_PQ_->empty();
- }
-
- /**
- * @brief Returns an Edge_handle and a Placement_type. This pair consists in
- * the edge with the lowest cost in the heap together with its placement.
- * The returned value is initialized iff the heap is non-empty.
- */
- boost::optional<std::pair<Edge_handle, Placement_type > > top_edge() {
- boost::optional<std::pair<Edge_handle, Placement_type > > res;
-
- if (!heap_PQ_->empty()) {
- auto edge = heap_PQ_->top();
- Profile const& profile = create_profile(edge);
- Placement_type placement = get_placement(profile);
- res = std::make_pair(edge, placement);
- DBGMSG("top edge:", complex_[edge]);
- }
- return res;
- }
-
- /**
- * @brief Constructor with default policies.
- *
- * @details The default cost, placement, valid and visitor policies
- * are respectively : the edge length, the first point, the link condition
- */
- Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex)
- : complex_(complex),
- cost_policy_(new Edge_length_cost<Profile>),
- placement_policy_(new First_vertex_placement<Profile>),
- valid_contraction_policy_(new Link_condition_valid_contraction<Profile>),
- contraction_visitor_(new Contraction_visitor_()),
- edge_profile_factory_(0),
- initial_num_edges_heap_(0),
- current_num_edges_heap_(0) {
- complex_.set_visitor(this);
- if (contraction_visitor_) contraction_visitor_->on_started(complex);
- collect_edges();
- }
-
- /**
- * @brief Constructor with customed policies.
- * @remark Policies destruction is handle by the class with smart pointers.
- */
- Skeleton_blocker_contractor(GeometricSimplifiableComplex& complex,
- Cost_policy_ *cost_policy,
- Placement_policy_ * placement_policy = new First_vertex_placement<Profile>,
- Valid_contraction_policy_ * valid_contraction_policy =
- new Link_condition_valid_contraction<Profile>,
- Contraction_visitor_* contraction_visitor = new Contraction_visitor_(),
- Edge_profile_factory_* edge_profile_factory = NULL) :
- complex_(complex),
- cost_policy_(cost_policy),
- placement_policy_(placement_policy),
- valid_contraction_policy_(valid_contraction_policy),
- contraction_visitor_(contraction_visitor),
- edge_profile_factory_(edge_profile_factory),
- initial_num_edges_heap_(0),
- current_num_edges_heap_(0) {
- complex_.set_visitor(this);
- if (contraction_visitor) contraction_visitor->on_started(complex);
- collect_edges();
- }
-
- ~Skeleton_blocker_contractor() {
- complex_.set_visitor(0);
- }
-
- private:
- void contract_edge(const Profile& profile, Placement_type placement) {
- if (contraction_visitor_) contraction_visitor_->on_contracting(profile, placement);
-
- assert(complex_.contains_vertex(profile.v0_handle()));
- assert(complex_.contains_vertex(profile.v1_handle()));
- assert(placement);
-
- profile.complex().point(profile.v0_handle()) = *placement;
-
- // remark : this is not necessary since v1 will be deactivated
- // profile.complex().point(profile.v1_handle()) = *placement;
-
- complex_.contract_edge(profile.v0_handle(), profile.v1_handle());
-
- assert(complex_.contains_vertex(profile.v0_handle()));
- assert(!complex_.contains_vertex(profile.v1_handle()));
-
- update_changed_edges();
-
- // the visitor could do something as complex_.remove_popable_blockers();
- if (contraction_visitor_) contraction_visitor_->on_contracted(profile, placement);
- }
-
- private:
- // every time the visitor's method on_changed_edge is called, it adds an
- // edge to changed_edges_
- std::vector< Edge_handle > changed_edges_;
-
- /**
- * @brief we update the cost and the position in the heap of an edge that has
- * been changed
- */
- inline void on_changed_edge(Vertex_handle a, Vertex_handle b) override {
- boost::optional<Edge_handle> ab(complex_[std::make_pair(a, b)]);
- assert(ab);
- changed_edges_.push_back(*ab);
- }
-
- void update_changed_edges() {
- // xxx do a parralel for
- DBG("update edges");
-
- // sequential loop
- for (auto ab : changed_edges_) {
- // 1-get the Edge_handle corresponding to ab
- // 2-change the data in mEdgeArray[ab.id()]
- // 3-update the heap
- Edge_data& data = get_data(ab);
- Profile const& profile = create_profile(ab);
- data.cost() = get_cost(profile);
- if (data.is_in_PQ()) {
- update_in_PQ(ab, data);
- } else {
- insert_in_PQ(ab, data);
- }
- }
- changed_edges_.clear();
- }
-
-
- private:
- void on_remove_edge(Vertex_handle a, Vertex_handle b) override {
- boost::optional<Edge_handle> ab((complex_[std::make_pair(a, b)]));
- assert(ab);
- Edge_data& lData = get_data(*ab);
- if (lData.is_in_PQ()) {
- remove_from_PQ(*ab, lData);
- }
- }
-
- private:
- /**
- * @brief Called when the edge 'ax' has been added while the edge 'bx'
- * is still there but will be removed on next instruction.
- * We assign the index of 'bx' to the edge index of 'ax'
- */
- void on_swaped_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) override {
- boost::optional<Edge_handle> ax(complex_[std::make_pair(a, x)]);
- boost::optional<Edge_handle> bx(complex_[std::make_pair(b, x)]);
- assert(ax && bx);
- complex_[*ax].index() = complex_[*bx].index();
- }
-
- private:
- /**
- * @brief Called when a blocker is removed.
- * All the edges that passes through the blocker may be edge-contractible
- * again and are thus reinserted in the heap.
- */
- void on_delete_blocker(const Simplex * blocker) override {
- // we go for all pairs xy that belongs to the blocker
- // note that such pairs xy are necessarily edges of the complex
- // by definition of a blocker
-
- // todo uniqument utile pour la link condition
- // laisser a l'utilisateur ? booleen update_heap_on_removed_blocker?
- Simplex blocker_copy(*blocker);
- for (auto x = blocker_copy.begin(); x != blocker_copy.end(); ++x) {
- for (auto y = x; ++y != blocker_copy.end();) {
- auto edge_descr(complex_[std::make_pair(*x, *y)]);
- assert(edge_descr);
- Edge_data& data = get_data(*edge_descr);
- Profile const& profile = create_profile(*edge_descr);
- data.cost() = get_cost(profile);
-
- // If the edge is already in the heap
- // its priority has not changed.
- // If the edge is not present, we reinsert it
- // remark : we could also reinsert the edge
- // only if it is valid
- if (!data.is_in_PQ()) {
- insert_in_PQ(*edge_descr, data);
- }
- }
- }
- }
-
-
- private:
- std::shared_ptr<Cost_policy_> cost_policy_;
- std::shared_ptr<Placement_policy_> placement_policy_;
- std::shared_ptr<Valid_contraction_policy_> valid_contraction_policy_;
- std::shared_ptr<Contraction_visitor_> contraction_visitor_;
-
- // in case the user wants to do something special when the edge profile
- // are created (for instance add some info)
- std::shared_ptr<Edge_profile_factory_> edge_profile_factory_;
- Edge_data_array edge_data_array_;
-
- boost::scoped_ptr<PQ> heap_PQ_;
- int initial_num_edges_heap_;
- int current_num_edges_heap_;
-};
-
-} // namespace contraction
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_CONTRACTOR_H_
diff --git a/include/gudhi/Skeleton_blocker_geometric_complex.h b/include/gudhi/Skeleton_blocker_geometric_complex.h
deleted file mode 100644
index 39b88ceb..00000000
--- a/include/gudhi/Skeleton_blocker_geometric_complex.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
-#define SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
-
-#include <gudhi/Skeleton_blocker_complex.h>
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
-#include <gudhi/Debug_utils.h>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * @brief Class that represents a geometric complex that can be simplified.
- * The class allows access to points of vertices.
- * @ingroup skbl
- */
-template<typename SkeletonBlockerGeometricDS>
-class Skeleton_blocker_geometric_complex :
-public Skeleton_blocker_complex<SkeletonBlockerGeometricDS> {
- public:
- typedef typename SkeletonBlockerGeometricDS::GT GT;
-
- typedef Skeleton_blocker_complex<SkeletonBlockerGeometricDS> SimplifiableSkeletonblocker;
-
- typedef typename SimplifiableSkeletonblocker::Vertex_handle Vertex_handle;
- typedef typename SimplifiableSkeletonblocker::Root_vertex_handle Root_vertex_handle;
- typedef typename SimplifiableSkeletonblocker::Edge_handle Edge_handle;
- typedef typename SimplifiableSkeletonblocker::Simplex Simplex;
-
- typedef typename SimplifiableSkeletonblocker::Graph_vertex Graph_vertex;
-
- typedef typename SkeletonBlockerGeometricDS::Point Point;
-
- Skeleton_blocker_geometric_complex() { }
-
- /**
- * constructor given a list of points
- */
- template<typename PointIterator>
- explicit Skeleton_blocker_geometric_complex(int num_vertices, PointIterator begin, PointIterator end) {
- for (auto point = begin; point != end; ++point)
- add_vertex(*point);
- }
-
- /**
- * @brief Constructor with a list of simplices.
- * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be
- * computed or not).
- */
- template<typename SimpleHandleOutputIterator, typename PointIterator>
- Skeleton_blocker_geometric_complex(
- SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end,
- PointIterator points_begin, PointIterator points_end,
- bool is_flag_complex = false)
- : Skeleton_blocker_complex<SkeletonBlockerGeometricDS>(simplex_begin, simplex_end, is_flag_complex) {
- unsigned current = 0;
- for (auto point = points_begin; point != points_end; ++point)
- (*this)[Vertex_handle(current++)].point() = Point(point->begin(), point->end());
- }
-
- /**
- * @brief Constructor with a list of simplices.
- * Points of every vertex are the point constructed with default constructor.
- * @details is_flag_complex indicates if the complex is a flag complex or not (to know if blockers have to be computed or not).
- */
- template<typename SimpleHandleOutputIterator>
- Skeleton_blocker_geometric_complex(
- SimpleHandleOutputIterator simplex_begin, SimpleHandleOutputIterator simplex_end,
- bool is_flag_complex = false)
- : Skeleton_blocker_complex<SkeletonBlockerGeometricDS>(simplex_begin, simplex_end, is_flag_complex) { }
-
- /**
- * @brief Add a vertex to the complex with a default constructed associated point.
- */
- Vertex_handle add_vertex() {
- return SimplifiableSkeletonblocker::add_vertex();
- }
-
- /**
- * @brief Add a vertex to the complex with its associated point.
- */
- Vertex_handle add_vertex(const Point& point) {
- Vertex_handle ad = SimplifiableSkeletonblocker::add_vertex();
- (*this)[ad].point() = point;
- return ad;
- }
-
- /**
- * @brief Returns the Point associated to the vertex v.
- */
- const Point& point(Vertex_handle v) const {
- assert(this->contains_vertex(v));
- return (*this)[v].point();
- }
-
- /**
- * @brief Returns the Point associated to the vertex v.
- */
- Point& point(Vertex_handle v) {
- assert(this->contains_vertex(v));
- return (*this)[v].point();
- }
-
- const Point& point(Root_vertex_handle global_v) const {
- Vertex_handle local_v((*this)[global_v]);
- assert(this->contains_vertex(local_v));
- return (*this)[local_v].point();
- }
-
- Point& point(Root_vertex_handle global_v) {
- Vertex_handle local_v((*this)[global_v]);
- assert(this->contains_vertex(local_v));
- return (*this)[local_v].point();
- }
-
- typedef Skeleton_blocker_link_complex<Skeleton_blocker_geometric_complex> Geometric_link;
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Geometric_link link(Vertex_handle v) const {
- Geometric_link link(*this, Simplex(v));
- // we now add the point info
- add_points_to_link(link);
- return link;
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Geometric_link link(const Simplex& simplex) const {
- Geometric_link link(*this, simplex);
- // we now add the point info
- add_points_to_link(link);
- return link;
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Geometric_link link(Edge_handle edge) const {
- Geometric_link link(*this, edge);
- // we now add the point info
- add_points_to_link(link);
- return link;
- }
-
- typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerGeometricDS>> Abstract_link;
-
- /**
- * Constructs the abstract link of v (without points coordinates).
- */
- Abstract_link abstract_link(Vertex_handle v) const {
- return Abstract_link(*this, Simplex(v));
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Abstract_link abstract_link(const Simplex& simplex) const {
- return Abstract_link(*this, simplex);
- }
-
- /**
- * Constructs the link of 'simplex' with points coordinates.
- */
- Abstract_link abstract_link(Edge_handle edge) const {
- return Abstract_link(*this, edge);
- }
-
- private:
- void add_points_to_link(Geometric_link& link) const {
- for (Vertex_handle v : link.vertex_range()) {
- Root_vertex_handle v_root(link.get_id(v));
- link.point(v) = (*this).point(v_root);
- }
- }
-};
-
-
-template<typename SkeletonBlockerGeometricComplex, typename SimpleHandleOutputIterator, typename PointIterator>
-SkeletonBlockerGeometricComplex make_complex_from_top_faces(
- SimpleHandleOutputIterator simplex_begin,
- SimpleHandleOutputIterator simplex_end,
- PointIterator points_begin,
- PointIterator points_end,
- bool is_flag_complex = false) {
- typedef SkeletonBlockerGeometricComplex SBGC;
- SkeletonBlockerGeometricComplex complex;
- unsigned current = 0;
- complex =
- make_complex_from_top_faces<SBGC>(simplex_begin, simplex_end, is_flag_complex);
- for (auto point = points_begin; point != points_end; ++point)
- // complex.point(Vertex_handle(current++)) = Point(point->begin(),point->end());
- complex.point(typename SBGC::Vertex_handle(current++)) = typename SBGC::Point(*point);
- return complex;
-}
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_GEOMETRIC_COMPLEX_H_
diff --git a/include/gudhi/Skeleton_blocker_link_complex.h b/include/gudhi/Skeleton_blocker_link_complex.h
deleted file mode 100644
index 428d4e9b..00000000
--- a/include/gudhi/Skeleton_blocker_link_complex.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_LINK_COMPLEX_H_
-#define SKELETON_BLOCKER_LINK_COMPLEX_H_
-
-#include <gudhi/Skeleton_blocker_complex.h>
-#include <gudhi/Debug_utils.h>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-template<class ComplexType> class Skeleton_blocker_sub_complex;
-
-/**
- * \brief Class representing the link of a simplicial complex encoded by a skeleton/blockers pair.
- * It inherits from Skeleton_blocker_sub_complex because such complex is a sub complex of a
- * root complex.
- * \ingroup skbl
- */
-template<typename ComplexType>
-class Skeleton_blocker_link_complex : public Skeleton_blocker_sub_complex<
-ComplexType> {
- template<typename T> friend class Skeleton_blocker_link_superior;
- typedef typename ComplexType::Edge_handle Edge_handle;
-
- typedef typename ComplexType::boost_vertex_handle boost_vertex_handle;
-
- private:
- bool only_superior_vertices_;
-
- public:
- typedef typename ComplexType::Vertex_handle Vertex_handle;
- typedef typename ComplexType::Root_vertex_handle Root_vertex_handle;
-
- typedef typename ComplexType::Simplex Simplex;
- typedef typename ComplexType::Root_simplex_handle Root_simplex_handle;
-
- typedef typename ComplexType::Blocker_handle Blocker_handle;
-
- typedef typename ComplexType::Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_handle_iterator;
-
- explicit Skeleton_blocker_link_complex(bool only_superior_vertices = false)
- : only_superior_vertices_(only_superior_vertices) { }
-
- /**
- * If the parameter only_superior_vertices is true,
- * only vertices greater than the one of alpha are added.
- * Only vertices are computed if only_vertices is true.
- */
- Skeleton_blocker_link_complex(const ComplexType & parent_complex,
- const Simplex& alpha_parent_adress,
- bool only_superior_vertices = false,
- bool only_vertices = false)
- : only_superior_vertices_(only_superior_vertices) {
- if (!alpha_parent_adress.empty())
- build_link(parent_complex, alpha_parent_adress, only_vertices);
- }
-
- /**
- * If the parameter only_superior_vertices is true,
- * only vertices greater than the one of the vertex are added.
- */
- Skeleton_blocker_link_complex(const ComplexType & parent_complex,
- Vertex_handle a_parent_adress,
- bool only_superior_vertices = false)
- : only_superior_vertices_(only_superior_vertices) {
- Simplex alpha_simplex(a_parent_adress);
- build_link(parent_complex, alpha_simplex);
- }
-
- /**
- * If the parameter only_superior_vertices is true,
- * only vertices greater than the one of the edge are added.
- */
- Skeleton_blocker_link_complex(const ComplexType & parent_complex,
- Edge_handle edge, bool only_superior_vertices =
- false)
- : only_superior_vertices_(only_superior_vertices) {
- Simplex alpha_simplex(parent_complex.first_vertex(edge),
- parent_complex.second_vertex(edge));
- build_link(parent_complex, alpha_simplex);
- }
-
- protected:
- /**
- * @brief compute vertices of the link.
- * If the boolean only_superior_vertices is true, then only the vertices
- * are greater than vertices of alpha_parent_adress are added.
- */
- void compute_link_vertices(const ComplexType & parent_complex,
- const Simplex& alpha_parent_adress,
- bool only_superior_vertices,
- bool is_alpha_blocker = false) {
- if (alpha_parent_adress.dimension() == 0) {
- // for a vertex we know exactly the number of vertices of the link (and the size of the corresponding vector)
- // thus we call a specific function that will reserve a vector with appropriate size
- this->compute_link_vertices(parent_complex,
- alpha_parent_adress.first_vertex(),
- only_superior_vertices_);
- } else {
- // we compute the intersection of neighbors of alpha and store it in link_vertices
- Simplex link_vertices_parent;
- parent_complex.add_neighbours(alpha_parent_adress, link_vertices_parent,
- only_superior_vertices);
- // For all vertex 'v' in this intersection, we go through all its adjacent blockers.
- // If one blocker minus 'v' is included in alpha then the vertex is not in the link complex.
- for (auto v_parent : link_vertices_parent) {
- bool new_vertex = true;
- for (auto beta : parent_complex.const_blocker_range(v_parent)) {
- if (!is_alpha_blocker || *beta != alpha_parent_adress) {
- new_vertex = !(alpha_parent_adress.contains_difference(*beta,
- v_parent));
- if (!new_vertex)
- break;
- }
- }
- if (new_vertex)
- this->add_vertex(parent_complex.get_id(v_parent));
- }
- }
- }
-
- /**
- * @brief compute vertices of the link.
- * If the boolean only_superior_vertices is true, then only the vertices
- * are greater than vertices of alpha_parent_adress are added.
- */
- void compute_link_vertices(const ComplexType & parent_complex,
- Vertex_handle alpha_parent_adress,
- bool only_superior_vertices) {
- // for a vertex we know exactly the number of vertices of the link (and the size of the corresponding vector
- this->skeleton.m_vertices.reserve(
- parent_complex.degree(alpha_parent_adress));
-
- // For all vertex 'v' in this intersection, we go through all its adjacent blockers.
- // If one blocker minus 'v' is included in alpha then the vertex is not in the link complex.
- for (auto v_parent : parent_complex.vertex_range(alpha_parent_adress)) {
- if (!only_superior_vertices
- || v_parent.vertex > alpha_parent_adress.vertex)
- this->add_vertex(parent_complex.get_id(v_parent));
- }
- }
-
- void compute_link_edges(const ComplexType & parent_complex,
- const Simplex& alpha_parent_adress,
- bool is_alpha_blocker = false) {
- if (this->num_vertices() <= 1)
- return;
-
- for (auto x_link = this->vertex_range().begin();
- x_link != this->vertex_range().end(); ++x_link) {
- for (auto y_link = x_link; ++y_link != this->vertex_range().end();) {
- Vertex_handle x_parent = *parent_complex.get_address(
- this->get_id(*x_link));
- Vertex_handle y_parent = *parent_complex.get_address(
- this->get_id(*y_link));
- if (parent_complex.contains_edge(x_parent, y_parent)) {
- // we check that there is no blocker subset of alpha passing trough x and y
- bool new_edge = true;
- for (auto blocker_parent : parent_complex.const_blocker_range(
- x_parent)) {
- if (!is_alpha_blocker || *blocker_parent != alpha_parent_adress) {
- if (blocker_parent->contains(y_parent)) {
- new_edge = !(alpha_parent_adress.contains_difference(
- *blocker_parent, x_parent, y_parent));
- if (!new_edge)
- break;
- }
- }
- }
- if (new_edge)
- this->add_edge_without_blockers(*x_link, *y_link);
- }
- }
- }
- }
-
- /**
- * @brief : Given an address in the current complex, it returns the
- * corresponding address in 'other_complex'.
- * It assumes that other_complex have a vertex 'this.get_id(address)'
- */
- boost::optional<Vertex_handle> give_equivalent_vertex(const ComplexType & other_complex,
- Vertex_handle address) const {
- Root_vertex_handle id((*this)[address].get_id());
- return other_complex.get_address(id);
- }
-
- /*
- * compute the blockers of the link if is_alpha_blocker is false.
- * Otherwise, alpha is a blocker, and the link is computed in the complex where
- * the blocker is anticollapsed.
- */
- void compute_link_blockers(const ComplexType & parent_complex,
- const Simplex& alpha_parent,
- bool is_alpha_blocker = false) {
- for (auto x_link : this->vertex_range()) {
- Vertex_handle x_parent = *this->give_equivalent_vertex(parent_complex,
- x_link);
-
- for (auto blocker_parent : parent_complex.const_blocker_range(x_parent)) {
- if (!is_alpha_blocker || *blocker_parent != alpha_parent) {
- Simplex sigma_parent(*blocker_parent);
-
- sigma_parent.difference(alpha_parent);
-
- if (sigma_parent.dimension() >= 2
- && sigma_parent.first_vertex() == x_parent) {
- Root_simplex_handle sigma_id(parent_complex.get_id(sigma_parent));
- auto sigma_link = this->get_simplex_address(sigma_id);
- // ie if the vertices of sigma are vertices of the link
- if (sigma_link) {
- bool is_new_blocker = true;
- for (auto a : alpha_parent) {
- for (auto eta_parent : parent_complex.const_blocker_range(a)) {
- if (!is_alpha_blocker || *eta_parent != alpha_parent) {
- Simplex eta_minus_alpha(*eta_parent);
- eta_minus_alpha.difference(alpha_parent);
- if (eta_minus_alpha != sigma_parent
- && sigma_parent.contains_difference(*eta_parent,
- alpha_parent)) {
- is_new_blocker = false;
- break;
- }
- }
- }
- if (!is_new_blocker)
- break;
- }
- if (is_new_blocker)
- this->add_blocker(new Simplex(*sigma_link));
- }
- }
- }
- }
- }
- }
-
- public:
- /**
- * @brief compute vertices, edges and blockers of the link.
- * @details If the boolean only_superior_vertices is true, then the link is computed only
- * with vertices that are greater than vertices of alpha_parent_adress.
- */
- void build_link(const ComplexType & parent_complex,
- const Simplex& alpha_parent_adress,
- bool is_alpha_blocker = false,
- bool only_vertices = false) {
- assert(is_alpha_blocker || parent_complex.contains(alpha_parent_adress));
- compute_link_vertices(parent_complex, alpha_parent_adress, only_superior_vertices_);
- if (!only_vertices) {
- compute_link_edges(parent_complex, alpha_parent_adress, is_alpha_blocker);
- compute_link_blockers(parent_complex, alpha_parent_adress, is_alpha_blocker);
- }
- }
-
- /**
- * @brief build the link of a blocker which is the link
- * of the blocker's simplex if this simplex had been
- * removed from the blockers of the complex.
- */
- friend void build_link_of_blocker(const ComplexType & parent_complex,
- Simplex& blocker,
- Skeleton_blocker_link_complex & result) {
- assert(blocker.dimension() >= 2);
- assert(parent_complex.contains_blocker(blocker));
- result.clear();
- result.build_link(parent_complex, blocker, true);
- }
-};
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_LINK_COMPLEX_H_
diff --git a/include/gudhi/Skeleton_blocker_simplifiable_complex.h b/include/gudhi/Skeleton_blocker_simplifiable_complex.h
deleted file mode 100644
index d5adb39d..00000000
--- a/include/gudhi/Skeleton_blocker_simplifiable_complex.h
+++ /dev/null
@@ -1,467 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): David Salinas
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
-#define SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
-
-#include <gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h>
-
-#include <list>
-#include <vector>
-#include <set>
-
-namespace Gudhi {
-
-namespace skeleton_blocker {
-
-/**
- * Returns true if the blocker 'sigma' is popable.
- * To define popable, let us call 'L' the complex that
- * consists in the current complex without the blocker 'sigma'.
- * A blocker 'sigma' is then "popable" if the link of 'sigma'
- * in L is reducible.
- *
- */
-template<typename SkeletonBlockerDS>
-bool Skeleton_blocker_complex<SkeletonBlockerDS>::is_popable_blocker(Blocker_handle sigma) const {
- assert(this->contains_blocker(*sigma));
- Skeleton_blocker_link_complex<Skeleton_blocker_complex> link_blocker_sigma;
- build_link_of_blocker(*this, *sigma, link_blocker_sigma);
- return link_blocker_sigma.is_contractible() == CONTRACTIBLE;
-}
-
-/**
- * Removes all the popable blockers of the complex and delete them.
- * @returns the number of popable blockers deleted
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_popable_blockers() {
- std::list<Vertex_handle> vertex_to_check;
- for (auto v : this->vertex_range())
- vertex_to_check.push_front(v);
-
- while (!vertex_to_check.empty()) {
- Vertex_handle v = vertex_to_check.front();
- vertex_to_check.pop_front();
-
- bool blocker_popable_found = true;
- while (blocker_popable_found) {
- blocker_popable_found = false;
- for (auto block : this->blocker_range(v)) {
- if (this->is_popable_blocker(block)) {
- for (Vertex_handle nv : *block)
- if (nv != v) vertex_to_check.push_back(nv);
- this->delete_blocker(block);
- blocker_popable_found = true;
- break;
- }
- }
- }
- }
-}
-
-/**
- * Removes all the popable blockers of the complex passing through v and delete them.
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_popable_blockers(Vertex_handle v) {
- bool blocker_popable_found = true;
- while (blocker_popable_found) {
- blocker_popable_found = false;
- for (auto block : this->blocker_range(v)) {
- if (is_popable_blocker(block)) {
- this->delete_blocker(block);
- blocker_popable_found = true;
- }
- }
- }
-}
-
-/**
- * @brief Removes all the popable blockers of the complex passing through v and delete them.
- * Also remove popable blockers in the neighborhood if they became popable.
- *
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_all_popable_blockers(Vertex_handle v) {
- std::list<Vertex_handle> vertex_to_check;
- vertex_to_check.push_front(v);
-
- while (!vertex_to_check.empty()) {
- Vertex_handle v = vertex_to_check.front();
- vertex_to_check.pop_front();
-
- bool blocker_popable_found = true;
- while (blocker_popable_found) {
- blocker_popable_found = false;
- for (auto block : this->blocker_range(v)) {
- if (this->is_popable_blocker(block)) {
- for (Vertex_handle nv : *block)
- if (nv != v) vertex_to_check.push_back(nv);
- this->delete_blocker(block);
- blocker_popable_found = true;
- break;
- }
- }
- }
- }
-}
-
-/**
- * Remove the star of the vertice 'v'
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle v) {
- // we remove the blockers that are not consistent anymore
- update_blockers_after_remove_star_of_vertex_or_edge(Simplex(v));
- while (this->degree(v) > 0) {
- Vertex_handle w(* (adjacent_vertices(v.vertex, this->skeleton).first));
- this->remove_edge(v, w);
- }
- this->remove_vertex(v);
-}
-
-/**
- * after removing the star of a simplex, blockers sigma that contains this simplex must be removed.
- * Furthermore, all simplices tau of the form sigma \setminus simplex_to_be_removed must be added
- * whenever the dimension of tau is at least 2.
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::update_blockers_after_remove_star_of_vertex_or_edge(const Simplex& simplex_to_be_removed) {
- std::list <Blocker_handle> blockers_to_update;
- if (simplex_to_be_removed.empty()) return;
-
- auto v0 = simplex_to_be_removed.first_vertex();
- for (auto blocker : this->blocker_range(v0)) {
- if (blocker->contains(simplex_to_be_removed))
- blockers_to_update.push_back(blocker);
- }
-
- for (auto blocker_to_update : blockers_to_update) {
- Simplex sub_blocker_to_be_added;
- bool sub_blocker_need_to_be_added =
- (blocker_to_update->dimension() - simplex_to_be_removed.dimension()) >= 2;
- if (sub_blocker_need_to_be_added) {
- sub_blocker_to_be_added = *blocker_to_update;
- sub_blocker_to_be_added.difference(simplex_to_be_removed);
- }
- this->delete_blocker(blocker_to_update);
- if (sub_blocker_need_to_be_added)
- this->add_blocker(sub_blocker_to_be_added);
- }
-}
-
-/**
- * Remove the star of the edge connecting vertices a and b.
- * @returns the number of blocker that have been removed
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Vertex_handle a, Vertex_handle b) {
- update_blockers_after_remove_star_of_vertex_or_edge(Simplex(a, b));
- // we remove the edge
- this->remove_edge(a, b);
-}
-
-/**
- * Remove the star of the edge 'e'.
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(Edge_handle e) {
- return remove_star(this->first_vertex(e), this->second_vertex(e));
-}
-
-/**
- * Remove the star of the simplex 'sigma' which needs to belong to the complex
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_star(const Simplex& sigma) {
- assert(this->contains(sigma));
- if (sigma.dimension() == 0) {
- remove_star(sigma.first_vertex());
- } else if (sigma.dimension() == 1) {
- remove_star(sigma.first_vertex(), sigma.last_vertex());
- } else {
- remove_blocker_containing_simplex(sigma);
- this->add_blocker(sigma);
- }
-}
-
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::add_simplex(const Simplex& sigma) {
- // to add a simplex s, all blockers included in s are first removed
- // and then all simplex in the coboundary of s are added as blockers
- assert(!this->contains(sigma));
- assert(sigma.dimension() > 1);
- if (!contains_vertices(sigma)) {
- std::cerr << "add_simplex: Some vertices were not present in the complex, adding them" << std::endl;
- size_t num_vertices_to_add = sigma.last_vertex() - this->num_vertices() + 1;
- for (size_t i = 0; i < num_vertices_to_add; ++i)
- this->add_vertex();
- }
- assert(contains_vertices(sigma));
- if (!contains_edges(sigma))
- add_edge(sigma);
- remove_blocker_include_in_simplex(sigma);
- add_blockers_after_simplex_insertion(sigma);
-}
-
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::add_blockers_after_simplex_insertion(Simplex sigma) {
- if (sigma.dimension() < 1) return;
-
- for (auto s : coboundary_range(sigma)) {
- this->add_blocker(s);
- }
-}
-
-/**
- * remove all blockers that contains sigma
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_containing_simplex(const Simplex& sigma) {
- std::vector <Blocker_handle> blockers_to_remove;
- for (auto blocker : this->blocker_range(sigma.first_vertex())) {
- if (blocker->contains(sigma))
- blockers_to_remove.push_back(blocker);
- }
- for (auto blocker_to_update : blockers_to_remove)
- this->delete_blocker(blocker_to_update);
-}
-
-/**
- * remove all blockers that contains sigma
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::remove_blocker_include_in_simplex(const Simplex& sigma) {
- // TODO(DS): write efficiently by using only superior blockers
- // eg for all s, check blockers whose vertices are all greater than s
- std::set <Blocker_handle> blockers_to_remove;
- for (auto s : sigma) {
- for (auto blocker : this->blocker_range(s)) {
- if (sigma.contains(*blocker))
- blockers_to_remove.insert(blocker);
- }
- }
- for (auto blocker_to_update : blockers_to_remove) {
- auto s = *blocker_to_update;
- this->delete_blocker(blocker_to_update);
- // now if there is a vertex v in the link of s
- // and v is not included in sigma then v.s is a blocker
- // (all faces of v.s are there since v belongs to the link of s)
- for (const auto& b : coboundary_range(s))
- if (!sigma.contains(b))
- this->add_blocker(b);
- }
-}
-
-/**
- * Compute simplices beta such that a.beta is an order 0 blocker
- * that may be used to construct a new blocker after contracting ab.
- * It requires that the link condition is satisfied.
- */
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::tip_blockers(Vertex_handle a, Vertex_handle b,
- std::vector<Simplex> & buffer) const {
- for (auto const & blocker : this->const_blocker_range(a)) {
- Simplex beta = (*blocker);
- beta.remove_vertex(a);
- buffer.push_back(beta);
- }
-
- Simplex n;
- this->add_neighbours(b, n);
- this->remove_neighbours(a, n);
- n.remove_vertex(a);
-
-
- for (Vertex_handle y : n) {
- Simplex beta;
- beta.add_vertex(y);
- buffer.push_back(beta);
- }
-}
-
-/**
- * @brief "Replace" the edge 'bx' by the edge 'ax'.
- * Assume that the edge 'bx' was present whereas 'ax' was not.
- * Precisely, it does not replace edges, but remove 'bx' and then add 'ax'.
- * The visitor 'on_swaped_edge' is called just after edge 'ax' had been added
- * and just before edge 'bx' had been removed. That way, it can
- * eventually access to information of 'ax'.
- */
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::swap_edge(Vertex_handle a, Vertex_handle b, Vertex_handle x) {
- this->add_edge_without_blockers(a, x);
- if (this->visitor) this->visitor->on_swaped_edge(a, b, x);
- this->remove_edge(b, x);
-}
-
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_vertex(Vertex_handle v) {
- std::list <Blocker_handle> blockers_to_delete;
- for (auto blocker : this->blocker_range(v)) {
- blockers_to_delete.push_back(blocker);
- }
- while (!blockers_to_delete.empty()) {
- this->remove_blocker(blockers_to_delete.back());
- blockers_to_delete.pop_back();
- }
-}
-
-/**
- * @brief removes all blockers passing through the edge 'ab'
- */
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_edge(Vertex_handle a, Vertex_handle b) {
- std::list<Blocker_handle> blocker_to_delete;
- for (auto blocker : this->blocker_range(a))
- if (blocker->contains(b)) blocker_to_delete.push_back(blocker);
- while (!blocker_to_delete.empty()) {
- this->delete_blocker(blocker_to_delete.back());
- blocker_to_delete.pop_back();
- }
-}
-
-/**
- * Contracts the edge connecting vertices a and b.
- * @remark If the link condition Link(ab) = Link(a) inter Link(b) is not satisfied,
- * it removes first all blockers passing through 'ab'
- */
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::contract_edge(Vertex_handle a, Vertex_handle b) {
- assert(this->contains_vertex(a));
- assert(this->contains_vertex(b));
-
- if (this->contains_edge(a, b))
- this->add_edge_without_blockers(a, b);
-
- // if some blockers passes through 'ab', we need to remove them.
- if (!link_condition(a, b))
- delete_blockers_around_edge(a, b);
-
- std::set<Simplex> blockers_to_add;
-
- get_blockers_to_be_added_after_contraction(a, b, blockers_to_add);
-
- delete_blockers_around_vertices(a, b);
-
- update_edges_after_contraction(a, b);
-
- this->remove_vertex(b);
-
- notify_changed_edges(a);
-
- for (auto block : blockers_to_add)
- this->add_blocker(block);
-
- assert(this->contains_vertex(a));
- assert(!this->contains_vertex(b));
-}
-
-template<typename SkeletonBlockerDS>
-void Skeleton_blocker_complex<SkeletonBlockerDS>::get_blockers_to_be_added_after_contraction(Vertex_handle a,
- Vertex_handle b,
- std::set<Simplex>& blockers_to_add) {
- blockers_to_add.clear();
-
- typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > LinkComplexType;
-
- LinkComplexType link_a(*this, a);
- LinkComplexType link_b(*this, b);
-
- std::vector<Simplex> vector_alpha, vector_beta;
-
- tip_blockers(a, b, vector_alpha);
- tip_blockers(b, a, vector_beta);
-
- for (auto alpha = vector_alpha.begin(); alpha != vector_alpha.end(); ++alpha) {
- for (auto beta = vector_beta.begin(); beta != vector_beta.end(); ++beta) {
- Simplex sigma = *alpha;
- sigma.union_vertices(*beta);
- Root_simplex_handle sigma_id = this->get_id(sigma);
- if (this->contains(sigma) &&
- proper_faces_in_union<Skeleton_blocker_complex < SkeletonBlockerDS >> (sigma_id, link_a, link_b)) {
- // Blocker_handle blocker = new Simplex(sigma);
- sigma.add_vertex(a);
- blockers_to_add.insert(sigma);
- }
- }
- }
-}
-
-/**
- * delete all blockers that passes through a or b
- */
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::delete_blockers_around_vertices(Vertex_handle a, Vertex_handle b) {
- std::vector<Blocker_handle> blocker_to_delete;
- for (auto bl : this->blocker_range(a))
- blocker_to_delete.push_back(bl);
- for (auto bl : this->blocker_range(b))
- blocker_to_delete.push_back(bl);
- while (!blocker_to_delete.empty()) {
- this->delete_blocker(blocker_to_delete.back());
- blocker_to_delete.pop_back();
- }
-}
-
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::update_edges_after_contraction(Vertex_handle a, Vertex_handle b) {
- // We update the set of edges
- this->remove_edge(a, b);
-
- // For all edges {b,x} incident to b,
- // we remove {b,x} and add {a,x} if not already there.
- while (this->degree(b) > 0) {
- Vertex_handle x(*(adjacent_vertices(b.vertex, this->skeleton).first));
- if (!this->contains_edge(a, x))
- // we 'replace' the edge 'bx' by the edge 'ax'
- this->swap_edge(a, b, x);
- else
- this->remove_edge(b, x);
- }
-}
-
-template<typename SkeletonBlockerDS>
-void
-Skeleton_blocker_complex<SkeletonBlockerDS>::notify_changed_edges(Vertex_handle a) {
- // We notify the visitor that all edges incident to 'a' had changed
- boost_adjacency_iterator v, v_end;
-
- for (tie(v, v_end) = adjacent_vertices(a.vertex, this->skeleton); v != v_end; ++v)
- if (this->visitor) this->visitor->on_changed_edge(a, Vertex_handle(*v));
-}
-
-
-} // namespace skeleton_blocker
-
-namespace skbl = skeleton_blocker;
-
-} // namespace Gudhi
-
-#endif // SKELETON_BLOCKER_SIMPLIFIABLE_COMPLEX_H_
diff --git a/include/gudhi/Sparse_rips_complex.h b/include/gudhi/Sparse_rips_complex.h
deleted file mode 100644
index 4dcc08ed..00000000
--- a/include/gudhi/Sparse_rips_complex.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Marc Glisse
- *
- * Copyright (C) 2018 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SPARSE_RIPS_COMPLEX_H_
-#define SPARSE_RIPS_COMPLEX_H_
-
-#include <gudhi/Debug_utils.h>
-#include <gudhi/graph_simplicial_complex.h>
-#include <gudhi/choose_n_farthest_points.h>
-
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/range/metafunctions.hpp>
-
-#include <vector>
-
-namespace Gudhi {
-
-namespace rips_complex {
-
-// The whole interface is copied on Rips_complex. A redesign should be discussed with all complex creation classes in
-// mind.
-
-/**
- * \class Sparse_rips_complex
- * \brief Sparse Rips complex data structure.
- *
- * \ingroup rips_complex
- *
- * \details
- * This class is used to construct a sparse \f$(1+O(\epsilon))\f$-approximation of `Rips_complex`, i.e. a filtered
- * simplicial complex that is multiplicatively \f$(1+O(\epsilon))\f$-interleaved with the Rips filtration.
- *
- * \tparam Filtration_value is the type used to store the filtration values of the simplicial complex.
- */
-template <typename Filtration_value>
-class Sparse_rips_complex {
- private:
- // TODO(MG): use a different graph where we know we can safely insert in parallel.
- typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
- boost::property<vertex_filtration_t, Filtration_value>,
- boost::property<edge_filtration_t, Filtration_value>>
- Graph;
-
- typedef int Vertex_handle;
-
- public:
- /** \brief Sparse_rips_complex constructor from a list of points.
- *
- * @param[in] points Range of points.
- * @param[in] distance Distance function that returns a `Filtration_value` from 2 given points.
- * @param[in] epsilon Approximation parameter. epsilon must be positive.
- *
- */
- template <typename RandomAccessPointRange, typename Distance>
- Sparse_rips_complex(const RandomAccessPointRange& points, Distance distance, double epsilon) {
- GUDHI_CHECK(epsilon > 0, "epsilon must be positive");
- std::vector<Vertex_handle> sorted_points;
- std::vector<Filtration_value> params;
- auto dist_fun = [&](Vertex_handle i, Vertex_handle j) { return distance(points[i], points[j]); };
- Ker<decltype(dist_fun)> kernel(dist_fun);
- subsampling::choose_n_farthest_points(kernel, boost::irange<Vertex_handle>(0, boost::size(points)), -1, -1,
- std::back_inserter(sorted_points), std::back_inserter(params));
- compute_sparse_graph(sorted_points, params, dist_fun, epsilon);
- }
-
- /** \brief Sparse_rips_complex constructor from a distance matrix.
- *
- * @param[in] distance_matrix Range of range of distances.
- * `distance_matrix[i][j]` returns the distance between points \f$i\f$ and
- * \f$j\f$ as long as \f$ 0 \leqslant i < j \leqslant
- * distance\_matrix.size().\f$
- * @param[in] epsilon Approximation parameter. epsilon must be positive.
- */
- template <typename DistanceMatrix>
- Sparse_rips_complex(const DistanceMatrix& distance_matrix, double epsilon)
- : Sparse_rips_complex(boost::irange<Vertex_handle>(0, boost::size(distance_matrix)),
- [&](Vertex_handle i, Vertex_handle j) { return distance_matrix[j][i]; }, epsilon) {}
-
- /** \brief Fills the simplicial complex with the sparse Rips graph and
- * expands it with all the cliques, stopping at a given maximal dimension.
- *
- * \tparam SimplicialComplexForRips must meet `SimplicialComplexForRips` concept.
- *
- * @param[in] complex the complex to fill
- * @param[in] dim_max maximal dimension of the simplicial complex.
- * @exception std::invalid_argument In debug mode, if `complex.num_vertices()` does not return 0.
- *
- */
- template <typename SimplicialComplexForRips>
- void create_complex(SimplicialComplexForRips& complex, int dim_max) {
- GUDHI_CHECK(complex.num_vertices() == 0,
- std::invalid_argument("Sparse_rips_complex::create_complex - simplicial complex is not empty"));
-
- complex.insert_graph(graph_);
- complex.expansion(dim_max);
- }
-
- private:
- // choose_n_farthest_points wants the distance function in this form...
- template <class Distance>
- struct Ker {
- typedef std::size_t Point_d; // index into point range
- Ker(Distance& d) : dist(d) {}
- // Despite the name, this is not squared...
- typedef Distance Squared_distance_d;
- Squared_distance_d& squared_distance_d_object() const { return dist; }
- Distance& dist;
- };
-
- // PointRange must be random access.
- template <typename PointRange, typename ParamRange, typename Distance>
- void compute_sparse_graph(const PointRange& points, const ParamRange& params, Distance& dist, double epsilon) {
- const int n = boost::size(points);
- graph_.~Graph();
- new (&graph_) Graph(n);
- // for(auto v : vertices(g)) // doesn't work :-(
- typename boost::graph_traits<Graph>::vertex_iterator v_i, v_e;
- for (std::tie(v_i, v_e) = vertices(graph_); v_i != v_e; ++v_i) {
- auto v = *v_i;
- // This whole loop might not be necessary, leave it until someone investigates if it is safe to remove.
- put(vertex_filtration_t(), graph_, v, 0);
- }
-
- // TODO(MG):
- // - make it parallel
- // - only test near-enough neighbors
- for (int i = 0; i < n; ++i)
- for (int j = i + 1; j < n; ++j) {
- auto&& pi = points[i];
- auto&& pj = points[j];
- auto d = dist(pi, pj);
- auto li = params[i];
- auto lj = params[j];
- GUDHI_CHECK(lj <= li, "Bad furthest point sorting");
- Filtration_value alpha;
-
- // The paper has d/2 and d-lj/e to match the Cech, but we use doubles to match the Rips
- if (d * epsilon <= 2 * lj)
- alpha = d;
- else if (d * epsilon <= li + lj && (epsilon >= 1 || d * epsilon <= lj * (1 + 1 / (1 - epsilon))))
- alpha = (d - lj / epsilon) * 2;
- else
- continue;
-
- add_edge(pi, pj, alpha, graph_);
- }
- }
-
- Graph graph_;
-};
-
-} // namespace rips_complex
-
-} // namespace Gudhi
-
-#endif // SPARSE_RIPS_COMPLEX_H_
diff --git a/include/gudhi/Strong_witness_complex.h b/include/gudhi/Strong_witness_complex.h
deleted file mode 100644
index fd6b3f38..00000000
--- a/include/gudhi/Strong_witness_complex.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef STRONG_WITNESS_COMPLEX_H_
-#define STRONG_WITNESS_COMPLEX_H_
-
-#include <gudhi/Active_witness/Active_witness.h>
-
-#include <utility>
-#include <vector>
-#include <list>
-#include <limits>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
- /**
- * \private
- * \class Strong_witness_complex
- * \brief Constructs strong witness complex for a given table of nearest landmarks with respect to witnesses.
- * \ingroup witness_complex
- *
- * \tparam Nearest_landmark_table_ needs to be a range of a range of pairs of nearest landmarks and distances.
- * The class Nearest_landmark_table_::value_type must be a copiable range.
- * The range of pairs must admit a member type 'iterator'. The dereference type
- * of the pair range iterator needs to be 'std::pair<std::size_t, double>'.
- */
-template< class Nearest_landmark_table_ >
-class Strong_witness_complex {
- private:
- typedef typename Nearest_landmark_table_::value_type Nearest_landmark_range;
- typedef std::size_t Witness_id;
- typedef std::size_t Landmark_id;
- typedef std::pair<Landmark_id, double> Id_distance_pair;
- typedef Active_witness<Id_distance_pair, Nearest_landmark_range> ActiveWitness;
- typedef std::list< ActiveWitness > ActiveWitnessList;
- typedef std::vector< Landmark_id > typeVectorVertex;
- typedef std::vector<Nearest_landmark_range> Nearest_landmark_table_internal;
- typedef Landmark_id Vertex_handle;
-
- protected:
- Nearest_landmark_table_internal nearest_landmark_table_;
-
- public:
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /* @name Constructor
- */
-
- //@{
-
- Strong_witness_complex() {
- }
-
- /**
- * \brief Initializes member variables before constructing simplicial complex.
- * \details Records nearest landmark table.
- * @param[in] nearest_landmark_table needs to be a range of a range of pairs of nearest landmarks and distances.
- * The class Nearest_landmark_table_::value_type must be a copiable range.
- * The range of pairs must admit a member type 'iterator'. The dereference type
- * of the pair range iterator needs to be 'std::pair<std::size_t, double>'.
- */
- Strong_witness_complex(Nearest_landmark_table_ const & nearest_landmark_table)
- : nearest_landmark_table_(std::begin(nearest_landmark_table), std::end(nearest_landmark_table)) {
- }
-
- /** \brief Outputs the strong witness complex of relaxation 'max_alpha_square'
- * in a simplicial complex data structure.
- * \details The function returns true if the construction is successful and false otherwise.
- * @param[out] complex Simplicial complex data structure, which is a model of
- * SimplicialComplexForWitness concept.
- * @param[in] max_alpha_square Maximal squared relaxation parameter.
- * @param[in] limit_dimension Represents the maximal dimension of the simplicial complex
- * (default value = no limit).
- */
- template < typename SimplicialComplexForWitness >
- bool create_complex(SimplicialComplexForWitness& complex,
- double max_alpha_square,
- Landmark_id limit_dimension = std::numeric_limits<Landmark_id>::max()) const {
- Landmark_id complex_dim = 0;
- if (complex.num_vertices() > 0) {
- std::cerr << "Strong witness complex cannot create complex - complex is not empty.\n";
- return false;
- }
- if (max_alpha_square < 0) {
- std::cerr << "Strong witness complex cannot create complex - squared relaxation parameter must be "
- << "non-negative.\n";
- return false;
- }
- for (auto w : nearest_landmark_table_) {
- ActiveWitness aw(w);
- typeVectorVertex simplex;
- typename ActiveWitness::iterator aw_it = aw.begin();
- float lim_dist2 = aw.begin()->second + max_alpha_square;
- while ((Landmark_id)simplex.size() <= limit_dimension && aw_it != aw.end() && aw_it->second < lim_dist2) {
- simplex.push_back(aw_it->first);
- complex.insert_simplex_and_subfaces(simplex, aw_it->second - aw.begin()->second);
- aw_it++;
- }
- // continue inserting limD-faces of the following simplices
- typeVectorVertex& vertices = simplex; // 'simplex' now will be called vertices
- while (aw_it != aw.end() && aw_it->second < lim_dist2) {
- typeVectorVertex facet = {};
- add_all_faces_of_dimension(limit_dimension, vertices, vertices.begin(), aw_it,
- aw_it->second - aw.begin()->second, facet, complex);
- vertices.push_back(aw_it->first);
- aw_it++;
- }
- if ((Landmark_id)simplex.size() - 1 > complex_dim)
- complex_dim = simplex.size() - 1;
- }
- return true;
- }
-
- //@}
-
- private:
- /* \brief Adds recursively all the faces of a certain dimension dim-1 witnessed by the same witness.
- * Iterator is needed to know until how far we can take landmarks to form simplexes.
- * simplex is the prefix of the simplexes to insert.
- * The landmark pointed by aw_it is added to all formed simplices.
- */
- template < typename SimplicialComplexForWitness >
- void add_all_faces_of_dimension(Landmark_id dim,
- typeVectorVertex& vertices,
- typename typeVectorVertex::iterator curr_it,
- typename ActiveWitness::iterator aw_it,
- double filtration_value,
- typeVectorVertex& simplex,
- SimplicialComplexForWitness& sc) const {
- if (dim > 0) {
- while (curr_it != vertices.end()) {
- simplex.push_back(*curr_it);
- ++curr_it;
- add_all_faces_of_dimension(dim-1,
- vertices,
- curr_it,
- aw_it,
- filtration_value,
- simplex,
- sc);
- simplex.pop_back();
- add_all_faces_of_dimension(dim,
- vertices,
- curr_it,
- aw_it,
- filtration_value,
- simplex,
- sc);
- }
- } else if (dim == 0) {
- simplex.push_back(aw_it->first);
- sc.insert_simplex_and_subfaces(simplex, filtration_value);
- simplex.pop_back();
- }
- }
-};
-
-} // namespace witness_complex
-
-} // namespace Gudhi
-
-#endif // STRONG_WITNESS_COMPLEX_H_
diff --git a/include/gudhi/Tangential_complex.h b/include/gudhi/Tangential_complex.h
deleted file mode 100644
index d1c846cf..00000000
--- a/include/gudhi/Tangential_complex.h
+++ /dev/null
@@ -1,2008 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TANGENTIAL_COMPLEX_H_
-#define TANGENTIAL_COMPLEX_H_
-
-#include <gudhi/Tangential_complex/config.h>
-#include <gudhi/Tangential_complex/Simplicial_complex.h>
-#include <gudhi/Tangential_complex/utilities.h>
-#include <gudhi/Kd_tree_search.h>
-#include <gudhi/console_color.h>
-#include <gudhi/Clock.h>
-#include <gudhi/Simplex_tree.h>
-
-#include <CGAL/Default.h>
-#include <CGAL/Dimension.h>
-#include <CGAL/function_objects.h> // for CGAL::Identity
-#include <CGAL/Epick_d.h>
-#include <CGAL/Regular_triangulation_traits_adapter.h>
-#include <CGAL/Regular_triangulation.h>
-#include <CGAL/Delaunay_triangulation.h>
-#include <CGAL/Combination_enumerator.h>
-#include <CGAL/point_generators_d.h>
-
-#include <Eigen/Core>
-#include <Eigen/Eigen>
-
-#include <boost/optional.hpp>
-#include <boost/iterator/transform_iterator.hpp>
-#include <boost/range/adaptor/transformed.hpp>
-#include <boost/range/counting_range.hpp>
-#include <boost/math/special_functions/factorials.hpp>
-#include <boost/container/flat_set.hpp>
-
-#include <tuple>
-#include <vector>
-#include <set>
-#include <utility>
-#include <sstream>
-#include <iostream>
-#include <limits>
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <cmath> // for std::sqrt
-#include <string>
-#include <cstddef> // for std::size_t
-
-#ifdef GUDHI_USE_TBB
-#include <tbb/parallel_for.h>
-#include <tbb/combinable.h>
-#include <tbb/mutex.h>
-#endif
-
-// #define GUDHI_TC_EXPORT_NORMALS // Only for 3D surfaces (k=2, d=3)
-
-namespace sps = Gudhi::spatial_searching;
-
-namespace Gudhi {
-
-namespace tangential_complex {
-
-using namespace internal;
-
-class Vertex_data {
- public:
- Vertex_data(std::size_t data = (std::numeric_limits<std::size_t>::max)()) : m_data(data) {}
-
- operator std::size_t() { return m_data; }
-
- operator std::size_t() const { return m_data; }
-
- private:
- std::size_t m_data;
-};
-
-/**
- * \class Tangential_complex Tangential_complex.h gudhi/Tangential_complex.h
- * \brief Tangential complex data structure.
- *
- * \ingroup tangential_complex
- *
- * \details
- * The class Tangential_complex represents a tangential complex.
- * After the computation of the complex, an optional post-processing called perturbation can
- * be run to attempt to remove inconsistencies.
- *
- * \tparam Kernel_ requires a <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> class, which
- * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't.
- * \tparam DimensionTag can be either <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Dimension__tag.html">Dimension_tag<d></a>
- * if you know the intrinsic dimension at compile-time,
- * or <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_23/classCGAL_1_1Dynamic__dimension__tag.html">CGAL::Dynamic_dimension_tag</a>
- * if you don't.
- * \tparam Concurrency_tag enables sequential versus parallel computation. Possible values are `CGAL::Parallel_tag` (the
- * default) and `CGAL::Sequential_tag`. \tparam Triangulation_ is the type used for storing the local regular
- * triangulations. We highly recommend to use the default value (`CGAL::Regular_triangulation`).
- *
- */
-template <typename Kernel_, // ambiant kernel
- typename DimensionTag, // intrinsic dimension
- typename Concurrency_tag = CGAL::Parallel_tag, typename Triangulation_ = CGAL::Default>
-class Tangential_complex {
- typedef Kernel_ K;
- typedef typename K::FT FT;
- typedef typename K::Point_d Point;
- typedef typename K::Weighted_point_d Weighted_point;
- typedef typename K::Vector_d Vector;
-
- typedef typename CGAL::Default::Get<
- Triangulation_,
- CGAL::Regular_triangulation<
- CGAL::Epick_d<DimensionTag>,
- CGAL::Triangulation_data_structure<
- typename CGAL::Epick_d<DimensionTag>::Dimension,
- CGAL::Triangulation_vertex<CGAL::Regular_triangulation_traits_adapter<CGAL::Epick_d<DimensionTag> >,
- Vertex_data>,
- CGAL::Triangulation_full_cell<
- CGAL::Regular_triangulation_traits_adapter<CGAL::Epick_d<DimensionTag> > > > > >::type Triangulation;
- typedef typename Triangulation::Geom_traits Tr_traits;
- typedef typename Triangulation::Weighted_point Tr_point;
- typedef typename Tr_traits::Base::Point_d Tr_bare_point;
- typedef typename Triangulation::Vertex_handle Tr_vertex_handle;
- typedef typename Triangulation::Full_cell_handle Tr_full_cell_handle;
- typedef typename Tr_traits::Vector_d Tr_vector;
-
-#if defined(GUDHI_USE_TBB)
- typedef tbb::mutex Mutex_for_perturb;
- typedef Vector Translation_for_perturb;
- typedef std::vector<Atomic_wrapper<FT> > Weights;
-#else
- typedef Vector Translation_for_perturb;
- typedef std::vector<FT> Weights;
-#endif
- typedef std::vector<Translation_for_perturb> Translations_for_perturb;
-
- // Store a local triangulation and a handle to its center vertex
-
- struct Tr_and_VH {
- public:
- Tr_and_VH() : m_tr(NULL) {}
-
- Tr_and_VH(int dim) : m_tr(new Triangulation(dim)) {}
-
- ~Tr_and_VH() { destroy_triangulation(); }
-
- Triangulation &construct_triangulation(int dim) {
- delete m_tr;
- m_tr = new Triangulation(dim);
- return tr();
- }
-
- void destroy_triangulation() {
- delete m_tr;
- m_tr = NULL;
- }
-
- Triangulation &tr() { return *m_tr; }
-
- Triangulation const &tr() const { return *m_tr; }
-
- Tr_vertex_handle const &center_vertex() const { return m_center_vertex; }
-
- Tr_vertex_handle &center_vertex() { return m_center_vertex; }
-
- private:
- Triangulation *m_tr;
- Tr_vertex_handle m_center_vertex;
- };
-
- public:
- typedef Basis<K> Tangent_space_basis;
- typedef Basis<K> Orthogonal_space_basis;
- typedef std::vector<Tangent_space_basis> TS_container;
- typedef std::vector<Orthogonal_space_basis> OS_container;
-
- typedef std::vector<Point> Points;
-
- typedef boost::container::flat_set<std::size_t> Simplex;
- typedef std::set<Simplex> Simplex_set;
-
- private:
- typedef sps::Kd_tree_search<K, Points> Points_ds;
- typedef typename Points_ds::KNS_range KNS_range;
- typedef typename Points_ds::INS_range INS_range;
-
- typedef std::vector<Tr_and_VH> Tr_container;
- typedef std::vector<Vector> Vectors;
-
- // An Incident_simplex is the list of the vertex indices
- // except the center vertex
- typedef boost::container::flat_set<std::size_t> Incident_simplex;
- typedef std::vector<Incident_simplex> Star;
- typedef std::vector<Star> Stars_container;
-
- // For transform_iterator
-
- static const Tr_point &vertex_handle_to_point(Tr_vertex_handle vh) { return vh->point(); }
-
- template <typename P, typename VH>
- static const P &vertex_handle_to_point(VH vh) {
- return vh->point();
- }
-
- public:
- typedef internal::Simplicial_complex Simplicial_complex;
-
- /** \brief Constructor from a range of points.
- * Points are copied into the instance, and a search data structure is initialized.
- * Note the complex is not computed: `compute_tangential_complex` must be called after the creation
- * of the object.
- *
- * @param[in] points Range of points (`Point_range::value_type` must be the same as `Kernel_::Point_d`).
- * @param[in] intrinsic_dimension Intrinsic dimension of the manifold.
- * @param[in] k Kernel instance.
- */
- template <typename Point_range>
- Tangential_complex(Point_range points, int intrinsic_dimension,
-#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
- InputIterator first_for_tse, InputIterator last_for_tse,
-#endif
- const K &k = K())
- : m_k(k),
- m_intrinsic_dim(intrinsic_dimension),
- m_ambient_dim(points.empty() ? 0 : k.point_dimension_d_object()(*points.begin())),
- m_points(points.begin(), points.end()),
- m_weights(m_points.size(), FT(0))
-#if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
- ,
- m_p_perturb_mutexes(NULL)
-#endif
- ,
- m_points_ds(m_points),
- m_last_max_perturb(0.),
- m_are_tangent_spaces_computed(m_points.size(), false),
- m_tangent_spaces(m_points.size(), Tangent_space_basis())
-#ifdef GUDHI_TC_EXPORT_NORMALS
- ,
- m_orth_spaces(m_points.size(), Orthogonal_space_basis())
-#endif
-#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
- ,
- m_points_for_tse(first_for_tse, last_for_tse),
- m_points_ds_for_tse(m_points_for_tse)
-#endif
- {
- }
-
- /// Destructor
- ~Tangential_complex() {
-#if defined(GUDHI_USE_TBB) && defined(GUDHI_TC_PERTURB_POSITION)
- delete[] m_p_perturb_mutexes;
-#endif
- }
-
- /// Returns the intrinsic dimension of the manifold.
- int intrinsic_dimension() const { return m_intrinsic_dim; }
-
- /// Returns the ambient dimension.
- int ambient_dimension() const { return m_ambient_dim; }
-
- Points const &points() const { return m_points; }
-
- /** \brief Returns the point corresponding to the vertex given as parameter.
- *
- * @param[in] vertex Vertex handle of the point to retrieve.
- * @return The point found.
- */
- Point get_point(std::size_t vertex) const { return m_points[vertex]; }
-
- /** \brief Returns the perturbed position of the point corresponding to the vertex given as parameter.
- *
- * @param[in] vertex Vertex handle of the point to retrieve.
- * @return The perturbed position of the point found.
- */
- Point get_perturbed_point(std::size_t vertex) const { return compute_perturbed_point(vertex); }
-
- /// Returns the number of vertices.
-
- std::size_t number_of_vertices() const { return m_points.size(); }
-
- void set_weights(const Weights &weights) { m_weights = weights; }
-
- void set_tangent_planes(const TS_container &tangent_spaces
-#ifdef GUDHI_TC_EXPORT_NORMALS
- ,
- const OS_container &orthogonal_spaces
-#endif
- ) {
-#ifdef GUDHI_TC_EXPORT_NORMALS
- GUDHI_CHECK(m_points.size() == tangent_spaces.size() && m_points.size() == orthogonal_spaces.size(),
- std::logic_error("Wrong sizes"));
-#else
- GUDHI_CHECK(m_points.size() == tangent_spaces.size(), std::logic_error("Wrong sizes"));
-#endif
- m_tangent_spaces = tangent_spaces;
-#ifdef GUDHI_TC_EXPORT_NORMALS
- m_orth_spaces = orthogonal_spaces;
-#endif
- for (std::size_t i = 0; i < m_points.size(); ++i) m_are_tangent_spaces_computed[i] = true;
- }
-
- /// Computes the tangential complex.
- void compute_tangential_complex() {
-#ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
- std::cerr << red << "WARNING: GUDHI_TC_PERFORM_EXTRA_CHECKS is defined. "
- << "Computation might be slower than usual.\n"
- << white;
-#endif
-
-#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
- Gudhi::Clock t;
-#endif
-
- // We need to do that because we don't want the container to copy the
- // already-computed triangulations (while resizing) since it would
- // invalidate the vertex handles stored beside the triangulations
- m_triangulations.resize(m_points.size());
- m_stars.resize(m_points.size());
- m_squared_star_spheres_radii_incl_margin.resize(m_points.size(), FT(-1));
-#ifdef GUDHI_TC_PERTURB_POSITION
- if (m_points.empty())
- m_translations.clear();
- else
- m_translations.resize(m_points.size(), m_k.construct_vector_d_object()(m_ambient_dim));
-#if defined(GUDHI_USE_TBB)
- delete[] m_p_perturb_mutexes;
- m_p_perturb_mutexes = new Mutex_for_perturb[m_points.size()];
-#endif
-#endif
-
-#ifdef GUDHI_USE_TBB
- // Parallel
- if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
- tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*this));
- } else {
-#endif // GUDHI_USE_TBB
- // Sequential
- for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
-#ifdef GUDHI_USE_TBB
- }
-#endif // GUDHI_USE_TBB
-
-#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_USE_TBB)
- t.end();
- std::cerr << "Tangential complex computed in " << t.num_seconds() << " seconds.\n";
-#endif
- }
-
- /// \brief Type returned by `Tangential_complex::fix_inconsistencies_using_perturbation`.
- struct Fix_inconsistencies_info {
- /// `true` if all inconsistencies could be removed, `false` if the time limit has been reached before
- bool success = false;
- /// number of steps performed
- unsigned int num_steps = 0;
- /// initial number of inconsistent stars
- std::size_t initial_num_inconsistent_stars = 0;
- /// best number of inconsistent stars during the process
- std::size_t best_num_inconsistent_stars = 0;
- /// final number of inconsistent stars
- std::size_t final_num_inconsistent_stars = 0;
- };
-
- /** \brief Attempts to fix inconsistencies by perturbing the point positions.
- *
- * @param[in] max_perturb Maximum length of the translations used by the perturbation.
- * @param[in] time_limit Time limit in seconds. If -1, no time limit is set.
- */
- Fix_inconsistencies_info fix_inconsistencies_using_perturbation(double max_perturb, double time_limit = -1.) {
- Fix_inconsistencies_info info;
-
- if (time_limit == 0.) return info;
-
- Gudhi::Clock t;
-
-#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
- std::tuple<std::size_t, std::size_t, std::size_t> stats_before = number_of_inconsistent_simplices(false);
-
- if (std::get<1>(stats_before) == 0) {
-#ifdef DEBUG_TRACES
- std::cerr << "Nothing to fix.\n";
-#endif
- info.success = false;
- return info;
- }
-#endif // GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
-
- m_last_max_perturb = max_perturb;
-
- bool done = false;
- info.best_num_inconsistent_stars = m_triangulations.size();
- info.num_steps = 0;
- while (!done) {
-#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
- std::cerr << "\nBefore fix step:\n"
- << " * Total number of simplices in stars (incl. duplicates): " << std::get<0>(stats_before) << "\n"
- << " * Num inconsistent simplices in stars (incl. duplicates): " << red << std::get<1>(stats_before)
- << white << " (" << 100. * std::get<1>(stats_before) / std::get<0>(stats_before) << "%)\n"
- << " * Number of stars containing inconsistent simplices: " << red << std::get<2>(stats_before)
- << white << " (" << 100. * std::get<2>(stats_before) / m_points.size() << "%)\n";
-#endif
-
-#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
- std::cerr << yellow << "\nAttempt to fix inconsistencies using perturbations - step #" << info.num_steps + 1
- << "... " << white;
-#endif
-
- std::size_t num_inconsistent_stars = 0;
- std::vector<std::size_t> updated_points;
-
-#ifdef GUDHI_TC_PROFILING
- Gudhi::Clock t_fix_step;
-#endif
-
- // Parallel
-#if defined(GUDHI_USE_TBB)
- if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
- tbb::combinable<std::size_t> num_inconsistencies;
- tbb::combinable<std::vector<std::size_t> > tls_updated_points;
- tbb::parallel_for(tbb::blocked_range<size_t>(0, m_triangulations.size()),
- Try_to_solve_inconsistencies_in_a_local_triangulation(*this, max_perturb, num_inconsistencies,
- tls_updated_points));
- num_inconsistent_stars = num_inconsistencies.combine(std::plus<std::size_t>());
- updated_points =
- tls_updated_points.combine([](std::vector<std::size_t> const &x, std::vector<std::size_t> const &y) {
- std::vector<std::size_t> res;
- res.reserve(x.size() + y.size());
- res.insert(res.end(), x.begin(), x.end());
- res.insert(res.end(), y.begin(), y.end());
- return res;
- });
- } else {
-#endif // GUDHI_USE_TBB
- // Sequential
- for (std::size_t i = 0; i < m_triangulations.size(); ++i) {
- num_inconsistent_stars +=
- try_to_solve_inconsistencies_in_a_local_triangulation(i, max_perturb, std::back_inserter(updated_points));
- }
-#if defined(GUDHI_USE_TBB)
- }
-#endif // GUDHI_USE_TBB
-
-#ifdef GUDHI_TC_PROFILING
- t_fix_step.end();
-#endif
-
-#if defined(GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES) || defined(DEBUG_TRACES)
- std::cerr << "\nEncountered during fix:\n"
- << " * Num stars containing inconsistent simplices: " << red << num_inconsistent_stars << white << " ("
- << 100. * num_inconsistent_stars / m_points.size() << "%)\n";
-#endif
-
-#ifdef GUDHI_TC_PROFILING
- std::cerr << yellow << "done in " << t_fix_step.num_seconds() << " seconds.\n" << white;
-#elif defined(DEBUG_TRACES)
- std::cerr << yellow << "done.\n" << white;
-#endif
-
- if (num_inconsistent_stars > 0) refresh_tangential_complex(updated_points);
-
-#ifdef GUDHI_TC_PERFORM_EXTRA_CHECKS
- // Confirm that all stars were actually refreshed
- std::size_t num_inc_1 = std::get<1>(number_of_inconsistent_simplices(false));
- refresh_tangential_complex();
- std::size_t num_inc_2 = std::get<1>(number_of_inconsistent_simplices(false));
- if (num_inc_1 != num_inc_2)
- std::cerr << red << "REFRESHMENT CHECK: FAILED. (" << num_inc_1 << " vs " << num_inc_2 << ")\n" << white;
- else
- std::cerr << green << "REFRESHMENT CHECK: PASSED.\n" << white;
-#endif
-
-#ifdef GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
- std::tuple<std::size_t, std::size_t, std::size_t> stats_after = number_of_inconsistent_simplices(false);
-
- std::cerr << "\nAfter fix:\n"
- << " * Total number of simplices in stars (incl. duplicates): " << std::get<0>(stats_after) << "\n"
- << " * Num inconsistent simplices in stars (incl. duplicates): " << red << std::get<1>(stats_after)
- << white << " (" << 100. * std::get<1>(stats_after) / std::get<0>(stats_after) << "%)\n"
- << " * Number of stars containing inconsistent simplices: " << red << std::get<2>(stats_after) << white
- << " (" << 100. * std::get<2>(stats_after) / m_points.size() << "%)\n";
-
- stats_before = stats_after;
-#endif
-
- if (info.num_steps == 0) info.initial_num_inconsistent_stars = num_inconsistent_stars;
-
- if (num_inconsistent_stars < info.best_num_inconsistent_stars)
- info.best_num_inconsistent_stars = num_inconsistent_stars;
-
- info.final_num_inconsistent_stars = num_inconsistent_stars;
-
- done = (num_inconsistent_stars == 0);
- if (!done) {
- ++info.num_steps;
- if (time_limit > 0. && t.num_seconds() > time_limit) {
-#ifdef DEBUG_TRACES
- std::cerr << red << "Time limit reached.\n" << white;
-#endif
- info.success = false;
- return info;
- }
- }
- }
-
-#ifdef DEBUG_TRACES
- std::cerr << green << "Fixed!\n" << white;
-#endif
- info.success = true;
- return info;
- }
-
- /// \brief Type returned by `Tangential_complex::number_of_inconsistent_simplices`.
- struct Num_inconsistencies {
- /// Total number of simplices in stars (including duplicates that appear in several stars)
- std::size_t num_simplices = 0;
- /// Number of inconsistent simplices
- std::size_t num_inconsistent_simplices = 0;
- /// Number of stars containing at least one inconsistent simplex
- std::size_t num_inconsistent_stars = 0;
- };
-
- /// Returns the number of inconsistencies
- /// @param[in] verbose If true, outputs a message into `std::cerr`.
-
- Num_inconsistencies number_of_inconsistent_simplices(
-#ifdef DEBUG_TRACES
- bool verbose = true
-#else
- bool verbose = false
-#endif
- ) const {
- Num_inconsistencies stats;
-
- // For each triangulation
- for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
- bool is_star_inconsistent = false;
-
- // For each cell
- Star::const_iterator it_inc_simplex = m_stars[idx].begin();
- Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- // Don't check infinite cells
- if (is_infinite(*it_inc_simplex)) continue;
-
- Simplex c = *it_inc_simplex;
- c.insert(idx); // Add the missing index
-
- if (!is_simplex_consistent(c)) {
- ++stats.num_inconsistent_simplices;
- is_star_inconsistent = true;
- }
-
- ++stats.num_simplices;
- }
- stats.num_inconsistent_stars += is_star_inconsistent;
- }
-
- if (verbose) {
- std::cerr << "\n==========================================================\n"
- << "Inconsistencies:\n"
- << " * Total number of simplices in stars (incl. duplicates): " << stats.num_simplices << "\n"
- << " * Number of inconsistent simplices in stars (incl. duplicates): "
- << stats.num_inconsistent_simplices << " ("
- << 100. * stats.num_inconsistent_simplices / stats.num_simplices << "%)\n"
- << " * Number of stars containing inconsistent simplices: " << stats.num_inconsistent_stars << " ("
- << 100. * stats.num_inconsistent_stars / m_points.size() << "%)\n"
- << "==========================================================\n";
- }
-
- return stats;
- }
-
- /** \brief Exports the complex into a Simplex_tree.
- *
- * \tparam Simplex_tree_ must be a `Simplex_tree`.
- *
- * @param[out] tree The result, where each `Vertex_handle` is the index of the
- * corresponding point in the range provided to the constructor (it can also be
- * retrieved through the `Tangential_complex::get_point` function.
- * @param[in] export_inconsistent_simplices Also export inconsistent simplices or not?
- * @return The maximal dimension of the simplices.
- */
- template <typename Simplex_tree_>
- int create_complex(Simplex_tree_ &tree,
- bool export_inconsistent_simplices = true
- /// \cond ADVANCED_PARAMETERS
- ,
- bool export_infinite_simplices = false, Simplex_set *p_inconsistent_simplices = NULL
- /// \endcond
- ) const {
-#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
- std::cerr << yellow << "\nExporting the TC as a Simplex_tree... " << white;
-#endif
-#ifdef GUDHI_TC_PROFILING
- Gudhi::Clock t;
-#endif
-
- int max_dim = -1;
-
- // For each triangulation
- for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
- // For each cell of the star
- Star::const_iterator it_inc_simplex = m_stars[idx].begin();
- Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- Simplex c = *it_inc_simplex;
-
- // Don't export infinite cells
- if (!export_infinite_simplices && is_infinite(c)) continue;
-
- if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
-
- if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
- // Add the missing center vertex
- c.insert(idx);
-
- // Try to insert the simplex
- bool inserted = tree.insert_simplex_and_subfaces(c).second;
-
- // Inconsistent?
- if (p_inconsistent_simplices && inserted && !is_simplex_consistent(c)) {
- p_inconsistent_simplices->insert(c);
- }
- }
- }
-
-#ifdef GUDHI_TC_PROFILING
- t.end();
- std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
-#elif defined(DEBUG_TRACES)
- std::cerr << yellow << "done.\n" << white;
-#endif
-
- return max_dim;
- }
-
- // First clears the complex then exports the TC into it
- // Returns the max dimension of the simplices
- // check_lower_and_higher_dim_simplices : 0 (false), 1 (true), 2 (auto)
- // If the check is enabled, the function:
- // - won't insert the simplex if it is already in a higher dim simplex
- // - will erase any lower-dim simplices that are faces of the new simplex
- // "auto" (= 2) will enable the check as a soon as it encounters a
- // simplex whose dimension is different from the previous ones.
- // N.B.: The check is quite expensive.
-
- int create_complex(Simplicial_complex &complex, bool export_inconsistent_simplices = true,
- bool export_infinite_simplices = false, int check_lower_and_higher_dim_simplices = 2,
- Simplex_set *p_inconsistent_simplices = NULL) const {
-#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
- std::cerr << yellow << "\nExporting the TC as a Simplicial_complex... " << white;
-#endif
-#ifdef GUDHI_TC_PROFILING
- Gudhi::Clock t;
-#endif
-
- int max_dim = -1;
- complex.clear();
-
- // For each triangulation
- for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
- // For each cell of the star
- Star::const_iterator it_inc_simplex = m_stars[idx].begin();
- Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- Simplex c = *it_inc_simplex;
-
- // Don't export infinite cells
- if (!export_infinite_simplices && is_infinite(c)) continue;
-
- if (!export_inconsistent_simplices && !is_simplex_consistent(c)) continue;
-
- // Unusual simplex dim?
- if (check_lower_and_higher_dim_simplices == 2 && max_dim != -1 && static_cast<int>(c.size()) != max_dim) {
- // Let's activate the check
- std::cerr << red
- << "Info: check_lower_and_higher_dim_simplices ACTIVATED. "
- "Export might be take some time...\n"
- << white;
- check_lower_and_higher_dim_simplices = 1;
- }
-
- if (static_cast<int>(c.size()) > max_dim) max_dim = static_cast<int>(c.size());
- // Add the missing center vertex
- c.insert(idx);
-
- // Try to insert the simplex
- bool added = complex.add_simplex(c, check_lower_and_higher_dim_simplices == 1);
-
- // Inconsistent?
- if (p_inconsistent_simplices && added && !is_simplex_consistent(c)) {
- p_inconsistent_simplices->insert(c);
- }
- }
- }
-
-#ifdef GUDHI_TC_PROFILING
- t.end();
- std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
-#elif defined(DEBUG_TRACES)
- std::cerr << yellow << "done.\n" << white;
-#endif
-
- return max_dim;
- }
-
- template <typename ProjectionFunctor = CGAL::Identity<Point> >
- std::ostream &export_to_off(const Simplicial_complex &complex, std::ostream &os,
- Simplex_set const *p_simpl_to_color_in_red = NULL,
- Simplex_set const *p_simpl_to_color_in_green = NULL,
- Simplex_set const *p_simpl_to_color_in_blue = NULL,
- ProjectionFunctor const &point_projection = ProjectionFunctor()) const {
- return export_to_off(os, false, p_simpl_to_color_in_red, p_simpl_to_color_in_green, p_simpl_to_color_in_blue,
- &complex, point_projection);
- }
-
- template <typename ProjectionFunctor = CGAL::Identity<Point> >
- std::ostream &export_to_off(std::ostream &os, bool color_inconsistencies = false,
- Simplex_set const *p_simpl_to_color_in_red = NULL,
- Simplex_set const *p_simpl_to_color_in_green = NULL,
- Simplex_set const *p_simpl_to_color_in_blue = NULL,
- const Simplicial_complex *p_complex = NULL,
- ProjectionFunctor const &point_projection = ProjectionFunctor()) const {
- if (m_points.empty()) return os;
-
- if (m_ambient_dim < 2) {
- std::cerr << "Error: export_to_off => ambient dimension should be >= 2.\n";
- os << "Error: export_to_off => ambient dimension should be >= 2.\n";
- return os;
- }
- if (m_ambient_dim > 3) {
- std::cerr << "Warning: export_to_off => ambient dimension should be "
- "<= 3. Only the first 3 coordinates will be exported.\n";
- }
-
- if (m_intrinsic_dim < 1 || m_intrinsic_dim > 3) {
- std::cerr << "Error: export_to_off => intrinsic dimension should be "
- "between 1 and 3.\n";
- os << "Error: export_to_off => intrinsic dimension should be "
- "between 1 and 3.\n";
- return os;
- }
-
- std::stringstream output;
- std::size_t num_simplices, num_vertices;
- export_vertices_to_off(output, num_vertices, false, point_projection);
- if (p_complex) {
- export_simplices_to_off(*p_complex, output, num_simplices, p_simpl_to_color_in_red, p_simpl_to_color_in_green,
- p_simpl_to_color_in_blue);
- } else {
- export_simplices_to_off(output, num_simplices, color_inconsistencies, p_simpl_to_color_in_red,
- p_simpl_to_color_in_green, p_simpl_to_color_in_blue);
- }
-
-#ifdef GUDHI_TC_EXPORT_NORMALS
- os << "N";
-#endif
-
- os << "OFF \n"
- << num_vertices << " " << num_simplices << " "
- << "0 \n"
- << output.str();
-
- return os;
- }
-
- private:
- void refresh_tangential_complex() {
-#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
- std::cerr << yellow << "\nRefreshing TC... " << white;
-#endif
-
-#ifdef GUDHI_TC_PROFILING
- Gudhi::Clock t;
-#endif
-#ifdef GUDHI_USE_TBB
- // Parallel
- if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
- tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()), Compute_tangent_triangulation(*this));
- } else {
-#endif // GUDHI_USE_TBB
- // Sequential
- for (std::size_t i = 0; i < m_points.size(); ++i) compute_tangent_triangulation(i);
-#ifdef GUDHI_USE_TBB
- }
-#endif // GUDHI_USE_TBB
-
-#ifdef GUDHI_TC_PROFILING
- t.end();
- std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
-#elif defined(DEBUG_TRACES)
- std::cerr << yellow << "done.\n" << white;
-#endif
- }
-
- // If the list of perturbed points is provided, it is much faster
- template <typename Point_indices_range>
- void refresh_tangential_complex(Point_indices_range const &perturbed_points_indices) {
-#if defined(DEBUG_TRACES) || defined(GUDHI_TC_PROFILING)
- std::cerr << yellow << "\nRefreshing TC... " << white;
-#endif
-
-#ifdef GUDHI_TC_PROFILING
- Gudhi::Clock t;
-#endif
-
- // ANN tree containing only the perturbed points
- Points_ds updated_pts_ds(m_points, perturbed_points_indices);
-
-#ifdef GUDHI_USE_TBB
- // Parallel
- if (boost::is_convertible<Concurrency_tag, CGAL::Parallel_tag>::value) {
- tbb::parallel_for(tbb::blocked_range<size_t>(0, m_points.size()),
- Refresh_tangent_triangulation(*this, updated_pts_ds));
- } else {
-#endif // GUDHI_USE_TBB
- // Sequential
- for (std::size_t i = 0; i < m_points.size(); ++i) refresh_tangent_triangulation(i, updated_pts_ds);
-#ifdef GUDHI_USE_TBB
- }
-#endif // GUDHI_USE_TBB
-
-#ifdef GUDHI_TC_PROFILING
- t.end();
- std::cerr << yellow << "done in " << t.num_seconds() << " seconds.\n" << white;
-#elif defined(DEBUG_TRACES)
- std::cerr << yellow << "done.\n" << white;
-#endif
- }
-
- void export_inconsistent_stars_to_OFF_files(std::string const &filename_base) const {
- // For each triangulation
- for (std::size_t idx = 0; idx < m_points.size(); ++idx) {
- // We build a SC along the way in case it's inconsistent
- Simplicial_complex sc;
- // For each cell
- bool is_inconsistent = false;
- Star::const_iterator it_inc_simplex = m_stars[idx].begin();
- Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- // Skip infinite cells
- if (is_infinite(*it_inc_simplex)) continue;
-
- Simplex c = *it_inc_simplex;
- c.insert(idx); // Add the missing index
-
- sc.add_simplex(c);
-
- // If we do not already know this star is inconsistent, test it
- if (!is_inconsistent && !is_simplex_consistent(c)) is_inconsistent = true;
- }
-
- if (is_inconsistent) {
- // Export star to OFF file
- std::stringstream output_filename;
- output_filename << filename_base << "_" << idx << ".off";
- std::ofstream off_stream(output_filename.str().c_str());
- export_to_off(sc, off_stream);
- }
- }
- }
-
- class Compare_distance_to_ref_point {
- public:
- Compare_distance_to_ref_point(Point const &ref, K const &k) : m_ref(ref), m_k(k) {}
-
- bool operator()(Point const &p1, Point const &p2) {
- typename K::Squared_distance_d sqdist = m_k.squared_distance_d_object();
- return sqdist(p1, m_ref) < sqdist(p2, m_ref);
- }
-
- private:
- Point const &m_ref;
- K const &m_k;
- };
-
-#ifdef GUDHI_USE_TBB
- // Functor for compute_tangential_complex function
- class Compute_tangent_triangulation {
- Tangential_complex &m_tc;
-
- public:
- // Constructor
- Compute_tangent_triangulation(Tangential_complex &tc) : m_tc(tc) {}
-
- // Constructor
- Compute_tangent_triangulation(const Compute_tangent_triangulation &ctt) : m_tc(ctt.m_tc) {}
-
- // operator()
- void operator()(const tbb::blocked_range<size_t> &r) const {
- for (size_t i = r.begin(); i != r.end(); ++i) m_tc.compute_tangent_triangulation(i);
- }
- };
-
- // Functor for refresh_tangential_complex function
- class Refresh_tangent_triangulation {
- Tangential_complex &m_tc;
- Points_ds const &m_updated_pts_ds;
-
- public:
- // Constructor
- Refresh_tangent_triangulation(Tangential_complex &tc, Points_ds const &updated_pts_ds)
- : m_tc(tc), m_updated_pts_ds(updated_pts_ds) {}
-
- // Constructor
- Refresh_tangent_triangulation(const Refresh_tangent_triangulation &ctt)
- : m_tc(ctt.m_tc), m_updated_pts_ds(ctt.m_updated_pts_ds) {}
-
- // operator()
- void operator()(const tbb::blocked_range<size_t> &r) const {
- for (size_t i = r.begin(); i != r.end(); ++i) m_tc.refresh_tangent_triangulation(i, m_updated_pts_ds);
- }
- };
-#endif // GUDHI_USE_TBB
-
- bool is_infinite(Simplex const &s) const { return *s.rbegin() == (std::numeric_limits<std::size_t>::max)(); }
-
- // Output: "triangulation" is a Regular Triangulation containing at least the
- // star of "center_pt"
- // Returns the handle of the center vertex
- Tr_vertex_handle compute_star(std::size_t i, const Point &center_pt, const Tangent_space_basis &tsb,
- Triangulation &triangulation, bool verbose = false) {
- int tangent_space_dim = tsb.dimension();
- const Tr_traits &local_tr_traits = triangulation.geom_traits();
-
- // Kernel functor & objects
- typename K::Squared_distance_d k_sqdist = m_k.squared_distance_d_object();
-
- // Triangulation's traits functor & objects
- typename Tr_traits::Compute_weight_d point_weight = local_tr_traits.compute_weight_d_object();
- typename Tr_traits::Power_center_d power_center = local_tr_traits.power_center_d_object();
-
- //***************************************************
- // Build a minimal triangulation in the tangent space
- // (we only need the star of p)
- //***************************************************
-
- // Insert p
- Tr_point proj_wp;
- if (i == tsb.origin()) {
- // Insert {(0, 0, 0...), m_weights[i]}
- proj_wp = local_tr_traits.construct_weighted_point_d_object()(
- local_tr_traits.construct_point_d_object()(tangent_space_dim, CGAL::ORIGIN), m_weights[i]);
- } else {
- const Weighted_point &wp = compute_perturbed_weighted_point(i);
- proj_wp = project_point_and_compute_weight(wp, tsb, local_tr_traits);
- }
-
- Tr_vertex_handle center_vertex = triangulation.insert(proj_wp);
- center_vertex->data() = i;
- if (verbose) std::cerr << "* Inserted point #" << i << "\n";
-
-#ifdef GUDHI_TC_VERY_VERBOSE
- std::size_t num_attempts_to_insert_points = 1;
- std::size_t num_inserted_points = 1;
-#endif
- // const int NUM_NEIGHBORS = 150;
- // KNS_range ins_range = m_points_ds.k_nearest_neighbors(center_pt, NUM_NEIGHBORS);
- INS_range ins_range = m_points_ds.incremental_nearest_neighbors(center_pt);
-
- // While building the local triangulation, we keep the radius
- // of the sphere "star sphere" centered at "center_vertex"
- // and which contains all the
- // circumspheres of the star of "center_vertex"
- boost::optional<FT> squared_star_sphere_radius_plus_margin = boost::make_optional(false, FT());
- // This is the strange way boost is recommending to get rid of "may be used uninitialized in this function".
- // Former code was :
- // boost::optional<FT> squared_star_sphere_radius_plus_margin;
-
- // Insert points until we find a point which is outside "star sphere"
- for (auto nn_it = ins_range.begin(); nn_it != ins_range.end(); ++nn_it) {
- std::size_t neighbor_point_idx = nn_it->first;
-
- // ith point = p, which is already inserted
- if (neighbor_point_idx != i) {
- // No need to lock the Mutex_for_perturb here since this will not be
- // called while other threads are perturbing the positions
- Point neighbor_pt;
- FT neighbor_weight;
- compute_perturbed_weighted_point(neighbor_point_idx, neighbor_pt, neighbor_weight);
-
- if (squared_star_sphere_radius_plus_margin &&
- k_sqdist(center_pt, neighbor_pt) > *squared_star_sphere_radius_plus_margin)
- break;
-
- Tr_point proj_pt = project_point_and_compute_weight(neighbor_pt, neighbor_weight, tsb, local_tr_traits);
-
-#ifdef GUDHI_TC_VERY_VERBOSE
- ++num_attempts_to_insert_points;
-#endif
-
- Tr_vertex_handle vh = triangulation.insert_if_in_star(proj_pt, center_vertex);
- // Tr_vertex_handle vh = triangulation.insert(proj_pt);
- if (vh != Tr_vertex_handle() && vh->data() == (std::numeric_limits<std::size_t>::max)()) {
-#ifdef GUDHI_TC_VERY_VERBOSE
- ++num_inserted_points;
-#endif
- if (verbose) std::cerr << "* Inserted point #" << neighbor_point_idx << "\n";
-
- vh->data() = neighbor_point_idx;
-
- // Let's recompute squared_star_sphere_radius_plus_margin
- if (triangulation.current_dimension() >= tangent_space_dim) {
- squared_star_sphere_radius_plus_margin = boost::none;
- // Get the incident cells and look for the biggest circumsphere
- std::vector<Tr_full_cell_handle> incident_cells;
- triangulation.incident_full_cells(center_vertex, std::back_inserter(incident_cells));
- for (typename std::vector<Tr_full_cell_handle>::iterator cit = incident_cells.begin();
- cit != incident_cells.end(); ++cit) {
- Tr_full_cell_handle cell = *cit;
- if (triangulation.is_infinite(cell)) {
- squared_star_sphere_radius_plus_margin = boost::none;
- break;
- } else {
- // Note that this uses the perturbed point since it uses
- // the points of the local triangulation
- Tr_point c =
- power_center(boost::make_transform_iterator(cell->vertices_begin(),
- vertex_handle_to_point<Tr_point, Tr_vertex_handle>),
- boost::make_transform_iterator(cell->vertices_end(),
- vertex_handle_to_point<Tr_point, Tr_vertex_handle>));
-
- FT sq_power_sphere_diam = 4 * point_weight(c);
-
- if (!squared_star_sphere_radius_plus_margin ||
- sq_power_sphere_diam > *squared_star_sphere_radius_plus_margin) {
- squared_star_sphere_radius_plus_margin = sq_power_sphere_diam;
- }
- }
- }
-
- // Let's add the margin, now
- // The value depends on whether we perturb weight or position
- if (squared_star_sphere_radius_plus_margin) {
- // "2*m_last_max_perturb" because both points can be perturbed
- squared_star_sphere_radius_plus_margin =
- CGAL::square(std::sqrt(*squared_star_sphere_radius_plus_margin) + 2 * m_last_max_perturb);
-
- // Save it in `m_squared_star_spheres_radii_incl_margin`
- m_squared_star_spheres_radii_incl_margin[i] = *squared_star_sphere_radius_plus_margin;
- } else {
- m_squared_star_spheres_radii_incl_margin[i] = FT(-1);
- }
- }
- }
- }
- }
-
- return center_vertex;
- }
-
- void refresh_tangent_triangulation(std::size_t i, Points_ds const &updated_pts_ds, bool verbose = false) {
- if (verbose) std::cerr << "** Refreshing tangent tri #" << i << " **\n";
-
- if (m_squared_star_spheres_radii_incl_margin[i] == FT(-1)) return compute_tangent_triangulation(i, verbose);
-
- Point center_point = compute_perturbed_point(i);
- // Among updated point, what is the closer from our center point?
- std::size_t closest_pt_index = updated_pts_ds.k_nearest_neighbors(center_point, 1, false).begin()->first;
-
- typename K::Construct_weighted_point_d k_constr_wp = m_k.construct_weighted_point_d_object();
- typename K::Power_distance_d k_power_dist = m_k.power_distance_d_object();
-
- // Construct a weighted point equivalent to the star sphere
- Weighted_point star_sphere = k_constr_wp(compute_perturbed_point(i), m_squared_star_spheres_radii_incl_margin[i]);
- Weighted_point closest_updated_point = compute_perturbed_weighted_point(closest_pt_index);
-
- // Is the "closest point" inside our star sphere?
- if (k_power_dist(star_sphere, closest_updated_point) <= FT(0)) compute_tangent_triangulation(i, verbose);
- }
-
- void compute_tangent_triangulation(std::size_t i, bool verbose = false) {
- if (verbose) std::cerr << "** Computing tangent tri #" << i << " **\n";
- // std::cerr << "***********************************************\n";
-
- // No need to lock the mutex here since this will not be called while
- // other threads are perturbing the positions
- const Point center_pt = compute_perturbed_point(i);
- Tangent_space_basis &tsb = m_tangent_spaces[i];
-
- // Estimate the tangent space
- if (!m_are_tangent_spaces_computed[i]) {
-#ifdef GUDHI_TC_EXPORT_NORMALS
- tsb = compute_tangent_space(center_pt, i, true /*normalize*/, &m_orth_spaces[i]);
-#else
- tsb = compute_tangent_space(center_pt, i);
-#endif
- }
-
-#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
- Gudhi::Clock t;
-#endif
- int tangent_space_dim = tangent_basis_dim(i);
- Triangulation &local_tr = m_triangulations[i].construct_triangulation(tangent_space_dim);
-
- m_triangulations[i].center_vertex() = compute_star(i, center_pt, tsb, local_tr, verbose);
-
-#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
- t.end();
- std::cerr << " - triangulation construction: " << t.num_seconds() << " s.\n";
- t.reset();
-#endif
-
-#ifdef GUDHI_TC_VERY_VERBOSE
- std::cerr << "Inserted " << num_inserted_points << " points / " << num_attempts_to_insert_points
- << " attemps to compute the star\n";
-#endif
-
- update_star(i);
-
-#if defined(GUDHI_TC_PROFILING) && defined(GUDHI_TC_VERY_VERBOSE)
- t.end();
- std::cerr << " - update_star: " << t.num_seconds() << " s.\n";
-#endif
- }
-
- // Updates m_stars[i] directly from m_triangulations[i]
-
- void update_star(std::size_t i) {
- Star &star = m_stars[i];
- star.clear();
- Triangulation &local_tr = m_triangulations[i].tr();
- Tr_vertex_handle center_vertex = m_triangulations[i].center_vertex();
- int cur_dim_plus_1 = local_tr.current_dimension() + 1;
-
- std::vector<Tr_full_cell_handle> incident_cells;
- local_tr.incident_full_cells(center_vertex, std::back_inserter(incident_cells));
-
- typename std::vector<Tr_full_cell_handle>::const_iterator it_c = incident_cells.begin();
- typename std::vector<Tr_full_cell_handle>::const_iterator it_c_end = incident_cells.end();
- // For each cell
- for (; it_c != it_c_end; ++it_c) {
- // Will contain all indices except center_vertex
- Incident_simplex incident_simplex;
- for (int j = 0; j < cur_dim_plus_1; ++j) {
- std::size_t index = (*it_c)->vertex(j)->data();
- if (index != i) incident_simplex.insert(index);
- }
- GUDHI_CHECK(incident_simplex.size() == cur_dim_plus_1 - 1,
- std::logic_error("update_star: wrong size of incident simplex"));
- star.push_back(incident_simplex);
- }
- }
-
- // Estimates tangent subspaces using PCA
-
- Tangent_space_basis compute_tangent_space(const Point &p, const std::size_t i, bool normalize_basis = true,
- Orthogonal_space_basis *p_orth_space_basis = NULL) {
- unsigned int num_pts_for_pca =
- (std::min)(static_cast<unsigned int>(std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
- static_cast<unsigned int>(m_points.size()));
-
- // Kernel functors
- typename K::Construct_vector_d constr_vec = m_k.construct_vector_d_object();
- typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
-
-#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
- KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false);
- const Points &points_for_pca = m_points_for_tse;
-#else
- KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false);
- const Points &points_for_pca = m_points;
-#endif
-
- // One row = one point
- Eigen::MatrixXd mat_points(num_pts_for_pca, m_ambient_dim);
- auto nn_it = kns_range.begin();
- for (unsigned int j = 0; j < num_pts_for_pca && nn_it != kns_range.end(); ++j, ++nn_it) {
- for (int i = 0; i < m_ambient_dim; ++i) {
- mat_points(j, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i));
- }
- }
- Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
- Eigen::MatrixXd cov = centered.adjoint() * centered;
- Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
-
- Tangent_space_basis tsb(i); // p = compute_perturbed_point(i) here
-
- // The eigenvectors are sorted in increasing order of their corresponding
- // eigenvalues
- for (int j = m_ambient_dim - 1; j >= m_ambient_dim - m_intrinsic_dim; --j) {
- if (normalize_basis) {
- Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim);
- tsb.push_back(normalize_vector(v, m_k));
- } else {
- tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim));
- }
- }
-
- if (p_orth_space_basis) {
- p_orth_space_basis->set_origin(i);
- for (int j = m_ambient_dim - m_intrinsic_dim - 1; j >= 0; --j) {
- if (normalize_basis) {
- Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim);
- p_orth_space_basis->push_back(normalize_vector(v, m_k));
- } else {
- p_orth_space_basis->push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim));
- }
- }
- }
-
- m_are_tangent_spaces_computed[i] = true;
-
- return tsb;
- }
-
- // Compute the space tangent to a simplex (p1, p2, ... pn)
- // TODO(CJ): Improve this?
- // Basically, it takes all the neighbor points to p1, p2... pn and runs PCA
- // on it. Note that most points are duplicated.
-
- Tangent_space_basis compute_tangent_space(const Simplex &s, bool normalize_basis = true) {
- unsigned int num_pts_for_pca =
- (std::min)(static_cast<unsigned int>(std::pow(GUDHI_TC_BASE_VALUE_FOR_PCA, m_intrinsic_dim)),
- static_cast<unsigned int>(m_points.size()));
-
- // Kernel functors
- typename K::Construct_vector_d constr_vec = m_k.construct_vector_d_object();
- typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
- typename K::Squared_length_d sqlen = m_k.squared_length_d_object();
- typename K::Scaled_vector_d scaled_vec = m_k.scaled_vector_d_object();
- typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
- typename K::Difference_of_vectors_d diff_vec = m_k.difference_of_vectors_d_object();
-
- // One row = one point
- Eigen::MatrixXd mat_points(s.size() * num_pts_for_pca, m_ambient_dim);
- unsigned int current_row = 0;
-
- for (Simplex::const_iterator it_index = s.begin(); it_index != s.end(); ++it_index) {
- const Point &p = m_points[*it_index];
-
-#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
- KNS_range kns_range = m_points_ds_for_tse.k_nearest_neighbors(p, num_pts_for_pca, false);
- const Points &points_for_pca = m_points_for_tse;
-#else
- KNS_range kns_range = m_points_ds.k_nearest_neighbors(p, num_pts_for_pca, false);
- const Points &points_for_pca = m_points;
-#endif
-
- auto nn_it = kns_range.begin();
- for (; current_row < num_pts_for_pca && nn_it != kns_range.end(); ++current_row, ++nn_it) {
- for (int i = 0; i < m_ambient_dim; ++i) {
- mat_points(current_row, i) = CGAL::to_double(coord(points_for_pca[nn_it->first], i));
- }
- }
- }
- Eigen::MatrixXd centered = mat_points.rowwise() - mat_points.colwise().mean();
- Eigen::MatrixXd cov = centered.adjoint() * centered;
- Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eig(cov);
-
- Tangent_space_basis tsb;
-
- // The eigenvectors are sorted in increasing order of their corresponding
- // eigenvalues
- for (int j = m_ambient_dim - 1; j >= m_ambient_dim - m_intrinsic_dim; --j) {
- if (normalize_basis) {
- Vector v = constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim);
- tsb.push_back(normalize_vector(v, m_k));
- } else {
- tsb.push_back(constr_vec(m_ambient_dim, eig.eigenvectors().col(j).data(),
- eig.eigenvectors().col(j).data() + m_ambient_dim));
- }
- }
-
- return tsb;
- }
-
- // Returns the dimension of the ith local triangulation
-
- int tangent_basis_dim(std::size_t i) const { return m_tangent_spaces[i].dimension(); }
-
- Point compute_perturbed_point(std::size_t pt_idx) const {
-#ifdef GUDHI_TC_PERTURB_POSITION
- return m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]);
-#else
- return m_points[pt_idx];
-#endif
- }
-
- void compute_perturbed_weighted_point(std::size_t pt_idx, Point &p, FT &w) const {
-#ifdef GUDHI_TC_PERTURB_POSITION
- p = m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]);
-#else
- p = m_points[pt_idx];
-#endif
- w = m_weights[pt_idx];
- }
-
- Weighted_point compute_perturbed_weighted_point(std::size_t pt_idx) const {
- typename K::Construct_weighted_point_d k_constr_wp = m_k.construct_weighted_point_d_object();
-
- Weighted_point wp = k_constr_wp(
-#ifdef GUDHI_TC_PERTURB_POSITION
- m_k.translated_point_d_object()(m_points[pt_idx], m_translations[pt_idx]),
-#else
- m_points[pt_idx],
-#endif
- m_weights[pt_idx]);
-
- return wp;
- }
-
- Point unproject_point(const Tr_point &p, const Tangent_space_basis &tsb, const Tr_traits &tr_traits) const {
- typename K::Translated_point_d k_transl = m_k.translated_point_d_object();
- typename K::Scaled_vector_d k_scaled_vec = m_k.scaled_vector_d_object();
- typename Tr_traits::Compute_coordinate_d coord = tr_traits.compute_coordinate_d_object();
-
- Point global_point = compute_perturbed_point(tsb.origin());
- for (int i = 0; i < m_intrinsic_dim; ++i) global_point = k_transl(global_point, k_scaled_vec(tsb[i], coord(p, i)));
-
- return global_point;
- }
-
- // Project the point in the tangent space
- // Resulting point coords are expressed in tsb's space
- Tr_bare_point project_point(const Point &p, const Tangent_space_basis &tsb, const Tr_traits &tr_traits) const {
- typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
- typename K::Difference_of_points_d diff_points = m_k.difference_of_points_d_object();
-
- Vector v = diff_points(p, compute_perturbed_point(tsb.origin()));
-
- std::vector<FT> coords;
- // Ambiant-space coords of the projected point
- coords.reserve(tsb.dimension());
- for (std::size_t i = 0; i < m_intrinsic_dim; ++i) {
- // Local coords are given by the scalar product with the vectors of tsb
- FT coord = scalar_pdct(v, tsb[i]);
- coords.push_back(coord);
- }
-
- return tr_traits.construct_point_d_object()(static_cast<int>(coords.size()), coords.begin(), coords.end());
- }
-
- // Project the point in the tangent space
- // The weight will be the squared distance between p and the projection of p
- // Resulting point coords are expressed in tsb's space
-
- Tr_point project_point_and_compute_weight(const Weighted_point &wp, const Tangent_space_basis &tsb,
- const Tr_traits &tr_traits) const {
- typename K::Point_drop_weight_d k_drop_w = m_k.point_drop_weight_d_object();
- typename K::Compute_weight_d k_point_weight = m_k.compute_weight_d_object();
- return project_point_and_compute_weight(k_drop_w(wp), k_point_weight(wp), tsb, tr_traits);
- }
-
- // Same as above, with slightly different parameters
- Tr_point project_point_and_compute_weight(const Point &p, const FT w, const Tangent_space_basis &tsb,
- const Tr_traits &tr_traits) const {
- const int point_dim = m_k.point_dimension_d_object()(p);
-
- typename K::Construct_point_d constr_pt = m_k.construct_point_d_object();
- typename K::Scalar_product_d scalar_pdct = m_k.scalar_product_d_object();
- typename K::Difference_of_points_d diff_points = m_k.difference_of_points_d_object();
- typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
- typename K::Construct_cartesian_const_iterator_d ccci = m_k.construct_cartesian_const_iterator_d_object();
-
- Point origin = compute_perturbed_point(tsb.origin());
- Vector v = diff_points(p, origin);
-
- // Same dimension? Then the weight is 0
- bool same_dim = (point_dim == tsb.dimension());
-
- std::vector<FT> coords;
- // Ambiant-space coords of the projected point
- std::vector<FT> p_proj(ccci(origin), ccci(origin, 0));
- coords.reserve(tsb.dimension());
- for (int i = 0; i < tsb.dimension(); ++i) {
- // Local coords are given by the scalar product with the vectors of tsb
- FT c = scalar_pdct(v, tsb[i]);
- coords.push_back(c);
-
- // p_proj += c * tsb[i]
- if (!same_dim) {
- for (int j = 0; j < point_dim; ++j) p_proj[j] += c * coord(tsb[i], j);
- }
- }
-
- // Same dimension? Then the weight is 0
- FT sq_dist_to_proj_pt = 0;
- if (!same_dim) {
- Point projected_pt = constr_pt(point_dim, p_proj.begin(), p_proj.end());
- sq_dist_to_proj_pt = m_k.squared_distance_d_object()(p, projected_pt);
- }
-
- return tr_traits.construct_weighted_point_d_object()(
- tr_traits.construct_point_d_object()(static_cast<int>(coords.size()), coords.begin(), coords.end()),
- w - sq_dist_to_proj_pt);
- }
-
- // Project all the points in the tangent space
-
- template <typename Indexed_point_range>
- std::vector<Tr_point> project_points_and_compute_weights(const Indexed_point_range &point_indices,
- const Tangent_space_basis &tsb,
- const Tr_traits &tr_traits) const {
- std::vector<Tr_point> ret;
- for (typename Indexed_point_range::const_iterator it = point_indices.begin(), it_end = point_indices.end();
- it != it_end; ++it) {
- ret.push_back(project_point_and_compute_weight(compute_perturbed_weighted_point(*it), tsb, tr_traits));
- }
- return ret;
- }
-
- // A simplex here is a local tri's full cell handle
-
- bool is_simplex_consistent(Tr_full_cell_handle fch, int cur_dim) const {
- Simplex c;
- for (int i = 0; i < cur_dim + 1; ++i) {
- std::size_t data = fch->vertex(i)->data();
- c.insert(data);
- }
- return is_simplex_consistent(c);
- }
-
- // A simplex here is a list of point indices
- // TODO(CJ): improve it like the other "is_simplex_consistent" below
-
- bool is_simplex_consistent(Simplex const &simplex) const {
- // Check if the simplex is in the stars of all its vertices
- Simplex::const_iterator it_point_idx = simplex.begin();
- // For each point p of the simplex, we parse the incidents cells of p
- // and we check if "simplex" is among them
- for (; it_point_idx != simplex.end(); ++it_point_idx) {
- std::size_t point_idx = *it_point_idx;
- // Don't check infinite simplices
- if (point_idx == (std::numeric_limits<std::size_t>::max)()) continue;
-
- Star const &star = m_stars[point_idx];
-
- // What we're looking for is "simplex" \ point_idx
- Incident_simplex is_to_find = simplex;
- is_to_find.erase(point_idx);
-
- // For each cell
- if (std::find(star.begin(), star.end(), is_to_find) == star.end()) return false;
- }
-
- return true;
- }
-
- // A simplex here is a list of point indices
- // "s" contains all the points of the simplex except "center_point"
- // This function returns the points whose star doesn't contain the simplex
- // N.B.: the function assumes that the simplex is contained in
- // star(center_point)
-
- template <typename OutputIterator> // value_type = std::size_t
- bool is_simplex_consistent(std::size_t center_point,
- Incident_simplex const &s, // without "center_point"
- OutputIterator points_whose_star_does_not_contain_s,
- bool check_also_in_non_maximal_faces = false) const {
- Simplex full_simplex = s;
- full_simplex.insert(center_point);
-
- // Check if the simplex is in the stars of all its vertices
- Incident_simplex::const_iterator it_point_idx = s.begin();
- // For each point p of the simplex, we parse the incidents cells of p
- // and we check if "simplex" is among them
- for (; it_point_idx != s.end(); ++it_point_idx) {
- std::size_t point_idx = *it_point_idx;
- // Don't check infinite simplices
- if (point_idx == (std::numeric_limits<std::size_t>::max)()) continue;
-
- Star const &star = m_stars[point_idx];
-
- // What we're looking for is full_simplex \ point_idx
- Incident_simplex is_to_find = full_simplex;
- is_to_find.erase(point_idx);
-
- if (check_also_in_non_maximal_faces) {
- // For each simplex "is" of the star, check if ic_to_simplex is
- // included in "is"
- bool found = false;
- for (Star::const_iterator is = star.begin(), is_end = star.end(); !found && is != is_end; ++is) {
- if (std::includes(is->begin(), is->end(), is_to_find.begin(), is_to_find.end())) found = true;
- }
-
- if (!found) *points_whose_star_does_not_contain_s++ = point_idx;
- } else {
- // Does the star contain is_to_find?
- if (std::find(star.begin(), star.end(), is_to_find) == star.end())
- *points_whose_star_does_not_contain_s++ = point_idx;
- }
- }
-
- return true;
- }
-
- // A simplex here is a list of point indices
- // It looks for s in star(p).
- // "s" contains all the points of the simplex except p.
- bool is_simplex_in_star(std::size_t p, Incident_simplex const &s, bool check_also_in_non_maximal_faces = true) const {
- Star const &star = m_stars[p];
-
- if (check_also_in_non_maximal_faces) {
- // For each simplex "is" of the star, check if ic_to_simplex is
- // included in "is"
- bool found = false;
- for (Star::const_iterator is = star.begin(), is_end = star.end(); !found && is != is_end; ++is) {
- if (std::includes(is->begin(), is->end(), s.begin(), s.end())) found = true;
- }
-
- return found;
- } else {
- return !(std::find(star.begin(), star.end(), s) == star.end());
- }
- }
-
-#ifdef GUDHI_USE_TBB
- // Functor for try_to_solve_inconsistencies_in_a_local_triangulation function
- class Try_to_solve_inconsistencies_in_a_local_triangulation {
- Tangential_complex &m_tc;
- double m_max_perturb;
- tbb::combinable<std::size_t> &m_num_inconsistencies;
- tbb::combinable<std::vector<std::size_t> > &m_updated_points;
-
- public:
- // Constructor
- Try_to_solve_inconsistencies_in_a_local_triangulation(Tangential_complex &tc, double max_perturb,
- tbb::combinable<std::size_t> &num_inconsistencies,
- tbb::combinable<std::vector<std::size_t> > &updated_points)
- : m_tc(tc),
- m_max_perturb(max_perturb),
- m_num_inconsistencies(num_inconsistencies),
- m_updated_points(updated_points) {}
-
- // Constructor
- Try_to_solve_inconsistencies_in_a_local_triangulation(
- const Try_to_solve_inconsistencies_in_a_local_triangulation &tsilt)
- : m_tc(tsilt.m_tc),
- m_max_perturb(tsilt.m_max_perturb),
- m_num_inconsistencies(tsilt.m_num_inconsistencies),
- m_updated_points(tsilt.m_updated_points) {}
-
- // operator()
- void operator()(const tbb::blocked_range<size_t> &r) const {
- for (size_t i = r.begin(); i != r.end(); ++i) {
- m_num_inconsistencies.local() += m_tc.try_to_solve_inconsistencies_in_a_local_triangulation(
- i, m_max_perturb, std::back_inserter(m_updated_points.local()));
- }
- }
- };
-#endif // GUDHI_USE_TBB
-
- void perturb(std::size_t point_idx, double max_perturb) {
- const Tr_traits &local_tr_traits = m_triangulations[point_idx].tr().geom_traits();
- typename Tr_traits::Compute_coordinate_d coord = local_tr_traits.compute_coordinate_d_object();
- typename K::Translated_point_d k_transl = m_k.translated_point_d_object();
- typename K::Construct_vector_d k_constr_vec = m_k.construct_vector_d_object();
- typename K::Scaled_vector_d k_scaled_vec = m_k.scaled_vector_d_object();
-
- CGAL::Random_points_in_ball_d<Tr_bare_point> tr_point_in_ball_generator(
- m_intrinsic_dim, m_random_generator.get_double(0., max_perturb));
-
- Tr_point local_random_transl =
- local_tr_traits.construct_weighted_point_d_object()(*tr_point_in_ball_generator++, 0);
- Translation_for_perturb global_transl = k_constr_vec(m_ambient_dim);
- const Tangent_space_basis &tsb = m_tangent_spaces[point_idx];
- for (int i = 0; i < m_intrinsic_dim; ++i) {
- global_transl = k_transl(global_transl, k_scaled_vec(tsb[i], coord(local_random_transl, i)));
- }
- // Parallel
-#if defined(GUDHI_USE_TBB)
- m_p_perturb_mutexes[point_idx].lock();
- m_translations[point_idx] = global_transl;
- m_p_perturb_mutexes[point_idx].unlock();
- // Sequential
-#else
- m_translations[point_idx] = global_transl;
-#endif
- }
-
- // Return true if inconsistencies were found
- template <typename OutputIt>
- bool try_to_solve_inconsistencies_in_a_local_triangulation(
- std::size_t tr_index, double max_perturb, OutputIt perturbed_pts_indices = CGAL::Emptyset_iterator()) {
- bool is_inconsistent = false;
-
- Star const &star = m_stars[tr_index];
-
- // For each incident simplex
- Star::const_iterator it_inc_simplex = star.begin();
- Star::const_iterator it_inc_simplex_end = star.end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- const Incident_simplex &incident_simplex = *it_inc_simplex;
-
- // Don't check infinite cells
- if (is_infinite(incident_simplex)) continue;
-
- Simplex c = incident_simplex;
- c.insert(tr_index); // Add the missing index
-
- // Perturb the center point
- if (!is_simplex_consistent(c)) {
- is_inconsistent = true;
-
- std::size_t idx = tr_index;
-
- perturb(tr_index, max_perturb);
- *perturbed_pts_indices++ = idx;
-
- // We will try the other cells next time
- break;
- }
- }
-
- return is_inconsistent;
- }
-
- // 1st line: number of points
- // Then one point per line
- std::ostream &export_point_set(std::ostream &os, bool use_perturbed_points = false,
- const char *coord_separator = " ") const {
- if (use_perturbed_points) {
- std::vector<Point> perturbed_points;
- perturbed_points.reserve(m_points.size());
- for (std::size_t i = 0; i < m_points.size(); ++i) perturbed_points.push_back(compute_perturbed_point(i));
-
- return export_point_set(m_k, perturbed_points, os, coord_separator);
- } else {
- return export_point_set(m_k, m_points, os, coord_separator);
- }
- }
-
- template <typename ProjectionFunctor = CGAL::Identity<Point> >
- std::ostream &export_vertices_to_off(std::ostream &os, std::size_t &num_vertices, bool use_perturbed_points = false,
- ProjectionFunctor const &point_projection = ProjectionFunctor()) const {
- if (m_points.empty()) {
- num_vertices = 0;
- return os;
- }
-
- // If m_intrinsic_dim = 1, we output each point two times
- // to be able to export each segment as a flat triangle with 3 different
- // indices (otherwise, Meshlab detects degenerated simplices)
- const int N = (m_intrinsic_dim == 1 ? 2 : 1);
-
- // Kernel functors
- typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
-
-#ifdef GUDHI_TC_EXPORT_ALL_COORDS_IN_OFF
- int num_coords = m_ambient_dim;
-#else
- int num_coords = (std::min)(m_ambient_dim, 3);
-#endif
-
-#ifdef GUDHI_TC_EXPORT_NORMALS
- OS_container::const_iterator it_os = m_orth_spaces.begin();
-#endif
- typename Points::const_iterator it_p = m_points.begin();
- typename Points::const_iterator it_p_end = m_points.end();
- // For each point p
- for (std::size_t i = 0; it_p != it_p_end; ++it_p, ++i) {
- Point p = point_projection(use_perturbed_points ? compute_perturbed_point(i) : *it_p);
- for (int ii = 0; ii < N; ++ii) {
- int j = 0;
- for (; j < num_coords; ++j) os << CGAL::to_double(coord(p, j)) << " ";
- if (j == 2) os << "0";
-
-#ifdef GUDHI_TC_EXPORT_NORMALS
- for (j = 0; j < num_coords; ++j) os << " " << CGAL::to_double(coord(*it_os->begin(), j));
-#endif
- os << "\n";
- }
-#ifdef GUDHI_TC_EXPORT_NORMALS
- ++it_os;
-#endif
- }
-
- num_vertices = N * m_points.size();
- return os;
- }
-
- std::ostream &export_simplices_to_off(std::ostream &os, std::size_t &num_OFF_simplices,
- bool color_inconsistencies = false,
- Simplex_set const *p_simpl_to_color_in_red = NULL,
- Simplex_set const *p_simpl_to_color_in_green = NULL,
- Simplex_set const *p_simpl_to_color_in_blue = NULL) const {
- // If m_intrinsic_dim = 1, each point is output two times
- // (see export_vertices_to_off)
- num_OFF_simplices = 0;
- std::size_t num_maximal_simplices = 0;
- std::size_t num_inconsistent_maximal_simplices = 0;
- std::size_t num_inconsistent_stars = 0;
- typename Tr_container::const_iterator it_tr = m_triangulations.begin();
- typename Tr_container::const_iterator it_tr_end = m_triangulations.end();
- // For each triangulation
- for (std::size_t idx = 0; it_tr != it_tr_end; ++it_tr, ++idx) {
- bool is_star_inconsistent = false;
-
- Triangulation const &tr = it_tr->tr();
-
- if (tr.current_dimension() < m_intrinsic_dim) continue;
-
- // Color for this star
- std::stringstream color;
- // color << rand()%256 << " " << 100+rand()%156 << " " << 100+rand()%156;
- color << 128 << " " << 128 << " " << 128;
-
- // Gather the triangles here, with an int telling its color
- typedef std::vector<std::pair<Simplex, int> > Star_using_triangles;
- Star_using_triangles star_using_triangles;
-
- // For each cell of the star
- Star::const_iterator it_inc_simplex = m_stars[idx].begin();
- Star::const_iterator it_inc_simplex_end = m_stars[idx].end();
- for (; it_inc_simplex != it_inc_simplex_end; ++it_inc_simplex) {
- Simplex c = *it_inc_simplex;
- c.insert(idx);
- std::size_t num_vertices = c.size();
- ++num_maximal_simplices;
-
- int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
- if (color_inconsistencies && !is_simplex_consistent(c)) {
- ++num_inconsistent_maximal_simplices;
- color_simplex = 0;
- is_star_inconsistent = true;
- } else {
- if (p_simpl_to_color_in_red && std::find(p_simpl_to_color_in_red->begin(), p_simpl_to_color_in_red->end(),
- c) != p_simpl_to_color_in_red->end()) {
- color_simplex = 1;
- } else if (p_simpl_to_color_in_green &&
- std::find(p_simpl_to_color_in_green->begin(), p_simpl_to_color_in_green->end(), c) !=
- p_simpl_to_color_in_green->end()) {
- color_simplex = 2;
- } else if (p_simpl_to_color_in_blue &&
- std::find(p_simpl_to_color_in_blue->begin(), p_simpl_to_color_in_blue->end(), c) !=
- p_simpl_to_color_in_blue->end()) {
- color_simplex = 3;
- }
- }
-
- // If m_intrinsic_dim = 1, each point is output two times,
- // so we need to multiply each index by 2
- // And if only 2 vertices, add a third one (each vertex is duplicated in
- // the file when m_intrinsic dim = 2)
- if (m_intrinsic_dim == 1) {
- Simplex tmp_c;
- Simplex::iterator it = c.begin();
- for (; it != c.end(); ++it) tmp_c.insert(*it * 2);
- if (num_vertices == 2) tmp_c.insert(*tmp_c.rbegin() + 1);
-
- c = tmp_c;
- }
-
- if (num_vertices <= 3) {
- star_using_triangles.push_back(std::make_pair(c, color_simplex));
- } else {
- // num_vertices >= 4: decompose the simplex in triangles
- std::vector<bool> booleans(num_vertices, false);
- std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
- do {
- Simplex triangle;
- Simplex::iterator it = c.begin();
- for (int i = 0; it != c.end(); ++i, ++it) {
- if (booleans[i]) triangle.insert(*it);
- }
- star_using_triangles.push_back(std::make_pair(triangle, color_simplex));
- } while (std::next_permutation(booleans.begin(), booleans.end()));
- }
- }
-
- // For each cell
- Star_using_triangles::const_iterator it_simplex = star_using_triangles.begin();
- Star_using_triangles::const_iterator it_simplex_end = star_using_triangles.end();
- for (; it_simplex != it_simplex_end; ++it_simplex) {
- const Simplex &c = it_simplex->first;
-
- // Don't export infinite cells
- if (is_infinite(c)) continue;
-
- int color_simplex = it_simplex->second;
-
- std::stringstream sstr_c;
-
- Simplex::const_iterator it_point_idx = c.begin();
- for (; it_point_idx != c.end(); ++it_point_idx) {
- sstr_c << *it_point_idx << " ";
- }
-
- os << 3 << " " << sstr_c.str();
- if (color_inconsistencies || p_simpl_to_color_in_red || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
- switch (color_simplex) {
- case 0:
- os << " 255 255 0";
- break;
- case 1:
- os << " 255 0 0";
- break;
- case 2:
- os << " 0 255 0";
- break;
- case 3:
- os << " 0 0 255";
- break;
- default:
- os << " " << color.str();
- break;
- }
- }
- ++num_OFF_simplices;
- os << "\n";
- }
- if (is_star_inconsistent) ++num_inconsistent_stars;
- }
-
-#ifdef DEBUG_TRACES
- std::cerr << "\n==========================================================\n"
- << "Export from list of stars to OFF:\n"
- << " * Number of vertices: " << m_points.size() << "\n"
- << " * Total number of maximal simplices: " << num_maximal_simplices << "\n";
- if (color_inconsistencies) {
- std::cerr << " * Number of inconsistent stars: " << num_inconsistent_stars << " ("
- << (m_points.size() > 0 ? 100. * num_inconsistent_stars / m_points.size() : 0.) << "%)\n"
- << " * Number of inconsistent maximal simplices: " << num_inconsistent_maximal_simplices << " ("
- << (num_maximal_simplices > 0 ? 100. * num_inconsistent_maximal_simplices / num_maximal_simplices : 0.)
- << "%)\n";
- }
- std::cerr << "==========================================================\n";
-#endif
-
- return os;
- }
-
- public:
- std::ostream &export_simplices_to_off(const Simplicial_complex &complex, std::ostream &os,
- std::size_t &num_OFF_simplices,
- Simplex_set const *p_simpl_to_color_in_red = NULL,
- Simplex_set const *p_simpl_to_color_in_green = NULL,
- Simplex_set const *p_simpl_to_color_in_blue = NULL) const {
- typedef Simplicial_complex::Simplex Simplex;
- typedef Simplicial_complex::Simplex_set Simplex_set;
-
- // If m_intrinsic_dim = 1, each point is output two times
- // (see export_vertices_to_off)
- num_OFF_simplices = 0;
- std::size_t num_maximal_simplices = 0;
-
- typename Simplex_set::const_iterator it_s = complex.simplex_range().begin();
- typename Simplex_set::const_iterator it_s_end = complex.simplex_range().end();
- // For each simplex
- for (; it_s != it_s_end; ++it_s) {
- Simplex c = *it_s;
- ++num_maximal_simplices;
-
- int color_simplex = -1; // -1=no color, 0=yellow, 1=red, 2=green, 3=blue
- if (p_simpl_to_color_in_red && std::find(p_simpl_to_color_in_red->begin(), p_simpl_to_color_in_red->end(), c) !=
- p_simpl_to_color_in_red->end()) {
- color_simplex = 1;
- } else if (p_simpl_to_color_in_green &&
- std::find(p_simpl_to_color_in_green->begin(), p_simpl_to_color_in_green->end(), c) !=
- p_simpl_to_color_in_green->end()) {
- color_simplex = 2;
- } else if (p_simpl_to_color_in_blue &&
- std::find(p_simpl_to_color_in_blue->begin(), p_simpl_to_color_in_blue->end(), c) !=
- p_simpl_to_color_in_blue->end()) {
- color_simplex = 3;
- }
-
- // Gather the triangles here
- typedef std::vector<Simplex> Triangles;
- Triangles triangles;
-
- int num_vertices = static_cast<int>(c.size());
- // Do not export smaller dimension simplices
- if (num_vertices < m_intrinsic_dim + 1) continue;
-
- // If m_intrinsic_dim = 1, each point is output two times,
- // so we need to multiply each index by 2
- // And if only 2 vertices, add a third one (each vertex is duplicated in
- // the file when m_intrinsic dim = 2)
- if (m_intrinsic_dim == 1) {
- Simplex tmp_c;
- Simplex::iterator it = c.begin();
- for (; it != c.end(); ++it) tmp_c.insert(*it * 2);
- if (num_vertices == 2) tmp_c.insert(*tmp_c.rbegin() + 1);
-
- c = tmp_c;
- }
-
- if (num_vertices <= 3) {
- triangles.push_back(c);
- } else {
- // num_vertices >= 4: decompose the simplex in triangles
- std::vector<bool> booleans(num_vertices, false);
- std::fill(booleans.begin() + num_vertices - 3, booleans.end(), true);
- do {
- Simplex triangle;
- Simplex::iterator it = c.begin();
- for (int i = 0; it != c.end(); ++i, ++it) {
- if (booleans[i]) triangle.insert(*it);
- }
- triangles.push_back(triangle);
- } while (std::next_permutation(booleans.begin(), booleans.end()));
- }
-
- // For each cell
- Triangles::const_iterator it_tri = triangles.begin();
- Triangles::const_iterator it_tri_end = triangles.end();
- for (; it_tri != it_tri_end; ++it_tri) {
- // Don't export infinite cells
- if (is_infinite(*it_tri)) continue;
-
- os << 3 << " ";
- Simplex::const_iterator it_point_idx = it_tri->begin();
- for (; it_point_idx != it_tri->end(); ++it_point_idx) {
- os << *it_point_idx << " ";
- }
-
- if (p_simpl_to_color_in_red || p_simpl_to_color_in_green || p_simpl_to_color_in_blue) {
- switch (color_simplex) {
- case 0:
- os << " 255 255 0";
- break;
- case 1:
- os << " 255 0 0";
- break;
- case 2:
- os << " 0 255 0";
- break;
- case 3:
- os << " 0 0 255";
- break;
- default:
- os << " 128 128 128";
- break;
- }
- }
-
- ++num_OFF_simplices;
- os << "\n";
- }
- }
-
-#ifdef DEBUG_TRACES
- std::cerr << "\n==========================================================\n"
- << "Export from complex to OFF:\n"
- << " * Number of vertices: " << m_points.size() << "\n"
- << " * Total number of maximal simplices: " << num_maximal_simplices << "\n"
- << "==========================================================\n";
-#endif
-
- return os;
- }
-
- private:
- const K m_k;
- const int m_intrinsic_dim;
- const int m_ambient_dim;
-
- Points m_points;
- Weights m_weights;
-#ifdef GUDHI_TC_PERTURB_POSITION
- Translations_for_perturb m_translations;
-#if defined(GUDHI_USE_TBB)
- Mutex_for_perturb *m_p_perturb_mutexes;
-#endif
-#endif
-
- Points_ds m_points_ds;
- double m_last_max_perturb;
- std::vector<bool> m_are_tangent_spaces_computed;
- TS_container m_tangent_spaces;
-#ifdef GUDHI_TC_EXPORT_NORMALS
- OS_container m_orth_spaces;
-#endif
- Tr_container m_triangulations; // Contains the triangulations
- // and their center vertex
- Stars_container m_stars;
- std::vector<FT> m_squared_star_spheres_radii_incl_margin;
-
-#ifdef GUDHI_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
- Points m_points_for_tse;
- Points_ds m_points_ds_for_tse;
-#endif
-
- mutable CGAL::Random m_random_generator;
-}; // /class Tangential_complex
-
-} // end namespace tangential_complex
-} // end namespace Gudhi
-
-#endif // TANGENTIAL_COMPLEX_H_
diff --git a/include/gudhi/Tangential_complex/Simplicial_complex.h b/include/gudhi/Tangential_complex/Simplicial_complex.h
deleted file mode 100644
index f79186b0..00000000
--- a/include/gudhi/Tangential_complex/Simplicial_complex.h
+++ /dev/null
@@ -1,539 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_
-#define TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_
-
-#include <gudhi/Tangential_complex/config.h>
-#include <gudhi/Tangential_complex/utilities.h>
-#include <gudhi/Debug_utils.h>
-#include <gudhi/console_color.h>
-
-#include <CGAL/iterator.h>
-
-// For is_pure_pseudomanifold
-#include <boost/graph/graph_traits.hpp>
-#include <boost/graph/adjacency_list.hpp>
-#include <boost/graph/connected_components.hpp>
-#include <boost/container/flat_set.hpp>
-
-#include <algorithm>
-#include <string>
-#include <fstream>
-#include <map> // for map<>
-#include <vector> // for vector<>
-#include <set> // for set<>
-
-namespace Gudhi {
-namespace tangential_complex {
-namespace internal {
-
-class Simplicial_complex {
- public:
- typedef boost::container::flat_set<std::size_t> Simplex;
- typedef std::set<Simplex> Simplex_set;
-
- // If perform_checks = true, the function:
- // - won't insert the simplex if it is already in a higher dim simplex
- // - will erase any lower-dim simplices that are faces of the new simplex
- // Returns true if the simplex was added
- bool add_simplex(
- const Simplex &s, bool perform_checks = true) {
- if (perform_checks) {
- unsigned int num_pts = static_cast<int> (s.size());
- std::vector<Complex::iterator> to_erase;
- bool check_higher_dim_simpl = true;
- for (Complex::iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- // Check if the simplex is not already in a higher dim simplex
- if (check_higher_dim_simpl
- && it_simplex->size() > num_pts
- && std::includes(it_simplex->begin(), it_simplex->end(),
- s.begin(), s.end())) {
- // No need to insert it, then
- return false;
- }
- // Check if the simplex includes some lower-dim simplices
- if (it_simplex->size() < num_pts
- && std::includes(s.begin(), s.end(),
- it_simplex->begin(), it_simplex->end())) {
- to_erase.push_back(it_simplex);
- // We don't need to check higher-sim simplices any more
- check_higher_dim_simpl = false;
- }
- }
- for (std::vector<Complex::iterator>::const_iterator it = to_erase.begin();
- it != to_erase.end(); ++it) {
- m_complex.erase(*it);
- }
- }
- return m_complex.insert(s).second;
- }
-
- const Simplex_set &simplex_range() const {
- return m_complex;
- }
-
- bool empty() {
- return m_complex.empty();
- }
-
- void clear() {
- m_complex.clear();
- }
-
- template <typename Test, typename Output_it>
- void get_simplices_matching_test(Test test, Output_it out) {
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- if (test(*it_simplex))
- *out++ = *it_simplex;
- }
- }
-
- // When a simplex S has only one co-face C, we can remove S and C
- // without changing the topology
-
- void collapse(int max_simplex_dim, bool quiet = false) {
-#ifdef DEBUG_TRACES
- if (!quiet)
- std::cerr << "Collapsing... ";
-#endif
- // We note k = max_simplex_dim - 1
- int k = max_simplex_dim - 1;
-
- typedef Complex::iterator Simplex_iterator;
- typedef std::vector<Simplex_iterator> Simplex_iterator_list;
- typedef std::map<Simplex, Simplex_iterator_list> Cofaces_map;
-
- std::size_t num_collapsed_maximal_simplices = 0;
- do {
- num_collapsed_maximal_simplices = 0;
- // Create a map associating each non-maximal k-faces to the list of its
- // maximal cofaces
- Cofaces_map cofaces_map;
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- if (static_cast<int> (it_simplex->size()) > k + 1) {
- std::vector<Simplex> k_faces;
- // Get the k-faces composing the simplex
- combinations(*it_simplex, k + 1, std::back_inserter(k_faces));
- for (const auto &comb : k_faces)
- cofaces_map[comb].push_back(it_simplex);
- }
- }
-
- // For each non-maximal k-face F, if F has only one maximal coface Cf:
- // - Look for the other k-faces F2, F3... of Cf in the map and:
- // * if the list contains only Cf, clear the list (we don't remove the
- // list since it creates troubles with the iterators) and add the F2,
- // F3... to the complex
- // * otherwise, remove Cf from the associated list
- // - Remove Cf from the complex
- for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
- it_map_end = cofaces_map.end();
- it_map_elt != it_map_end;
- ++it_map_elt) {
- if (it_map_elt->second.size() == 1) {
- std::vector<Simplex> k_faces;
- const Simplex_iterator_list::value_type &it_Cf =
- *it_map_elt->second.begin();
- GUDHI_CHECK(it_Cf->size() == max_simplex_dim + 1,
- std::logic_error("Wrong dimension"));
- // Get the k-faces composing the simplex
- combinations(*it_Cf, k + 1, std::back_inserter(k_faces));
- for (const auto &f2 : k_faces) {
- // Skip F
- if (f2 != it_map_elt->first) {
- Cofaces_map::iterator it_comb_in_map = cofaces_map.find(f2);
- if (it_comb_in_map->second.size() == 1) {
- it_comb_in_map->second.clear();
- m_complex.insert(f2);
- } else { // it_comb_in_map->second.size() > 1
- Simplex_iterator_list::iterator it = std::find(it_comb_in_map->second.begin(),
- it_comb_in_map->second.end(),
- it_Cf);
- GUDHI_CHECK(it != it_comb_in_map->second.end(),
- std::logic_error("Error: it == it_comb_in_map->second.end()"));
- it_comb_in_map->second.erase(it);
- }
- }
- }
- m_complex.erase(it_Cf);
- ++num_collapsed_maximal_simplices;
- }
- }
- // Repeat until no maximal simplex got removed
- } while (num_collapsed_maximal_simplices > 0);
-
- // Collapse the lower dimension simplices
- if (k > 0)
- collapse(max_simplex_dim - 1, true);
-
-#ifdef DEBUG_TRACES
- if (!quiet)
- std::cerr << "done.\n";
-#endif
- }
-
- void display_stats() const {
- std::cerr << yellow << "Complex stats:\n" << white;
-
- if (m_complex.empty()) {
- std::cerr << " * No simplices.\n";
- } else {
- // Number of simplex for each dimension
- std::map<int, std::size_t> simplex_stats;
-
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- ++simplex_stats[static_cast<int> (it_simplex->size()) - 1];
- }
-
- for (std::map<int, std::size_t>::const_iterator it_map = simplex_stats.begin();
- it_map != simplex_stats.end(); ++it_map) {
- std::cerr << " * " << it_map->first << "-simplices: "
- << it_map->second << "\n";
- }
- }
- }
-
- // verbose_level = 0, 1 or 2
- bool is_pure_pseudomanifold__do_not_check_if_stars_are_connected(int simplex_dim,
- bool allow_borders = false,
- bool exit_at_the_first_problem = false,
- int verbose_level = 0,
- std::size_t *p_num_wrong_dim_simplices = NULL,
- std::size_t *p_num_wrong_number_of_cofaces = NULL) const {
- typedef Simplex K_1_face;
- typedef std::map<K_1_face, std::size_t> Cofaces_map;
-
- std::size_t num_wrong_dim_simplices = 0;
- std::size_t num_wrong_number_of_cofaces = 0;
-
- // Counts the number of cofaces of each K_1_face
-
- // Create a map associating each non-maximal k-faces to the list of its
- // maximal cofaces
- Cofaces_map cofaces_map;
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- if (static_cast<int> (it_simplex->size()) != simplex_dim + 1) {
- if (verbose_level >= 2)
- std::cerr << "Found a simplex with dim = "
- << it_simplex->size() - 1 << "\n";
- ++num_wrong_dim_simplices;
- } else {
- std::vector<K_1_face> k_1_faces;
- // Get the facets composing the simplex
- combinations(
- *it_simplex, simplex_dim, std::back_inserter(k_1_faces));
- for (const auto &k_1_face : k_1_faces) {
- ++cofaces_map[k_1_face];
- }
- }
- }
-
- for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
- it_map_end = cofaces_map.end();
- it_map_elt != it_map_end;
- ++it_map_elt) {
- if (it_map_elt->second != 2
- && (!allow_borders || it_map_elt->second != 1)) {
- if (verbose_level >= 2)
- std::cerr << "Found a k-1-face with "
- << it_map_elt->second << " cofaces\n";
-
- if (exit_at_the_first_problem)
- return false;
- else
- ++num_wrong_number_of_cofaces;
- }
- }
-
- bool ret = num_wrong_dim_simplices == 0 && num_wrong_number_of_cofaces == 0;
-
- if (verbose_level >= 1) {
- std::cerr << "Pure pseudo-manifold: ";
- if (ret) {
- std::cerr << green << "YES" << white << "\n";
- } else {
- std::cerr << red << "NO" << white << "\n"
- << " * Number of wrong dimension simplices: "
- << num_wrong_dim_simplices << "\n"
- << " * Number of wrong number of cofaces: "
- << num_wrong_number_of_cofaces << "\n";
- }
- }
-
- if (p_num_wrong_dim_simplices)
- *p_num_wrong_dim_simplices = num_wrong_dim_simplices;
- if (p_num_wrong_number_of_cofaces)
- *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
-
- return ret;
- }
-
- template <int K>
- std::size_t num_K_simplices() const {
- Simplex_set k_simplices;
-
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- if (it_simplex->size() == K + 1) {
- k_simplices.insert(*it_simplex);
- } else if (it_simplex->size() > K + 1) {
- // Get the k-faces composing the simplex
- combinations(
- *it_simplex, K + 1, std::inserter(k_simplices, k_simplices.begin()));
- }
- }
-
- return k_simplices.size();
- }
-
- std::ptrdiff_t euler_characteristic(bool verbose = false) const {
- if (verbose)
- std::cerr << "\nComputing Euler characteristic of the complex...\n";
-
- std::size_t num_vertices = num_K_simplices<0>();
- std::size_t num_edges = num_K_simplices<1>();
- std::size_t num_triangles = num_K_simplices<2>();
-
- std::ptrdiff_t ec =
- (std::ptrdiff_t) num_vertices
- - (std::ptrdiff_t) num_edges
- + (std::ptrdiff_t) num_triangles;
-
- if (verbose)
- std::cerr << "Euler characteristic: V - E + F = "
- << num_vertices << " - " << num_edges << " + " << num_triangles << " = "
- << blue
- << ec
- << white << "\n";
-
- return ec;
- }
-
- // TODO(CJ): ADD COMMENTS
-
- bool is_pure_pseudomanifold(
- int simplex_dim,
- std::size_t num_vertices,
- bool allow_borders = false,
- bool exit_at_the_first_problem = false,
- int verbose_level = 0,
- std::size_t *p_num_wrong_dim_simplices = NULL,
- std::size_t *p_num_wrong_number_of_cofaces = NULL,
- std::size_t *p_num_unconnected_stars = NULL,
- Simplex_set *p_wrong_dim_simplices = NULL,
- Simplex_set *p_wrong_number_of_cofaces_simplices = NULL,
- Simplex_set *p_unconnected_stars_simplices = NULL) const {
- // If simplex_dim == 1, we do not need to check if stars are connected
- if (simplex_dim == 1) {
- if (p_num_unconnected_stars)
- *p_num_unconnected_stars = 0;
- return is_pure_pseudomanifold__do_not_check_if_stars_are_connected(simplex_dim,
- allow_borders,
- exit_at_the_first_problem,
- verbose_level,
- p_num_wrong_dim_simplices,
- p_num_wrong_number_of_cofaces);
- }
- // Associates each vertex (= the index in the vector)
- // to its star (list of simplices)
- typedef std::vector<std::vector<Complex::const_iterator> > Stars;
- std::size_t num_wrong_dim_simplices = 0;
- std::size_t num_wrong_number_of_cofaces = 0;
- std::size_t num_unconnected_stars = 0;
-
- // Fills a Stars data structure
- Stars stars;
- stars.resize(num_vertices);
- for (Complex::const_iterator it_simplex = m_complex.begin(),
- it_simplex_end = m_complex.end();
- it_simplex != it_simplex_end;
- ++it_simplex) {
- if (static_cast<int> (it_simplex->size()) != simplex_dim + 1) {
- if (verbose_level >= 2)
- std::cerr << "Found a simplex with dim = "
- << it_simplex->size() - 1 << "\n";
- ++num_wrong_dim_simplices;
- if (p_wrong_dim_simplices)
- p_wrong_dim_simplices->insert(*it_simplex);
- } else {
- for (Simplex::const_iterator it_point_idx = it_simplex->begin();
- it_point_idx != it_simplex->end();
- ++it_point_idx) {
- stars[*it_point_idx].push_back(it_simplex);
- }
- }
- }
-
- // Now, for each star, we have a vector of its d-simplices
- // i.e. one index for each d-simplex
- // Boost Graph only deals with indexes, so we also need indexes for the
- // (d-1)-simplices
- std::size_t center_vertex_index = 0;
- for (Stars::const_iterator it_star = stars.begin();
- it_star != stars.end();
- ++it_star, ++center_vertex_index) {
- typedef std::map<Simplex, std::vector<std::size_t> >
- Dm1_faces_to_adj_D_faces;
- Dm1_faces_to_adj_D_faces dm1_faces_to_adj_d_faces;
-
- for (std::size_t i_dsimpl = 0; i_dsimpl < it_star->size(); ++i_dsimpl) {
- Simplex dm1_simpl_of_link = *((*it_star)[i_dsimpl]);
- dm1_simpl_of_link.erase(center_vertex_index);
- // Copy it to a vector so that we can use operator[] on it
- std::vector<std::size_t> dm1_simpl_of_link_vec(
- dm1_simpl_of_link.begin(), dm1_simpl_of_link.end());
-
- CGAL::Combination_enumerator<int> dm2_simplices(
- simplex_dim - 1, 0, simplex_dim);
- for (; !dm2_simplices.finished(); ++dm2_simplices) {
- Simplex dm2_simpl;
- for (int j = 0; j < simplex_dim - 1; ++j)
- dm2_simpl.insert(dm1_simpl_of_link_vec[dm2_simplices[j]]);
- dm1_faces_to_adj_d_faces[dm2_simpl].push_back(i_dsimpl);
- }
- }
-
- Adj_graph adj_graph;
- std::vector<Graph_vertex> d_faces_descriptors;
- d_faces_descriptors.resize(it_star->size());
- for (std::size_t j = 0; j < it_star->size(); ++j)
- d_faces_descriptors[j] = boost::add_vertex(adj_graph);
-
- Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it =
- dm1_faces_to_adj_d_faces.begin();
- Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it_end =
- dm1_faces_to_adj_d_faces.end();
- for (std::size_t i_km1_face = 0;
- dm1_to_d_it != dm1_to_d_it_end;
- ++dm1_to_d_it, ++i_km1_face) {
- Graph_vertex km1_gv = boost::add_vertex(adj_graph);
-
- for (std::vector<std::size_t>::const_iterator kface_it =
- dm1_to_d_it->second.begin();
- kface_it != dm1_to_d_it->second.end();
- ++kface_it) {
- boost::add_edge(km1_gv, *kface_it, adj_graph);
- }
-
- if (dm1_to_d_it->second.size() != 2
- && (!allow_borders || dm1_to_d_it->second.size() != 1)) {
- ++num_wrong_number_of_cofaces;
- if (p_wrong_number_of_cofaces_simplices) {
- for (auto idx : dm1_to_d_it->second)
- p_wrong_number_of_cofaces_simplices->insert(*((*it_star)[idx]));
- }
- }
- }
-
- // What is left is to check the connexity
- bool is_connected = true;
- if (boost::num_vertices(adj_graph) > 0) {
- std::vector<int> components(boost::num_vertices(adj_graph));
- is_connected =
- (boost::connected_components(adj_graph, &components[0]) == 1);
- }
-
- if (!is_connected) {
- if (verbose_level >= 2)
- std::cerr << "Error: star #" << center_vertex_index
- << " is not connected\n";
- ++num_unconnected_stars;
- if (p_unconnected_stars_simplices) {
- for (std::vector<Complex::const_iterator>::const_iterator
- it_simpl = it_star->begin(),
- it_simpl_end = it_star->end();
- it_simpl != it_simpl_end;
- ++it_simpl) {
- p_unconnected_stars_simplices->insert(**it_simpl);
- }
- }
- }
- }
-
- // Each one has been counted several times ("simplex_dim" times)
- num_wrong_number_of_cofaces /= simplex_dim;
-
- bool ret =
- num_wrong_dim_simplices == 0
- && num_wrong_number_of_cofaces == 0
- && num_unconnected_stars == 0;
-
- if (verbose_level >= 1) {
- std::cerr << "Pure pseudo-manifold: ";
- if (ret) {
- std::cerr << green << "YES" << white << "\n";
- } else {
- std::cerr << red << "NO" << white << "\n"
- << " * Number of wrong dimension simplices: "
- << num_wrong_dim_simplices << "\n"
- << " * Number of wrong number of cofaces: "
- << num_wrong_number_of_cofaces << "\n"
- << " * Number of not-connected stars: "
- << num_unconnected_stars << "\n";
- }
- }
-
- if (p_num_wrong_dim_simplices)
- *p_num_wrong_dim_simplices = num_wrong_dim_simplices;
- if (p_num_wrong_number_of_cofaces)
- *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
- if (p_num_unconnected_stars)
- *p_num_unconnected_stars = num_unconnected_stars;
-
- return ret;
- }
-
- private:
- typedef Simplex_set Complex;
-
- // graph is an adjacency list
- typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph;
- // map that gives to a certain simplex its node in graph and its dimension
- typedef boost::graph_traits<Adj_graph>::vertex_descriptor Graph_vertex;
- typedef boost::graph_traits<Adj_graph>::edge_descriptor Graph_edge;
-
- Complex m_complex;
-}; // class Simplicial_complex
-
-} // namespace internal
-} // namespace tangential_complex
-} // namespace Gudhi
-
-#endif // TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_
diff --git a/include/gudhi/Tangential_complex/config.h b/include/gudhi/Tangential_complex/config.h
deleted file mode 100644
index e1af1ea6..00000000
--- a/include/gudhi/Tangential_complex/config.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TANGENTIAL_COMPLEX_CONFIG_H_
-#define TANGENTIAL_COMPLEX_CONFIG_H_
-
-#include <cstddef>
-
-// ========================= Debugging & profiling =============================
-// #define GUDHI_TC_PROFILING
-// #define GUDHI_TC_VERY_VERBOSE
-// #define GUDHI_TC_PERFORM_EXTRA_CHECKS
-// #define GUDHI_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
-
-// ========================= Strategy ==========================================
-#define GUDHI_TC_PERTURB_POSITION
-// #define GUDHI_TC_PERTURB_WEIGHT
-
-// ========================= Parameters ========================================
-
-// PCA will use GUDHI_TC_BASE_VALUE_FOR_PCA^intrinsic_dim points
-const std::size_t GUDHI_TC_BASE_VALUE_FOR_PCA = 5;
-
-#endif // TANGENTIAL_COMPLEX_CONFIG_H_
diff --git a/include/gudhi/Tangential_complex/utilities.h b/include/gudhi/Tangential_complex/utilities.h
deleted file mode 100644
index 2dd46118..00000000
--- a/include/gudhi/Tangential_complex/utilities.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef TANGENTIAL_COMPLEX_UTILITIES_H_
-#define TANGENTIAL_COMPLEX_UTILITIES_H_
-
-#include <CGAL/Dimension.h>
-#include <CGAL/Combination_enumerator.h>
-#include <CGAL/IO/Triangulation_off_ostream.h>
-
-#include <boost/container/flat_set.hpp>
-
-#include <Eigen/Core>
-#include <Eigen/Eigen>
-
-#include <set>
-#include <vector>
-#include <array>
-#include <fstream>
-#include <atomic>
-#include <cmath> // for std::sqrt
-
-namespace Gudhi {
-namespace tangential_complex {
-namespace internal {
-
-// Provides copy constructors to std::atomic so that
-// it can be used in a vector
-template <typename T>
-struct Atomic_wrapper
-: public std::atomic<T> {
- typedef std::atomic<T> Base;
-
- Atomic_wrapper() { }
-
- Atomic_wrapper(const T &t) : Base(t) { }
-
- Atomic_wrapper(const std::atomic<T> &a) : Base(a.load()) { }
-
- Atomic_wrapper(const Atomic_wrapper &other) : Base(other.load()) { }
-
- Atomic_wrapper &operator=(const T &other) {
- Base::store(other);
- return *this;
- }
-
- Atomic_wrapper &operator=(const std::atomic<T> &other) {
- Base::store(other.load());
- return *this;
- }
-
- Atomic_wrapper &operator=(const Atomic_wrapper &other) {
- Base::store(other.load());
- return *this;
- }
-};
-
-// Modifies v in-place
-template <typename K>
-typename K::Vector_d& normalize_vector(typename K::Vector_d& v,
- K const& k) {
- v = k.scaled_vector_d_object()(
- v, typename K::FT(1) / std::sqrt(k.squared_length_d_object()(v)));
- return v;
-}
-
-template<typename Kernel>
-struct Basis {
- typedef typename Kernel::FT FT;
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::Vector_d Vector;
- typedef typename std::vector<Vector>::const_iterator const_iterator;
-
- std::size_t m_origin;
- std::vector<Vector> m_vectors;
-
- std::size_t origin() const {
- return m_origin;
- }
-
- void set_origin(std::size_t o) {
- m_origin = o;
- }
-
- const_iterator begin() const {
- return m_vectors.begin();
- }
-
- const_iterator end() const {
- return m_vectors.end();
- }
-
- std::size_t size() const {
- return m_vectors.size();
- }
-
- Vector& operator[](const std::size_t i) {
- return m_vectors[i];
- }
-
- const Vector& operator[](const std::size_t i) const {
- return m_vectors[i];
- }
-
- void push_back(const Vector& v) {
- m_vectors.push_back(v);
- }
-
- void reserve(const std::size_t s) {
- m_vectors.reserve(s);
- }
-
- Basis() { }
-
- Basis(std::size_t origin) : m_origin(origin) { }
-
- Basis(std::size_t origin, const std::vector<Vector>& vectors)
- : m_origin(origin), m_vectors(vectors) { }
-
- int dimension() const {
- return static_cast<int> (m_vectors.size());
- }
-};
-
-// 1st line: number of points
-// Then one point per line
-template <typename Kernel, typename Point_range>
-std::ostream &export_point_set(
- Kernel const& k,
- Point_range const& points,
- std::ostream & os,
- const char *coord_separator = " ") {
- // Kernel functors
- typename Kernel::Construct_cartesian_const_iterator_d ccci =
- k.construct_cartesian_const_iterator_d_object();
-
- os << points.size() << "\n";
-
- typename Point_range::const_iterator it_p = points.begin();
- typename Point_range::const_iterator it_p_end = points.end();
- // For each point p
- for (; it_p != it_p_end; ++it_p) {
- for (auto it = ccci(*it_p); it != ccci(*it_p, 0); ++it)
- os << CGAL::to_double(*it) << coord_separator;
-
- os << "\n";
- }
-
- return os;
-}
-
-// Compute all the k-combinations of elements
-// Output_iterator::value_type must be
-// boost::container::flat_set<std::size_t>
-template <typename Elements_container, typename Output_iterator>
-void combinations(const Elements_container elements, int k,
- Output_iterator combinations) {
- std::size_t n = elements.size();
- std::vector<bool> booleans(n, false);
- std::fill(booleans.begin() + n - k, booleans.end(), true);
- do {
- boost::container::flat_set<std::size_t> combination;
- typename Elements_container::const_iterator it_elt = elements.begin();
- for (std::size_t i = 0; i < n; ++i, ++it_elt) {
- if (booleans[i])
- combination.insert(*it_elt);
- }
- *combinations++ = combination;
- } while (std::next_permutation(booleans.begin(), booleans.end()));
-}
-
-} // namespace internal
-} // namespace tangential_complex
-} // namespace Gudhi
-
-#endif // TANGENTIAL_COMPLEX_UTILITIES_H_
diff --git a/include/gudhi/Unitary_tests_utils.h b/include/gudhi/Unitary_tests_utils.h
deleted file mode 100644
index e07c8d42..00000000
--- a/include/gudhi/Unitary_tests_utils.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Vincent Rouvreau
- *
- * Copyright (C) 2017 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef UNITARY_TESTS_UTILS_H_
-#define UNITARY_TESTS_UTILS_H_
-
-#include <boost/test/unit_test.hpp>
-
-#include <iostream>
-#include <limits> // for std::numeric_limits<>
-
-template<typename FloatingType >
-void GUDHI_TEST_FLOAT_EQUALITY_CHECK(FloatingType a, FloatingType b,
- FloatingType epsilon = std::numeric_limits<FloatingType>::epsilon()) {
-#ifdef DEBUG_TRACES
- std::cout << "GUDHI_TEST_FLOAT_EQUALITY_CHECK - " << a << " versus " << b
- << " | diff = " << std::fabs(a - b) << " - epsilon = " << epsilon << std::endl;
-#endif
- BOOST_CHECK(std::fabs(a - b) < epsilon);
-}
-
-#endif // UNITARY_TESTS_UTILS_H_
diff --git a/include/gudhi/Witness_complex.h b/include/gudhi/Witness_complex.h
deleted file mode 100644
index 67885258..00000000
--- a/include/gudhi/Witness_complex.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef WITNESS_COMPLEX_H_
-#define WITNESS_COMPLEX_H_
-
-#include <gudhi/Active_witness/Active_witness.h>
-#include <gudhi/Witness_complex/all_faces_in.h>
-
-#include <utility>
-#include <vector>
-#include <list>
-#include <limits>
-
-namespace Gudhi {
-
-namespace witness_complex {
-
-/**
- * \private
- * \class Witness_complex
- * \brief Constructs (weak) witness complex for a given table of nearest landmarks with respect to witnesses.
- * \ingroup witness_complex
- *
- * \tparam Nearest_landmark_table_ needs to be a range of a range of pairs of nearest landmarks and distances.
- * The class Nearest_landmark_table_::value_type must be a copiable range.
- * The range of pairs must admit a member type 'iterator'. The dereference type
- * of the pair range iterator needs to be 'std::pair<std::size_t, double>'.
-*/
-template< class Nearest_landmark_table_ >
-class Witness_complex {
- private:
- typedef typename Nearest_landmark_table_::value_type Nearest_landmark_range;
- typedef std::size_t Witness_id;
- typedef std::size_t Landmark_id;
- typedef std::pair<Landmark_id, double> Id_distance_pair;
- typedef Active_witness<Id_distance_pair, Nearest_landmark_range> ActiveWitness;
- typedef std::list< ActiveWitness > ActiveWitnessList;
- typedef std::vector< Landmark_id > typeVectorVertex;
- typedef std::vector<Nearest_landmark_range> Nearest_landmark_table_internal;
- typedef Landmark_id Vertex_handle;
-
- protected:
- Nearest_landmark_table_internal nearest_landmark_table_;
-
- public:
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /* @name Constructor
- */
-
- //@{
-
- Witness_complex() {
- }
-
- /**
- * \brief Initializes member variables before constructing simplicial complex.
- * \details Records nearest landmark table.
- * @param[in] nearest_landmark_table needs to be a range of a range of pairs of nearest landmarks and distances.
- * The class Nearest_landmark_table_::value_type must be a copiable range.
- * The range of pairs must admit a member type 'iterator'. The dereference type
- * of the pair range iterator needs to be 'std::pair<std::size_t, double>'.
- */
-
- Witness_complex(Nearest_landmark_table_ const & nearest_landmark_table)
- : nearest_landmark_table_(std::begin(nearest_landmark_table), std::end(nearest_landmark_table)) {
- }
-
- /** \brief Outputs the (weak) witness complex of relaxation 'max_alpha_square'
- * in a simplicial complex data structure.
- * \details The function returns true if the construction is successful and false otherwise.
- * @param[out] complex Simplicial complex data structure compatible which is a model of
- * SimplicialComplexForWitness concept.
- * @param[in] max_alpha_square Maximal squared relaxation parameter.
- * @param[in] limit_dimension Represents the maximal dimension of the simplicial complex
- * (default value = no limit).
- */
- template < typename SimplicialComplexForWitness >
- bool create_complex(SimplicialComplexForWitness& complex,
- double max_alpha_square,
- std::size_t limit_dimension = std::numeric_limits<std::size_t>::max()) const {
- if (complex.num_vertices() > 0) {
- std::cerr << "Witness complex cannot create complex - complex is not empty.\n";
- return false;
- }
- if (max_alpha_square < 0) {
- std::cerr << "Witness complex cannot create complex - squared relaxation parameter must be non-negative.\n";
- return false;
- }
- ActiveWitnessList active_witnesses;
- Landmark_id k = 0; /* current dimension in iterative construction */
- for (auto w : nearest_landmark_table_)
- active_witnesses.push_back(ActiveWitness(w));
- while (!active_witnesses.empty() && k <= limit_dimension) {
- typename ActiveWitnessList::iterator aw_it = active_witnesses.begin();
- std::vector<Landmark_id> simplex;
- simplex.reserve(k+1);
- while (aw_it != active_witnesses.end()) {
- bool ok = add_all_faces_of_dimension(k,
- max_alpha_square,
- std::numeric_limits<double>::infinity(),
- aw_it->begin(),
- simplex,
- complex,
- aw_it->end());
- assert(simplex.empty());
- if (!ok)
- active_witnesses.erase(aw_it++); // First increase the iterator and then erase the previous element
- else
- aw_it++;
- }
- k++;
- }
- return true;
- }
-
- //@}
-
- private:
- /* \brief Adds recursively all the faces of a certain dimension dim witnessed by the same witness.
- * Iterator is needed to know until how far we can take landmarks to form simplexes.
- * simplex is the prefix of the simplexes to insert.
- * The output value indicates if the witness rests active or not.
- */
- template < typename SimplicialComplexForWitness >
- bool add_all_faces_of_dimension(int dim,
- double alpha2,
- double norelax_dist2,
- typename ActiveWitness::iterator curr_l,
- std::vector<Landmark_id>& simplex,
- SimplicialComplexForWitness& sc,
- typename ActiveWitness::iterator end) const {
- if (curr_l == end)
- return false;
- bool will_be_active = false;
- typename ActiveWitness::iterator l_it = curr_l;
- if (dim > 0) {
- for (; l_it != end && l_it->second - alpha2 <= norelax_dist2; ++l_it) {
- simplex.push_back(l_it->first);
- if (sc.find(simplex) != sc.null_simplex()) {
- typename ActiveWitness::iterator next_it = l_it;
- will_be_active = add_all_faces_of_dimension(dim-1,
- alpha2,
- norelax_dist2,
- ++next_it,
- simplex,
- sc,
- end) || will_be_active;
- }
- assert(!simplex.empty());
- simplex.pop_back();
- // If norelax_dist is infinity, change to first omitted distance
- if (l_it->second <= norelax_dist2)
- norelax_dist2 = l_it->second;
- }
- } else if (dim == 0) {
- for (; l_it != end && l_it->second - alpha2 <= norelax_dist2; ++l_it) {
- simplex.push_back(l_it->first);
- double filtration_value = 0;
- // if norelax_dist is infinite, relaxation is 0.
- if (l_it->second > norelax_dist2)
- filtration_value = l_it->second - norelax_dist2;
- if (all_faces_in(simplex, &filtration_value, sc)) {
- will_be_active = true;
- sc.insert_simplex(simplex, filtration_value);
- }
- assert(!simplex.empty());
- simplex.pop_back();
- // If norelax_dist is infinity, change to first omitted distance
- if (l_it->second < norelax_dist2)
- norelax_dist2 = l_it->second;
- }
- }
- return will_be_active;
- }
-};
-
-} // namespace witness_complex
-
-} // namespace Gudhi
-
-#endif // WITNESS_COMPLEX_H_
diff --git a/include/gudhi/Witness_complex/all_faces_in.h b/include/gudhi/Witness_complex/all_faces_in.h
deleted file mode 100644
index c7b732b9..00000000
--- a/include/gudhi/Witness_complex/all_faces_in.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef WITNESS_COMPLEX_ALL_FACES_IN_H_
-#define WITNESS_COMPLEX_ALL_FACES_IN_H_
-
-/* \brief Check if the facets of the k-dimensional simplex witnessed
- * by witness witness_id are already in the complex.
- * inserted_vertex is the handle of the (k+1)-th vertex witnessed by witness_id
- */
-template < typename SimplicialComplexForWitness,
- typename Simplex >
- bool all_faces_in(Simplex& simplex,
- double* filtration_value,
- SimplicialComplexForWitness& sc) {
- typedef typename SimplicialComplexForWitness::Simplex_handle Simplex_handle;
-
- if (simplex.size() == 1)
- return true; /* Add vertices unconditionally */
-
- Simplex facet;
- for (typename Simplex::iterator not_it = simplex.begin(); not_it != simplex.end(); ++not_it) {
- facet.clear();
- for (typename Simplex::iterator it = simplex.begin(); it != simplex.end(); ++it)
- if (it != not_it)
- facet.push_back(*it);
- Simplex_handle facet_sh = sc.find(facet);
- if (facet_sh == sc.null_simplex())
- return false;
- else if (sc.filtration(facet_sh) > *filtration_value)
- *filtration_value = sc.filtration(facet_sh);
- }
- return true;
- }
-
-#endif // WITNESS_COMPLEX_ALL_FACES_IN_H_
diff --git a/include/gudhi/allocator.h b/include/gudhi/allocator.h
deleted file mode 100644
index 3de16a49..00000000
--- a/include/gudhi/allocator.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Marc Glisse
- *
- * Copyright (C) 2015 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ALLOCATOR_H_
-#define ALLOCATOR_H_
-
-#include <memory>
-#include <utility>
-
-namespace Gudhi {
-
-/** \private
- * An allocator that can be used to build an uninitialized vector.
- */
-template <class T, class Base = std::allocator<T>>
-struct no_init_allocator : Base {
- typedef std::allocator_traits<Base> Base_traits;
- template <class U> struct rebind {
- typedef no_init_allocator<U, typename Base_traits::template rebind_alloc<U>> other;
- };
-
- // Inherit constructors.
- using Base::Base;
-
- // Do nothing: that's the whole point!
- template<class P>
- void construct(P*) noexcept {}
-
- template<class P, class...U> void construct(P*p, U&&...u) {
- Base_traits::construct(*(Base*)this, p, std::forward<U>(u)...);
- }
-};
-
-} // namespace Gudhi
-
-#endif // ALLOCATOR_H_
diff --git a/include/gudhi/choose_n_farthest_points.h b/include/gudhi/choose_n_farthest_points.h
deleted file mode 100644
index ab1c4c73..00000000
--- a/include/gudhi/choose_n_farthest_points.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CHOOSE_N_FARTHEST_POINTS_H_
-#define CHOOSE_N_FARTHEST_POINTS_H_
-
-#include <boost/range.hpp>
-
-#include <gudhi/Null_output_iterator.h>
-
-#include <iterator>
-#include <vector>
-#include <random>
-#include <limits> // for numeric_limits<>
-
-namespace Gudhi {
-
-namespace subsampling {
-
-/**
- * \ingroup subsampling
- */
-enum : std::size_t {
-/**
- * Argument for `choose_n_farthest_points` to indicate that the starting point should be picked randomly.
- */
- random_starting_point = std::size_t(-1)
-};
-
-/**
- * \ingroup subsampling
- * \brief Subsample by a greedy strategy of iteratively adding the farthest point from the
- * current chosen point set to the subsampling.
- * The iteration starts with the landmark `starting point` or, if `starting point==random_starting_point`, with a random landmark.
- * \tparam Kernel must provide a type Kernel::Squared_distance_d which is a model of the
- * concept <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classKernel__d_1_1Squared__distance__d.html">Kernel_d::Squared_distance_d</a> (despite the name, taken from CGAL, this can be any kind of metric or proximity measure).
- * It must also contain a public member `squared_distance_d_object()` that returns an object of this type.
- * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access
- * via `operator[]` and the points should be stored contiguously in memory.
- * \tparam PointOutputIterator Output iterator whose value type is Kernel::Point_d.
- * \tparam DistanceOutputIterator Output iterator for distances.
- * \details It chooses `final_size` points from a random access range
- * `input_pts` and outputs them in the output iterator `output_it`. It also
- * outputs the distance from each of those points to the set of previous
- * points in `dist_it`.
- * @param[in] k A kernel object.
- * @param[in] input_pts Const reference to the input points.
- * @param[in] final_size The size of the subsample to compute.
- * @param[in] starting_point The seed in the farthest point algorithm.
- * @param[out] output_it The output iterator for points.
- * @param[out] dist_it The optional output iterator for distances.
- *
- */
-template < typename Kernel,
-typename Point_range,
-typename PointOutputIterator,
-typename DistanceOutputIterator = Null_output_iterator>
-void choose_n_farthest_points(Kernel const &k,
- Point_range const &input_pts,
- std::size_t final_size,
- std::size_t starting_point,
- PointOutputIterator output_it,
- DistanceOutputIterator dist_it = {}) {
- std::size_t nb_points = boost::size(input_pts);
- if (final_size > nb_points)
- final_size = nb_points;
-
- // Tests to the limit
- if (final_size < 1)
- return;
-
- if (starting_point == random_starting_point) {
- // Choose randomly the first landmark
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_int_distribution<std::size_t> dis(0, nb_points - 1);
- starting_point = dis(gen);
- }
-
- typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
-
- std::size_t current_number_of_landmarks = 0; // counter for landmarks
- const double infty = std::numeric_limits<double>::infinity(); // infinity (see next entry)
- std::vector< double > dist_to_L(nb_points, infty); // vector of current distances to L from input_pts
-
- std::size_t curr_max_w = starting_point;
-
- for (current_number_of_landmarks = 0; current_number_of_landmarks != final_size; current_number_of_landmarks++) {
- // curr_max_w at this point is the next landmark
- *output_it++ = input_pts[curr_max_w];
- *dist_it++ = dist_to_L[curr_max_w];
- std::size_t i = 0;
- for (auto&& p : input_pts) {
- double curr_dist = sqdist(p, *(std::begin(input_pts) + curr_max_w));
- if (curr_dist < dist_to_L[i])
- dist_to_L[i] = curr_dist;
- ++i;
- }
- // choose the next curr_max_w
- double curr_max_dist = 0; // used for defining the furhest point from L
- for (i = 0; i < dist_to_L.size(); i++)
- if (dist_to_L[i] > curr_max_dist) {
- curr_max_dist = dist_to_L[i];
- curr_max_w = i;
- }
- }
-}
-
-} // namespace subsampling
-
-} // namespace Gudhi
-
-#endif // CHOOSE_N_FARTHEST_POINTS_H_
diff --git a/include/gudhi/common_persistence_representations.h b/include/gudhi/common_persistence_representations.h
deleted file mode 100644
index 3d03f1f6..00000000
--- a/include/gudhi/common_persistence_representations.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef COMMON_PERSISTENCE_REPRESENTATIONS_H_
-#define COMMON_PERSISTENCE_REPRESENTATIONS_H_
-
-#include <utility>
-#include <string>
-#include <cmath>
-
-namespace Gudhi {
-namespace Persistence_representations {
-// this file contain an implementation of some common procedures used in Persistence_representations.
-
-// double epsi = std::numeric_limits<double>::epsilon();
-double epsi = 0.000005;
-
-/**
- * A procedure used to compare doubles. Typically given two doubles A and B, comparing A == B is not good idea. In this
- *case, we use the procedure almostEqual with the epsi defined at
- * the top of the file. Setting up the epsi gives the user a tolerance on what should be consider equal.
-**/
-inline bool almost_equal(double a, double b) {
- if (std::fabs(a - b) < epsi) return true;
- return false;
-}
-
-// landscapes
-/**
- * Extra functions needed in construction of barcodes.
-**/
-double minus_length(std::pair<double, double> a) { return a.first - a.second; }
-double birth_plus_deaths(std::pair<double, double> a) { return a.first + a.second; }
-
-// landscapes
-/**
- * Given two points in R^2, the procedure compute the parameters A and B of the line y = Ax + B that crosses those two
- *points.
-**/
-std::pair<double, double> compute_parameters_of_a_line(std::pair<double, double> p1, std::pair<double, double> p2) {
- double a = (p2.second - p1.second) / (p2.first - p1.first);
- double b = p1.second - a * p1.first;
- return std::make_pair(a, b);
-}
-
-// landscapes
-/**
- * This procedure given two points which lies on the opposite sides of x axis, compute x for which the line connecting
- *those two points crosses x axis.
-**/
-double find_zero_of_a_line_segment_between_those_two_points(std::pair<double, double> p1,
- std::pair<double, double> p2) {
- if (p1.first == p2.first) return p1.first;
- if (p1.second * p2.second > 0) {
- std::ostringstream errMessage;
- errMessage << "In function find_zero_of_a_line_segment_between_those_two_points the arguments are: (" << p1.first
- << "," << p1.second << ") and (" << p2.first << "," << p2.second
- << "). There is no zero in line between those two points. Program terminated.";
- std::string errMessageStr = errMessage.str();
- const char* err = errMessageStr.c_str();
- throw(err);
- }
- // we assume here, that x \in [ p1.first, p2.first ] and p1 and p2 are points between which we will put the line
- // segment
- double a = (p2.second - p1.second) / (p2.first - p1.first);
- double b = p1.second - a * p1.first;
- return -b / a;
-}
-
-// landscapes
-/**
- * This method provides a comparison of points that is used in construction of persistence landscapes. The ordering is
- *lexicographical for the first coordinate, and reverse-lexicographical for the
- * second coordinate.
-**/
-bool compare_points_sorting(std::pair<double, double> f, std::pair<double, double> s) {
- if (f.first < s.first) {
- return true;
- } else { // f.first >= s.first
- if (f.first > s.first) {
- return false;
- } else { // f.first == s.first
- if (f.second > s.second) {
- return true;
- } else {
- return false;
- }
- }
- }
-}
-
-// landscapes
-/**
- * This procedure takes two points in R^2 and a double value x. It computes the line parsing through those two points
- *and return the value of that linear function at x.
-**/
-double function_value(std::pair<double, double> p1, std::pair<double, double> p2, double x) {
- // we assume here, that x \in [ p1.first, p2.first ] and p1 and p2 are points between which we will put the line
- // segment
- double a = (p2.second - p1.second) / (p2.first - p1.first);
- double b = p1.second - a * p1.first;
- return (a * x + b);
-}
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // COMMON_PERSISTENCE_REPRESENTATIONS_H_
diff --git a/include/gudhi/console_color.h b/include/gudhi/console_color.h
deleted file mode 100644
index a493e0d0..00000000
--- a/include/gudhi/console_color.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef CONSOLE_COLOR_H_
-#define CONSOLE_COLOR_H_
-
-#include <iostream>
-
-#if defined(WIN32)
-#include <windows.h>
-#endif
-
-inline std::ostream& blue(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout,
- FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
-#else
- s << "\x1b[0;34m";
-#endif
- return s;
-}
-
-inline std::ostream& red(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_INTENSITY);
-#else
- s << "\x1b[0;31m";
-#endif
- return s;
-}
-
-inline std::ostream& green(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
-#else
- s << "\x1b[0;32m";
-#endif
- return s;
-}
-
-inline std::ostream& yellow(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout,
- FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
-#else
- s << "\x1b[0;33m";
-#endif
- return s;
-}
-
-inline std::ostream& white(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout,
- FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
-#else
- s << "\x1b[0;37m";
-#endif
- return s;
-}
-
-inline std::ostream& black_on_white(std::ostream &s) {
-#if defined(WIN32)
- HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(hStdout,
- BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
-#else
- s << "\x1b[0;33m";
-#endif
- return s;
-}
-
-
-#endif // CONSOLE_COLOR_H_
diff --git a/include/gudhi/distance_functions.h b/include/gudhi/distance_functions.h
deleted file mode 100644
index 5ef12f2e..00000000
--- a/include/gudhi/distance_functions.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef DISTANCE_FUNCTIONS_H_
-#define DISTANCE_FUNCTIONS_H_
-
-#include <gudhi/Debug_utils.h>
-
-#include <gudhi/Miniball.hpp>
-
-#include <boost/range/metafunctions.hpp>
-#include <boost/range/size.hpp>
-
-#include <cmath> // for std::sqrt
-#include <type_traits> // for std::decay
-#include <iterator> // for std::begin, std::end
-#include <utility>
-
-namespace Gudhi {
-
-/** @file
- * @brief Global distance functions
- */
-
-/** @brief Compute the Euclidean distance between two Points given by a range of coordinates. The points are assumed to
- * have the same dimension. */
-class Euclidean_distance {
- public:
- // boost::range_value is not SFINAE-friendly so we cannot use it in the return type
- template< typename Point >
- typename std::iterator_traits<typename boost::range_iterator<Point>::type>::value_type
- operator()(const Point& p1, const Point& p2) const {
- auto it1 = std::begin(p1);
- auto it2 = std::begin(p2);
- typedef typename boost::range_value<Point>::type NT;
- NT dist = 0;
- for (; it1 != std::end(p1); ++it1, ++it2) {
- GUDHI_CHECK(it2 != std::end(p2), "inconsistent point dimensions");
- NT tmp = *it1 - *it2;
- dist += tmp*tmp;
- }
- GUDHI_CHECK(it2 == std::end(p2), "inconsistent point dimensions");
- using std::sqrt;
- return sqrt(dist);
- }
- template< typename T >
- T operator() (const std::pair< T, T >& f, const std::pair< T, T >& s) const {
- T dx = f.first - s.first;
- T dy = f.second - s.second;
- using std::sqrt;
- return sqrt(dx*dx + dy*dy);
- }
-};
-
-/** @brief Compute the radius of the minimal enclosing ball between Points given by a range of coordinates.
- * The points are assumed to have the same dimension. */
-class Minimal_enclosing_ball_radius {
- public:
- /** \brief Minimal_enclosing_ball_radius from two points.
- *
- * @param[in] point_1 First point.
- * @param[in] point_2 second point.
- * @return The minimal enclosing ball radius for the two points (aka. Euclidean distance / 2.).
- *
- * \tparam Point must be a range of Cartesian coordinates.
- *
- */
- template< typename Point >
- typename std::iterator_traits<typename boost::range_iterator<Point>::type>::value_type
- operator()(const Point& point_1, const Point& point_2) const {
- return Euclidean_distance()(point_1, point_2) / 2.;
- }
- /** \brief Minimal_enclosing_ball_radius from a point cloud.
- *
- * @param[in] point_cloud The points.
- * @return The minimal enclosing ball radius for the points.
- *
- * \tparam Point_cloud must be a range of points with Cartesian coordinates.
- * Point_cloud is a range over a range of Coordinate.
- *
- */
- template< typename Point_cloud,
- typename Point_iterator = typename boost::range_const_iterator<Point_cloud>::type,
- typename Point = typename std::iterator_traits<Point_iterator>::value_type,
- typename Coordinate_iterator = typename boost::range_const_iterator<Point>::type,
- typename Coordinate = typename std::iterator_traits<Coordinate_iterator>::value_type>
- Coordinate
- operator()(const Point_cloud& point_cloud) const {
- using Min_sphere = Miniball::Miniball<Miniball::CoordAccessor<Point_iterator, Coordinate_iterator>>;
-
- Min_sphere ms(boost::size(*point_cloud.begin()), point_cloud.begin(), point_cloud.end());
-#ifdef DEBUG_TRACES
- std::cout << "Minimal_enclosing_ball_radius = " << std::sqrt(ms.squared_radius()) << " | nb points = "
- << boost::size(point_cloud) << " | dimension = "
- << boost::size(*point_cloud.begin()) << std::endl;
-#endif // DEBUG_TRACES
-
- return std::sqrt(ms.squared_radius());
- }
-};
-
-} // namespace Gudhi
-
-#endif // DISTANCE_FUNCTIONS_H_
diff --git a/include/gudhi/graph_simplicial_complex.h b/include/gudhi/graph_simplicial_complex.h
deleted file mode 100644
index 49fe56cc..00000000
--- a/include/gudhi/graph_simplicial_complex.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clément Maria
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GRAPH_SIMPLICIAL_COMPLEX_H_
-#define GRAPH_SIMPLICIAL_COMPLEX_H_
-
-#include <boost/graph/adjacency_list.hpp>
-
-#include <utility> // for pair<>
-#include <vector>
-#include <map>
-#include <tuple> // for std::tie
-
-namespace Gudhi {
-
-/* Edge tag for Boost PropertyGraph. */
-struct edge_filtration_t {
- typedef boost::edge_property_tag kind;
-};
-
-/* Vertex tag for Boost PropertyGraph. */
-struct vertex_filtration_t {
- typedef boost::vertex_property_tag kind;
-};
-
-/** \brief Proximity_graph contains the vertices and edges with their filtration values in order to store the result
- * of `Gudhi::compute_proximity_graph` function.
- *
- * \tparam SimplicialComplexForProximityGraph furnishes `Filtration_value` type definition.
- *
- */
-template <typename SimplicialComplexForProximityGraph>
-using Proximity_graph = typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS
-, boost::property < vertex_filtration_t, typename SimplicialComplexForProximityGraph::Filtration_value >
-, boost::property < edge_filtration_t, typename SimplicialComplexForProximityGraph::Filtration_value >>;
-
-/** \brief Computes the proximity graph of the points.
- *
- * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the
- * distance function between points u and v is smaller than threshold.
- *
- * \tparam ForwardPointRange furnishes `.begin()` and `.end()` methods.
- *
- * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where
- * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`.
- */
-template< typename SimplicialComplexForProximityGraph
- , typename ForwardPointRange
- , typename Distance >
-Proximity_graph<SimplicialComplexForProximityGraph> compute_proximity_graph(
- const ForwardPointRange& points,
- typename SimplicialComplexForProximityGraph::Filtration_value threshold,
- Distance distance) {
- using Vertex_handle = typename SimplicialComplexForProximityGraph::Vertex_handle;
- using Filtration_value = typename SimplicialComplexForProximityGraph::Filtration_value;
-
- std::vector<std::pair< Vertex_handle, Vertex_handle >> edges;
- std::vector< Filtration_value > edges_fil;
- std::map< Vertex_handle, Filtration_value > vertices;
-
- Vertex_handle idx_u, idx_v;
- Filtration_value fil;
- idx_u = 0;
- for (auto it_u = points.begin(); it_u != points.end(); ++it_u) {
- idx_v = idx_u + 1;
- for (auto it_v = it_u + 1; it_v != points.end(); ++it_v, ++idx_v) {
- fil = distance(*it_u, *it_v);
- if (fil <= threshold) {
- edges.emplace_back(idx_u, idx_v);
- edges_fil.push_back(fil);
- }
- }
- ++idx_u;
- }
-
- // Points are labeled from 0 to idx_u-1
- Proximity_graph<SimplicialComplexForProximityGraph> skel_graph(edges.begin(), edges.end(), edges_fil.begin(), idx_u);
-
- auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph);
-
- typename boost::graph_traits<Proximity_graph<SimplicialComplexForProximityGraph>>::vertex_iterator vi, vi_end;
- for (std::tie(vi, vi_end) = boost::vertices(skel_graph);
- vi != vi_end; ++vi) {
- boost::put(vertex_prop, *vi, 0.);
- }
-
- return skel_graph;
-}
-
-} // namespace Gudhi
-
-#endif // GRAPH_SIMPLICIAL_COMPLEX_H_
diff --git a/include/gudhi/pick_n_random_points.h b/include/gudhi/pick_n_random_points.h
deleted file mode 100644
index 64821e5d..00000000
--- a/include/gudhi/pick_n_random_points.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Siargey Kachanovich
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef PICK_N_RANDOM_POINTS_H_
-#define PICK_N_RANDOM_POINTS_H_
-
-#include <gudhi/Clock.h>
-
-#include <boost/range/size.hpp>
-
-#include <cstddef>
-#include <random> // random_device, mt19937
-#include <algorithm> // shuffle
-#include <numeric> // iota
-#include <iterator>
-#include <vector>
-
-
-namespace Gudhi {
-
-namespace subsampling {
-
-/**
- * \ingroup subsampling
- * \brief Subsample a point set by picking random vertices.
- *
- * \details It chooses `final_size` distinct points from a random access range `points`
- * and outputs them to the output iterator `output_it`.
- * Point_container::iterator should be ValueSwappable and RandomAccessIterator.
- */
-template <typename Point_container,
-typename OutputIterator>
-void pick_n_random_points(Point_container const &points,
- std::size_t final_size,
- OutputIterator output_it) {
-#ifdef GUDHI_SUBSAMPLING_PROFILING
- Gudhi::Clock t;
-#endif
-
- std::size_t nbP = boost::size(points);
- if (final_size > nbP)
- final_size = nbP;
-
- std::vector<int> landmarks(nbP);
- std::iota(landmarks.begin(), landmarks.end(), 0);
-
- std::random_device rd;
- std::mt19937 g(rd());
-
- std::shuffle(landmarks.begin(), landmarks.end(), g);
- landmarks.resize(final_size);
-
- for (int l : landmarks)
- *output_it++ = points[l];
-
-#ifdef GUDHI_SUBSAMPLING_PROFILING
- t.end();
- std::cerr << "Random landmark choice took " << t.num_seconds()
- << " seconds." << std::endl;
-#endif
-}
-
-} // namespace subsampling
-
-} // namespace Gudhi
-
-#endif // PICK_N_RANDOM_POINTS_H_
diff --git a/include/gudhi/random_point_generators.h b/include/gudhi/random_point_generators.h
deleted file mode 100644
index f8107c8b..00000000
--- a/include/gudhi/random_point_generators.h
+++ /dev/null
@@ -1,507 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef RANDOM_POINT_GENERATORS_H_
-#define RANDOM_POINT_GENERATORS_H_
-
-#include <CGAL/number_utils.h>
-#include <CGAL/Random.h>
-#include <CGAL/point_generators_d.h>
-
-#include <vector> // for vector<>
-
-namespace Gudhi {
-
-///////////////////////////////////////////////////////////////////////////////
-// Note: All these functions have been tested with the CGAL::Epick_d kernel
-///////////////////////////////////////////////////////////////////////////////
-
-// construct_point: dim 2
-
-template <typename Kernel>
-typename Kernel::Point_d construct_point(const Kernel &k,
- typename Kernel::FT x1, typename Kernel::FT x2) {
- typename Kernel::FT tab[2];
- tab[0] = x1;
- tab[1] = x2;
- return k.construct_point_d_object()(2, &tab[0], &tab[2]);
-}
-
-// construct_point: dim 3
-
-template <typename Kernel>
-typename Kernel::Point_d construct_point(const Kernel &k,
- typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3) {
- typename Kernel::FT tab[3];
- tab[0] = x1;
- tab[1] = x2;
- tab[2] = x3;
- return k.construct_point_d_object()(3, &tab[0], &tab[3]);
-}
-
-// construct_point: dim 4
-
-template <typename Kernel>
-typename Kernel::Point_d construct_point(const Kernel &k,
- typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
- typename Kernel::FT x4) {
- typename Kernel::FT tab[4];
- tab[0] = x1;
- tab[1] = x2;
- tab[2] = x3;
- tab[3] = x4;
- return k.construct_point_d_object()(4, &tab[0], &tab[4]);
-}
-
-// construct_point: dim 5
-
-template <typename Kernel>
-typename Kernel::Point_d construct_point(const Kernel &k,
- typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
- typename Kernel::FT x4, typename Kernel::FT x5) {
- typename Kernel::FT tab[5];
- tab[0] = x1;
- tab[1] = x2;
- tab[2] = x3;
- tab[3] = x4;
- tab[4] = x5;
- return k.construct_point_d_object()(5, &tab[0], &tab[5]);
-}
-
-// construct_point: dim 6
-
-template <typename Kernel>
-typename Kernel::Point_d construct_point(const Kernel &k,
- typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
- typename Kernel::FT x4, typename Kernel::FT x5, typename Kernel::FT x6) {
- typename Kernel::FT tab[6];
- tab[0] = x1;
- tab[1] = x2;
- tab[2] = x3;
- tab[3] = x4;
- tab[4] = x5;
- tab[5] = x6;
- return k.construct_point_d_object()(6, &tab[0], &tab[6]);
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_plane(std::size_t num_points, int intrinsic_dim,
- int ambient_dim,
- double coord_min = -5., double coord_max = 5.) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- std::vector<FT> pt(ambient_dim, FT(0));
- for (int j = 0; j < intrinsic_dim; ++j)
- pt[j] = rng.get_double(coord_min, coord_max);
-
- Point p = k.construct_point_d_object()(ambient_dim, pt.begin(), pt.end());
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_moment_curve(std::size_t num_points, int dim,
- typename Kernel::FT min_x,
- typename Kernel::FT max_x) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- FT x = rng.get_double(min_x, max_x);
- std::vector<FT> coords;
- coords.reserve(dim);
- for (int p = 1; p <= dim; ++p)
- coords.push_back(std::pow(CGAL::to_double(x), p));
- Point p = k.construct_point_d_object()(
- dim, coords.begin(), coords.end());
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-
-// R = big radius, r = small radius
-template <typename Kernel/*, typename TC_basis*/>
-std::vector<typename Kernel::Point_d> generate_points_on_torus_3D(std::size_t num_points, double R, double r,
- bool uniform = false) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
-
- // if uniform
- std::size_t num_lines = (std::size_t)sqrt(num_points);
-
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- FT u, v;
- if (uniform) {
- std::size_t k1 = i / num_lines;
- std::size_t k2 = i % num_lines;
- u = 6.2832 * k1 / num_lines;
- v = 6.2832 * k2 / num_lines;
- } else {
- u = rng.get_double(0, 6.2832);
- v = rng.get_double(0, 6.2832);
- }
- Point p = construct_point(k,
- (R + r * std::cos(u)) * std::cos(v),
- (R + r * std::cos(u)) * std::sin(v),
- r * std::sin(u));
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-// "Private" function used by generate_points_on_torus_d
-template <typename Kernel, typename OutputIterator>
-static void generate_uniform_points_on_torus_d(const Kernel &k, int dim, std::size_t num_slices,
- OutputIterator out,
- double radius_noise_percentage = 0.,
- std::vector<typename Kernel::FT> current_point =
- std::vector<typename Kernel::FT>()) {
- CGAL::Random rng;
- int point_size = static_cast<int>(current_point.size());
- if (point_size == 2 * dim) {
- *out++ = k.construct_point_d_object()(point_size, current_point.begin(), current_point.end());
- } else {
- for (std::size_t slice_idx = 0; slice_idx < num_slices; ++slice_idx) {
- double radius_noise_ratio = 1.;
- if (radius_noise_percentage > 0.) {
- radius_noise_ratio = rng.get_double(
- (100. - radius_noise_percentage) / 100.,
- (100. + radius_noise_percentage) / 100.);
- }
- std::vector<typename Kernel::FT> cp2 = current_point;
- double alpha = 6.2832 * slice_idx / num_slices;
- cp2.push_back(radius_noise_ratio * std::cos(alpha));
- cp2.push_back(radius_noise_ratio * std::sin(alpha));
- generate_uniform_points_on_torus_d(
- k, dim, num_slices, out, radius_noise_percentage, cp2);
- }
- }
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_torus_d(std::size_t num_points, int dim, bool uniform = false,
- double radius_noise_percentage = 0.) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
-
- std::vector<Point> points;
- points.reserve(num_points);
- if (uniform) {
- std::size_t num_slices = (std::size_t)std::pow(num_points, 1. / dim);
- generate_uniform_points_on_torus_d(
- k, dim, num_slices, std::back_inserter(points), radius_noise_percentage);
- } else {
- for (std::size_t i = 0; i < num_points;) {
- double radius_noise_ratio = 1.;
- if (radius_noise_percentage > 0.) {
- radius_noise_ratio = rng.get_double(
- (100. - radius_noise_percentage) / 100.,
- (100. + radius_noise_percentage) / 100.);
- }
- std::vector<typename Kernel::FT> pt;
- pt.reserve(dim * 2);
- for (int curdim = 0; curdim < dim; ++curdim) {
- FT alpha = rng.get_double(0, 6.2832);
- pt.push_back(radius_noise_ratio * std::cos(alpha));
- pt.push_back(radius_noise_ratio * std::sin(alpha));
- }
-
- Point p = k.construct_point_d_object()(pt.begin(), pt.end());
- points.push_back(p);
- ++i;
- }
- }
- return points;
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_sphere_d(std::size_t num_points, int dim, double radius,
- double radius_noise_percentage = 0.) {
- typedef typename Kernel::Point_d Point;
- Kernel k;
- CGAL::Random rng;
- CGAL::Random_points_on_sphere_d<Point> generator(dim, radius);
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- Point p = *generator++;
- if (radius_noise_percentage > 0.) {
- double radius_noise_ratio = rng.get_double(
- (100. - radius_noise_percentage) / 100.,
- (100. + radius_noise_percentage) / 100.);
-
- typename Kernel::Point_to_vector_d k_pt_to_vec =
- k.point_to_vector_d_object();
- typename Kernel::Vector_to_point_d k_vec_to_pt =
- k.vector_to_point_d_object();
- typename Kernel::Scaled_vector_d k_scaled_vec =
- k.scaled_vector_d_object();
- p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio));
- }
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_in_ball_d(std::size_t num_points, int dim, double radius) {
- typedef typename Kernel::Point_d Point;
- Kernel k;
- CGAL::Random rng;
- CGAL::Random_points_in_ball_d<Point> generator(dim, radius);
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- Point p = *generator++;
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_in_cube_d(std::size_t num_points, int dim, double radius) {
- typedef typename Kernel::Point_d Point;
- Kernel k;
- CGAL::Random rng;
- CGAL::Random_points_in_cube_d<Point> generator(dim, radius);
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- Point p = *generator++;
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_two_spheres_d(std::size_t num_points, int dim, double radius,
- double distance_between_centers,
- double radius_noise_percentage = 0.) {
- typedef typename Kernel::FT FT;
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::Vector_d Vector;
- Kernel k;
- CGAL::Random rng;
- CGAL::Random_points_on_sphere_d<Point> generator(dim, radius);
- std::vector<Point> points;
- points.reserve(num_points);
-
- std::vector<FT> t(dim, FT(0));
- t[0] = distance_between_centers;
- Vector c1_to_c2(t.begin(), t.end());
-
- for (std::size_t i = 0; i < num_points;) {
- Point p = *generator++;
- if (radius_noise_percentage > 0.) {
- double radius_noise_ratio = rng.get_double(
- (100. - radius_noise_percentage) / 100.,
- (100. + radius_noise_percentage) / 100.);
-
- typename Kernel::Point_to_vector_d k_pt_to_vec =
- k.point_to_vector_d_object();
- typename Kernel::Vector_to_point_d k_vec_to_pt =
- k.vector_to_point_d_object();
- typename Kernel::Scaled_vector_d k_scaled_vec =
- k.scaled_vector_d_object();
- p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio));
- }
-
- typename Kernel::Translated_point_d k_transl =
- k.translated_point_d_object();
- Point p2 = k_transl(p, c1_to_c2);
- points.push_back(p);
- points.push_back(p2);
- i += 2;
- }
- return points;
-}
-
-// Product of a 3-sphere and a circle => d = 3 / D = 5
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_3sphere_and_circle(std::size_t num_points,
- double sphere_radius) {
- typedef typename Kernel::FT FT;
- typedef typename Kernel::Point_d Point;
- Kernel k;
- CGAL::Random rng;
- CGAL::Random_points_on_sphere_d<Point> generator(3, sphere_radius);
- std::vector<Point> points;
- points.reserve(num_points);
-
- typename Kernel::Compute_coordinate_d k_coord =
- k.compute_coordinate_d_object();
- for (std::size_t i = 0; i < num_points;) {
- Point p_sphere = *generator++; // First 3 coords
-
- FT alpha = rng.get_double(0, 6.2832);
- std::vector<FT> pt(5);
- pt[0] = k_coord(p_sphere, 0);
- pt[1] = k_coord(p_sphere, 1);
- pt[2] = k_coord(p_sphere, 2);
- pt[3] = std::cos(alpha);
- pt[4] = std::sin(alpha);
- Point p(pt.begin(), pt.end());
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-// a = big radius, b = small radius
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_klein_bottle_3D(std::size_t num_points, double a, double b,
- bool uniform = false) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
-
- // if uniform
- std::size_t num_lines = (std::size_t)sqrt(num_points);
-
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- FT u, v;
- if (uniform) {
- std::size_t k1 = i / num_lines;
- std::size_t k2 = i % num_lines;
- u = 6.2832 * k1 / num_lines;
- v = 6.2832 * k2 / num_lines;
- } else {
- u = rng.get_double(0, 6.2832);
- v = rng.get_double(0, 6.2832);
- }
- double tmp = cos(u / 2) * sin(v) - sin(u / 2) * sin(2. * v);
- Point p = construct_point(k,
- (a + b * tmp) * cos(u),
- (a + b * tmp) * sin(u),
- b * (sin(u / 2) * sin(v) + cos(u / 2) * sin(2. * v)));
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-// a = big radius, b = small radius
-template <typename Kernel>
-std::vector<typename Kernel::Point_d> generate_points_on_klein_bottle_4D(std::size_t num_points, double a, double b,
- double noise = 0., bool uniform = false) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
-
- // if uniform
- std::size_t num_lines = (std::size_t)sqrt(num_points);
-
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- FT u, v;
- if (uniform) {
- std::size_t k1 = i / num_lines;
- std::size_t k2 = i % num_lines;
- u = 6.2832 * k1 / num_lines;
- v = 6.2832 * k2 / num_lines;
- } else {
- u = rng.get_double(0, 6.2832);
- v = rng.get_double(0, 6.2832);
- }
- Point p = construct_point(k,
- (a + b * cos(v)) * cos(u) + (noise == 0. ? 0. : rng.get_double(0, noise)),
- (a + b * cos(v)) * sin(u) + (noise == 0. ? 0. : rng.get_double(0, noise)),
- b * sin(v) * cos(u / 2) + (noise == 0. ? 0. : rng.get_double(0, noise)),
- b * sin(v) * sin(u / 2) + (noise == 0. ? 0. : rng.get_double(0, noise)));
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-
-// a = big radius, b = small radius
-
-template <typename Kernel>
-std::vector<typename Kernel::Point_d>
-generate_points_on_klein_bottle_variant_5D(
- std::size_t num_points, double a, double b, bool uniform = false) {
- typedef typename Kernel::Point_d Point;
- typedef typename Kernel::FT FT;
- Kernel k;
- CGAL::Random rng;
-
- // if uniform
- std::size_t num_lines = (std::size_t)sqrt(num_points);
-
- std::vector<Point> points;
- points.reserve(num_points);
- for (std::size_t i = 0; i < num_points;) {
- FT u, v;
- if (uniform) {
- std::size_t k1 = i / num_lines;
- std::size_t k2 = i % num_lines;
- u = 6.2832 * k1 / num_lines;
- v = 6.2832 * k2 / num_lines;
- } else {
- u = rng.get_double(0, 6.2832);
- v = rng.get_double(0, 6.2832);
- }
- FT x1 = (a + b * cos(v)) * cos(u);
- FT x2 = (a + b * cos(v)) * sin(u);
- FT x3 = b * sin(v) * cos(u / 2);
- FT x4 = b * sin(v) * sin(u / 2);
- FT x5 = x1 + x2 + x3 + x4;
-
- Point p = construct_point(k, x1, x2, x3, x4, x5);
- points.push_back(p);
- ++i;
- }
- return points;
-}
-
-} // namespace Gudhi
-
-#endif // RANDOM_POINT_GENERATORS_H_
diff --git a/include/gudhi/read_persistence_from_file.h b/include/gudhi/read_persistence_from_file.h
deleted file mode 100644
index 4a2b9d68..00000000
--- a/include/gudhi/read_persistence_from_file.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef READ_PERSISTENCE_FROM_FILE_H_
-#define READ_PERSISTENCE_FROM_FILE_H_
-
-#include <gudhi/reader_utils.h>
-
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <vector>
-#include <algorithm>
-#include <string>
-#include <utility>
-#include <limits> // for std::numeric_limits<>
-
-namespace Gudhi {
-namespace Persistence_representations {
-
-/**
- * Universal procedure to read files with persistence. It ignores the lines starting from # (treat them as comments).
- * It reads the fist line which is not a comment and assume that there are some numerical entries over there. The
- *program assume
- * that each other line in the file, which is not a comment, have the same number of numerical entries (2, 3 or 4).
- * If there are two numerical entries per line, then the function assume that they are birth/death coordinates.
- * If there are three numerical entries per line, then the function assume that they are: dimension and birth/death
- *coordinates.
- * If there are four numerical entries per line, then the function assume that they are: the characteristic of a filed
- *over which
- * persistence was computed, dimension and birth/death coordinates.
- * The 'inf' string can appear only as a last element of a line.
- * The procedure returns vector of persistence pairs.
-**/
-std::vector<std::pair<double, double> > read_persistence_intervals_in_one_dimension_from_file(
- std::string const& filename, int dimension = -1, double what_to_substitute_for_infinite_bar = -1) {
- bool dbg = false;
-
- std::string line;
- std::vector<std::pair<double, double> > barcode_initial =
- read_persistence_intervals_in_dimension(filename, static_cast<int>(dimension));
- std::vector<std::pair<double, double> > final_barcode;
- final_barcode.reserve(barcode_initial.size());
-
- if (dbg) {
- std::cerr << "Here are the intervals that we read from the file : \n";
- for (size_t i = 0; i != barcode_initial.size(); ++i) {
- std::cout << barcode_initial[i].first << " " << barcode_initial[i].second << std::endl;
- }
- getchar();
- }
-
- for (size_t i = 0; i != barcode_initial.size(); ++i) {
- if (dbg) {
- std::cout << "COnsidering interval : " << barcode_initial[i].first << " " << barcode_initial[i].second
- << std::endl;
- }
-
- if (barcode_initial[i].first > barcode_initial[i].second) {
- // note that in this case barcode_initial[i].second != std::numeric_limits<double>::infinity()
- if (dbg) std::cout << "Swap and enter \n";
- // swap them to make sure that birth < death
- final_barcode.push_back(std::pair<double, double>(barcode_initial[i].second, barcode_initial[i].first));
- continue;
- } else {
- if (barcode_initial[i].second != std::numeric_limits<double>::infinity()) {
- if (dbg) std::cout << "Simply enters\n";
- // in this case, due to the previous conditions we know that barcode_initial[i].first <
- // barcode_initial[i].second, so we put them as they are
- final_barcode.push_back(std::pair<double, double>(barcode_initial[i].first, barcode_initial[i].second));
- }
- }
-
- if ((barcode_initial[i].second == std::numeric_limits<double>::infinity()) &&
- (what_to_substitute_for_infinite_bar != -1)) {
- if (barcode_initial[i].first < what_to_substitute_for_infinite_bar) {
- // if only birth < death.
- final_barcode.push_back(
- std::pair<double, double>(barcode_initial[i].first, what_to_substitute_for_infinite_bar));
- }
- } else {
- // if the variable what_to_substitute_for_infinite_bar is not set, then we ignore all the infinite bars.
- }
- }
-
- if (dbg) {
- std::cerr << "Here are the final bars that we are sending further : \n";
- for (size_t i = 0; i != final_barcode.size(); ++i) {
- std::cout << final_barcode[i].first << " " << final_barcode[i].second << std::endl;
- }
- std::cerr << "final_barcode.size() : " << final_barcode.size() << std::endl;
- getchar();
- }
-
- return final_barcode;
-} // read_persistence_intervals_in_one_dimension_from_file
-
-} // namespace Persistence_representations
-} // namespace Gudhi
-
-#endif // READ_PERSISTENCE_FROM_FILE_H_
diff --git a/include/gudhi/reader_utils.h b/include/gudhi/reader_utils.h
deleted file mode 100644
index 26eeb76d..00000000
--- a/include/gudhi/reader_utils.h
+++ /dev/null
@@ -1,369 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Maria, Pawel Dlotko, Clement Jamin
- *
- * Copyright (C) 2014 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef READER_UTILS_H_
-#define READER_UTILS_H_
-
-#include <gudhi/graph_simplicial_complex.h>
-#include <gudhi/Debug_utils.h>
-
-#include <boost/function_output_iterator.hpp>
-#include <boost/graph/adjacency_list.hpp>
-
-#include <iostream>
-#include <fstream>
-#include <map>
-#include <limits> // for numeric_limits
-#include <string>
-#include <vector>
-#include <utility> // for pair
-#include <tuple> // for std::make_tuple
-
-namespace Gudhi {
-
-// Keep this file tag for Doxygen to parse the code, otherwise, functions are not documented.
-// It is required for global functions and variables.
-
-/** @file
- * @brief This file includes common file reader for GUDHI
- */
-
-/**
- * @brief Read a set of points to turn it into a vector< vector<double> > by filling points.
- *
- * File format: 1 point per line<br>
- * X11 X12 ... X1d<br>
- * X21 X22 ... X2d<br>
- * etc<br>
- */
-inline void read_points(std::string file_name, std::vector<std::vector<double>>& points) {
- std::ifstream in_file(file_name.c_str(), std::ios::in);
- if (!in_file.is_open()) {
- std::cerr << "Unable to open file " << file_name << std::endl;
- return;
- }
-
- std::string line;
- double x;
- while (getline(in_file, line)) {
- std::vector<double> point;
- std::istringstream iss(line);
- while (iss >> x) {
- point.push_back(x);
- }
- // Check for empty lines
- if (!point.empty()) points.push_back(point);
- }
- in_file.close();
-}
-
-/**
- * @brief Read a graph from a file.
- *
- * \tparam Graph_t Type for the return graph. Must be constructible from iterators on pairs of Vertex_handle
- * \tparam Filtration_value Type for the value of the read filtration
- * \tparam Vertex_handle Type for the value of the read vertices
- *
- * File format: 1 simplex per line<br>
- * Dim1 X11 X12 ... X1d Fil1<br>
- * Dim2 X21 X22 ... X2d Fil2<br>
- * etc<br>
- *
- * The vertices must be labeled from 0 to n-1.
- * Every simplex must appear exactly once.
- * Simplices of dimension more than 1 are ignored.
- */
-template <typename Graph_t, typename Filtration_value, typename Vertex_handle>
-Graph_t read_graph(std::string file_name) {
- std::ifstream in_(file_name.c_str(), std::ios::in);
- if (!in_.is_open()) {
- std::string error_str("read_graph - Unable to open file ");
- error_str.append(file_name);
- std::cerr << error_str << std::endl;
- throw std::invalid_argument(error_str);
- }
-
- typedef std::pair<Vertex_handle, Vertex_handle> Edge_t;
- std::vector<Edge_t> edges;
- std::vector<Filtration_value> edges_fil;
- std::map<Vertex_handle, Filtration_value> vertices;
-
- std::string line;
- int dim;
- Vertex_handle u, v, max_h = -1;
- Filtration_value fil;
- while (getline(in_, line)) {
- std::istringstream iss(line);
- while (iss >> dim) {
- switch (dim) {
- case 0: {
- iss >> u;
- iss >> fil;
- vertices[u] = fil;
- if (max_h < u) {
- max_h = u;
- }
- break;
- }
- case 1: {
- iss >> u;
- iss >> v;
- iss >> fil;
- edges.push_back(Edge_t(u, v));
- edges_fil.push_back(fil);
- break;
- }
- default: { break; }
- }
- }
- }
- in_.close();
-
- if ((size_t)(max_h + 1) != vertices.size()) {
- std::cerr << "Error: vertices must be labeled from 0 to n-1 \n";
- }
-
- Graph_t skel_graph(edges.begin(), edges.end(), edges_fil.begin(), vertices.size());
- auto vertex_prop = boost::get(vertex_filtration_t(), skel_graph);
-
- typename boost::graph_traits<Graph_t>::vertex_iterator vi, vi_end;
- auto v_it = vertices.begin();
- for (std::tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi, ++v_it) {
- boost::put(vertex_prop, *vi, v_it->second);
- }
-
- return skel_graph;
-}
-
-/**
- * @brief Read a face from a file.
- *
- * File format: 1 simplex per line<br>
- * Dim1 X11 X12 ... X1d Fil1<br>
- * Dim2 X21 X22 ... X2d Fil2<br>
- * etc<br>
- *
- * The vertices must be labeled from 0 to n-1.
- * Every simplex must appear exactly once.
- * Simplices of dimension more than 1 are ignored.
- */
-template <typename Vertex_handle, typename Filtration_value>
-bool read_simplex(std::istream& in_, std::vector<Vertex_handle>& simplex, Filtration_value& fil) {
- int dim = 0;
- if (!(in_ >> dim)) return false;
- Vertex_handle v;
- for (int i = 0; i < dim + 1; ++i) {
- in_ >> v;
- simplex.push_back(v);
- }
- in_ >> fil;
- in_.ignore((std::numeric_limits<std::streamsize>::max)(), '\n'); // ignore until the carriage return
- return true;
-}
-
-/**
- * @brief Read a hasse simplex from a file.
- *
- * File format: 1 simplex per line<br>
- * Dim1 k11 k12 ... k1Dim1 Fil1<br>
- * Dim2 k21 k22 ... k2Dim2 Fil2<br>
- * etc<br>
- *
- * The key of a simplex is its position in the filtration order and also the number of its row in the file.
- * Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the filtration has dimension Dimi, filtration value
- * fil1 and simplices with key ki1 ... kiDimi in its boundary.*/
-template <typename Simplex_key, typename Filtration_value>
-bool read_hasse_simplex(std::istream& in_, std::vector<Simplex_key>& boundary, Filtration_value& fil) {
- int dim;
- if (!(in_ >> dim)) return false;
- if (dim == 0) {
- in_ >> fil;
- return true;
- }
- Simplex_key key;
- for (int i = 0; i < dim + 1; ++i) {
- in_ >> key;
- boundary.push_back(key);
- }
- in_ >> fil;
- return true;
-}
-
-/**
- * @brief Read a lower triangular distance matrix from a csv file. We assume that the .csv store the whole
- * (square) matrix.
- *
- * @author Pawel Dlotko
- *
- * Square matrix file format:<br>
- * 0;D12;...;D1j<br>
- * D21;0;...;D2j<br>
- * ...<br>
- * Dj1;Dj2;...;0<br>
- *
- * lower matrix file format:<br>
- * 0<br>
- * D21;<br>
- * D31;D32;<br>
- * ...<br>
- * Dj1;Dj2;...;Dj(j-1);<br>
- *
- **/
-template <typename Filtration_value>
-std::vector<std::vector<Filtration_value>> read_lower_triangular_matrix_from_csv_file(const std::string& filename,
- const char separator = ';') {
-#ifdef DEBUG_TRACES
- std::cout << "Using procedure read_lower_triangular_matrix_from_csv_file \n";
-#endif // DEBUG_TRACES
- std::vector<std::vector<Filtration_value>> result;
- std::ifstream in;
- in.open(filename.c_str());
- if (!in.is_open()) {
- return result;
- }
-
- std::string line;
-
- // the first line is emtpy, so we ignore it:
- std::getline(in, line);
- std::vector<Filtration_value> values_in_this_line;
- result.push_back(values_in_this_line);
-
- int number_of_line = 0;
-
- // first, read the file line by line to a string:
- while (std::getline(in, line)) {
- // if line is empty, break
- if (line.size() == 0) break;
-
- // if the last element of a string is comma:
- if (line[line.size() - 1] == separator) {
- // then shrink the string by one
- line.pop_back();
- }
-
- // replace all commas with spaces
- std::replace(line.begin(), line.end(), separator, ' ');
-
- // put the new line to a stream
- std::istringstream iss(line);
- // and now read the doubles.
-
- int number_of_entry = 0;
- std::vector<Filtration_value> values_in_this_line;
- while (iss.good()) {
- double entry;
- iss >> entry;
- if (number_of_entry <= number_of_line) {
- values_in_this_line.push_back(entry);
- }
- ++number_of_entry;
- }
- if (!values_in_this_line.empty()) result.push_back(values_in_this_line);
- ++number_of_line;
- }
- in.close();
-
-#ifdef DEBUG_TRACES
- std::cerr << "Here is the matrix we read : \n";
- for (size_t i = 0; i != result.size(); ++i) {
- for (size_t j = 0; j != result[i].size(); ++j) {
- std::cerr << result[i][j] << " ";
- }
- std::cerr << std::endl;
- }
-#endif // DEBUG_TRACES
-
- return result;
-} // read_lower_triangular_matrix_from_csv_file
-
-/**
-Reads a file containing persistence intervals.
-Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
-The output iterator `out` is used this way: `*out++ = std::make_tuple(dim, birth, death);`
-where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
-Note: the function does not check that birth <= death.
-**/
-template <typename OutputIterator>
-void read_persistence_intervals_and_dimension(std::string const& filename, OutputIterator out) {
- std::ifstream in(filename);
- if (!in.is_open()) {
- std::string error_str("read_persistence_intervals_and_dimension - Unable to open file ");
- error_str.append(filename);
- std::cerr << error_str << std::endl;
- throw std::invalid_argument(error_str);
- }
-
- while (!in.eof()) {
- std::string line;
- getline(in, line);
- if (line.length() != 0 && line[0] != '#') {
- double numbers[4];
- int n = sscanf(line.c_str(), "%lf %lf %lf %lf", &numbers[0], &numbers[1], &numbers[2], &numbers[3]);
- if (n >= 2) {
- int dim = (n >= 3 ? static_cast<int>(numbers[n - 3]) : -1);
- *out++ = std::make_tuple(dim, numbers[n - 2], numbers[n - 1]);
- }
- }
- }
-}
-
-/**
-Reads a file containing persistence intervals.
-Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
-The return value is an `std::map<dim, std::vector<std::pair<birth, death>>>`
-where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
-Note: the function does not check that birth <= death.
-**/
-inline std::map<int, std::vector<std::pair<double, double>>> read_persistence_intervals_grouped_by_dimension(
- std::string const& filename) {
- std::map<int, std::vector<std::pair<double, double>>> ret;
- read_persistence_intervals_and_dimension(
- filename, boost::make_function_output_iterator([&ret](std::tuple<int, double, double> t) {
- ret[get<0>(t)].push_back(std::make_pair(get<1>(t), get<2>(t)));
- }));
- return ret;
-}
-
-/**
-Reads a file containing persistence intervals.
-Each line might contain 2, 3 or 4 values: [[field] dimension] birth death
-If `only_this_dim` = -1, dimension is ignored and all lines are returned.
-If `only_this_dim` is >= 0, only the lines where dimension = `only_this_dim`
-(or where dimension is not specified) are returned.
-The return value is an `std::vector<std::pair<birth, death>>`
-where `dim` is an `int`, `birth` a `double`, and `death` a `double`.
-Note: the function does not check that birth <= death.
-**/
-inline std::vector<std::pair<double, double>> read_persistence_intervals_in_dimension(std::string const& filename,
- int only_this_dim = -1) {
- std::vector<std::pair<double, double>> ret;
- read_persistence_intervals_and_dimension(
- filename, boost::make_function_output_iterator([only_this_dim, &ret](std::tuple<int, double, double> t) {
- if (only_this_dim == get<0>(t) || only_this_dim == -1) ret.emplace_back(get<1>(t), get<2>(t));
- }));
- return ret;
-}
-
-} // namespace Gudhi
-
-#endif // READER_UTILS_H_
diff --git a/include/gudhi/sparsify_point_set.h b/include/gudhi/sparsify_point_set.h
deleted file mode 100644
index db10e0b1..00000000
--- a/include/gudhi/sparsify_point_set.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Clement Jamin
- *
- * Copyright (C) 2016 Inria
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef SPARSIFY_POINT_SET_H_
-#define SPARSIFY_POINT_SET_H_
-
-#include <gudhi/Kd_tree_search.h>
-#ifdef GUDHI_SUBSAMPLING_PROFILING
-#include <gudhi/Clock.h>
-#endif
-
-#include <cstddef>
-#include <vector>
-
-namespace Gudhi {
-
-namespace subsampling {
-
-/**
- * \ingroup subsampling
- * \brief Outputs a subset of the input points so that the
- * squared distance between any two points
- * is greater than or equal to `min_squared_dist`.
- *
- * \tparam Kernel must be a model of the <a target="_blank"
- * href="http://doc.cgal.org/latest/Spatial_searching/classSearchTraits.html">SearchTraits</a>
- * concept, such as the <a target="_blank"
- * href="http://doc.cgal.org/latest/Kernel_d/classCGAL_1_1Epick__d.html">CGAL::Epick_d</a> class, which
- * can be static if you know the ambiant dimension at compile-time, or dynamic if you don't.
- * \tparam Point_range Range whose value type is Kernel::Point_d. It must provide random-access
- * via `operator[]` and the points should be stored contiguously in memory.
- * \tparam OutputIterator Output iterator whose value type is Kernel::Point_d.
- *
- * @param[in] k A kernel object.
- * @param[in] input_pts Const reference to the input points.
- * @param[in] min_squared_dist Minimum squared distance separating the output points.
- * @param[out] output_it The output iterator.
- */
-template <typename Kernel, typename Point_range, typename OutputIterator>
-void
-sparsify_point_set(
- const Kernel &k, Point_range const& input_pts,
- typename Kernel::FT min_squared_dist,
- OutputIterator output_it) {
- typedef typename Gudhi::spatial_searching::Kd_tree_search<
- Kernel, Point_range> Points_ds;
-
-#ifdef GUDHI_SUBSAMPLING_PROFILING
- Gudhi::Clock t;
-#endif
-
- Points_ds points_ds(input_pts);
-
- std::vector<bool> dropped_points(input_pts.size(), false);
-
- // Parse the input points, and add them if they are not too close to
- // the other points
- std::size_t pt_idx = 0;
- for (typename Point_range::const_iterator it_pt = input_pts.begin();
- it_pt != input_pts.end();
- ++it_pt, ++pt_idx) {
- if (dropped_points[pt_idx])
- continue;
-
- *output_it++ = *it_pt;
-
- auto ins_range = points_ds.incremental_nearest_neighbors(*it_pt);
-
- // If another point Q is closer that min_squared_dist, mark Q to be dropped
- for (auto const& neighbor : ins_range) {
- std::size_t neighbor_point_idx = neighbor.first;
- // If the neighbor is too close, we drop the neighbor
- if (neighbor.second < min_squared_dist) {
- // N.B.: If neighbor_point_idx < pt_idx,
- // dropped_points[neighbor_point_idx] is already true but adding a
- // test doesn't make things faster, so why bother?
- dropped_points[neighbor_point_idx] = true;
- } else {
- break;
- }
- }
- }
-
-#ifdef GUDHI_SUBSAMPLING_PROFILING
- t.end();
- std::cerr << "Point set sparsified in " << t.num_seconds()
- << " seconds." << std::endl;
-#endif
-}
-
-} // namespace subsampling
-} // namespace Gudhi
-
-#endif // SPARSIFY_POINT_SET_H_
diff --git a/include/gudhi/writing_persistence_to_file.h b/include/gudhi/writing_persistence_to_file.h
deleted file mode 100644
index 34448576..00000000
--- a/include/gudhi/writing_persistence_to_file.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This file is part of the Gudhi Library. The Gudhi library
- * (Geometric Understanding in Higher Dimensions) is a generic C++
- * library for computational topology.
- *
- * Author(s): Pawel Dlotko
- *
- * Copyright (C) 2017 Swansea University, UK
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef WRITING_PERSISTENCE_TO_FILE_H_
-#define WRITING_PERSISTENCE_TO_FILE_H_
-
-#include <iostream>
-#include <string>
-#include <limits>
-
-namespace Gudhi {
-
-/**
-* This is a class to store persistence intervals. Its main purpose is to
-* exchange data in between different packages and provide unified way
-* of writing a collection of persistence intervals to file.
-**/
-template <typename Filtration_type, typename Coefficient_field>
-class Persistence_interval_common {
- public:
- /**
- * Constructor taking as an input birth and death of the pair.
- **/
- Persistence_interval_common(Filtration_type birth, Filtration_type death)
- : birth_(birth),
- death_(death),
- dimension_(std::numeric_limits<unsigned>::max()),
- arith_element_(std::numeric_limits<Coefficient_field>::max()) {}
-
- /**
- * Constructor taking as an input birth, death and dimension of the pair.
- **/
- Persistence_interval_common(Filtration_type birth, Filtration_type death, unsigned dim)
- : birth_(birth), death_(death), dimension_(dim), arith_element_(std::numeric_limits<Coefficient_field>::max()) {}
-
- /**
-* Constructor taking as an input birth, death, dimension of the pair as well
-* as the number p such that this interval is present over Z_p field.
-**/
- Persistence_interval_common(Filtration_type birth, Filtration_type death, unsigned dim, Coefficient_field field)
- : birth_(birth), death_(death), dimension_(dim), arith_element_(field) {}
-
- /**
- * Operator to compare two persistence pairs. During the comparision all the
- * fields: birth, death, dimensiona and arith_element_ are taken into account
- * and they all have to be equal for two pairs to be equal.
- **/
- bool operator==(const Persistence_interval_common& i2) const {
- return ((this->birth_ == i2.birth_) && (this->death_ == i2.death_) && (this->dimension_ == i2.dimension_) &&
- (this->arith_element_ == i2.arith_element_));
- }
-
- /**
- * Check if two persistence paris are not equal.
- **/
- bool operator!=(const Persistence_interval_common& i2) const { return (!((*this) == i2)); }
-
- /**
- * Operator to compare objects of a type Persistence_interval_common.
- * One intervals is smaller than the other if it has lower persistence.
- * Note that this operator do not take Arith_element into account when doing comparisions.
- **/
- bool operator<(const Persistence_interval_common& i2) const {
- return fabs(this->death_ - this->birth_) < fabs(i2.death_ - i2.birth_);
- }
-
- friend std::ostream& operator<<(std::ostream& out, const Persistence_interval_common& it) {
- if (it.arith_element_ != std::numeric_limits<Coefficient_field>::max()) {
- out << it.arith_element_ << " ";
- }
- if (it.dimension_ != std::numeric_limits<unsigned>::max()) {
- out << it.dimension_ << " ";
- }
- out << it.birth_ << " " << it.death_ << " ";
- return out;
- }
-
- private:
- Filtration_type birth_;
- Filtration_type death_;
- unsigned dimension_;
- Coefficient_field arith_element_;
-};
-
-/**
- * This function write a vector<Persistence_interval_common> to a stream
-**/
-template <typename Persistence_interval_range>
-void write_persistence_intervals_to_stream(const Persistence_interval_range& intervals,
- std::ostream& out = std::cout) {
- for (auto interval : intervals) {
- out << interval << "\n";
- }
-}
-
-} // namespace Gudhi
-
-#endif // WRITING_PERSISTENCE_TO_FILE_H_