Sparse_rips_complex.h
1 /* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT.
2  * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details.
3  * Author(s): Marc Glisse
4  *
5  * Copyright (C) 2018 Inria
6  *
7  * Modification(s):
8  * - YYYY/MM Author: Description of the modification
9  */
10 
11 #ifndef SPARSE_RIPS_COMPLEX_H_
12 #define SPARSE_RIPS_COMPLEX_H_
13 
14 #include <gudhi/Debug_utils.h>
16 #include <gudhi/choose_n_farthest_points.h>
17 
18 #include <boost/graph/adjacency_list.hpp>
19 #include <boost/range/metafunctions.hpp>
20 
21 #include <vector>
22 
23 namespace Gudhi {
24 
25 namespace rips_complex {
26 
27 // The whole interface is copied on Rips_complex. A redesign should be discussed with all complex creation classes in
28 // mind.
29 
44 template <typename Filtration_value>
46  private:
47  // TODO(MG): use a different graph where we know we can safely insert in parallel.
48  typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
49  boost::property<vertex_filtration_t, Filtration_value>,
50  boost::property<edge_filtration_t, Filtration_value>>
51  Graph;
52 
53  typedef int Vertex_handle;
54 
55  public:
65  template <typename RandomAccessPointRange, typename Distance>
66  Sparse_rips_complex(const RandomAccessPointRange& points, Distance distance, double epsilon, Filtration_value mini=-std::numeric_limits<Filtration_value>::infinity(), Filtration_value maxi=std::numeric_limits<Filtration_value>::infinity())
67  : epsilon_(epsilon) {
68  GUDHI_CHECK(epsilon > 0, "epsilon must be positive");
69  auto dist_fun = [&](Vertex_handle i, Vertex_handle j) { return distance(points[i], points[j]); };
70  subsampling::choose_n_farthest_points(dist_fun, boost::irange<Vertex_handle>(0, boost::size(points)), -1, -1,
71  std::back_inserter(sorted_points), std::back_inserter(params));
72  compute_sparse_graph(dist_fun, epsilon, mini, maxi);
73  }
74 
85  template <typename DistanceMatrix>
86  Sparse_rips_complex(const DistanceMatrix& distance_matrix, double epsilon, Filtration_value mini=-std::numeric_limits<Filtration_value>::infinity(), Filtration_value maxi=std::numeric_limits<Filtration_value>::infinity())
87  : Sparse_rips_complex(boost::irange<Vertex_handle>(0, boost::size(distance_matrix)),
88  [&](Vertex_handle i, Vertex_handle j) { return (i==j) ? 0 : (i<j) ? distance_matrix[j][i] : distance_matrix[i][j]; },
89  epsilon, mini, maxi) {}
90 
101  template <typename SimplicialComplexForRips>
102  void create_complex(SimplicialComplexForRips& complex, int dim_max) {
103  GUDHI_CHECK(complex.num_vertices() == 0,
104  std::invalid_argument("Sparse_rips_complex::create_complex - simplicial complex is not empty"));
105 
106  complex.insert_graph(graph_);
107  if(epsilon_ >= 1) {
108  complex.expansion(dim_max);
109  return;
110  }
111  const int n = boost::size(params);
112  std::vector<Filtration_value> lambda(n);
113  // lambda[original_order]=params[sorted_order]
114  for(int i=0;i<n;++i)
115  lambda[sorted_points[i]] = params[i];
116  double cst = epsilon_ * (1 - epsilon_) / 2;
117  auto block = [cst,&complex,&lambda](typename SimplicialComplexForRips::Simplex_handle sh){
118  auto filt = complex.filtration(sh);
119  auto mini = filt * cst;
120  for(auto v : complex.simplex_vertex_range(sh)){
121  if(lambda[v] < mini)
122  return true; // v died before this simplex could be born
123  }
124  return false;
125  };
126  complex.expansion_with_blockers(dim_max, block);
127  }
128 
129  private:
130  // PointRange must be random access.
131  template <typename Distance>
132  void compute_sparse_graph(Distance& dist, double epsilon, Filtration_value mini, Filtration_value maxi) {
133  const auto& points = sorted_points; // convenience alias
134  const int n = boost::size(points);
135  double cst = epsilon * (1 - epsilon) / 2;
136  graph_.~Graph();
137  new (&graph_) Graph(n);
138  // for(auto v : vertices(g)) // doesn't work :-(
139  typename boost::graph_traits<Graph>::vertex_iterator v_i, v_e;
140  for (std::tie(v_i, v_e) = vertices(graph_); v_i != v_e; ++v_i) {
141  auto v = *v_i;
142  // This whole loop might not be necessary, leave it until someone investigates if it is safe to remove.
143  put(vertex_filtration_t(), graph_, v, 0);
144  }
145 
146  // TODO(MG):
147  // - make it parallel
148  // - only test near-enough neighbors
149  for (int i = 0; i < n; ++i) {
150  auto&& pi = points[i];
151  auto li = params[i];
152  if (li < mini) break;
153  for (int j = i + 1; j < n; ++j) {
154  auto&& pj = points[j];
155  auto d = dist(pi, pj);
156  auto lj = params[j];
157  if (lj < mini) break;
158  GUDHI_CHECK(lj <= li, "Bad furthest point sorting");
159  Filtration_value alpha;
160 
161  // The paper has d/2 and d-lj/e to match the Cech, but we use doubles to match the Rips
162  if (d * epsilon <= 2 * lj)
163  alpha = d;
164  else if (d * epsilon > li + lj)
165  continue;
166  else {
167  alpha = (d - lj / epsilon) * 2;
168  // Keep the test exactly the same as in block to avoid inconsistencies
169  if (epsilon < 1 && alpha * cst > lj)
170  continue;
171  }
172 
173  if (alpha <= maxi)
174  add_edge(pi, pj, alpha, graph_);
175  }
176  }
177  }
178 
179  Graph graph_;
180  double epsilon_;
181  // Because of the arbitrary split between constructor and create_complex
182  // sorted_points[sorted_order]=original_order
183  std::vector<Vertex_handle> sorted_points;
184  // params[sorted_order]=distance to previous points
185  std::vector<Filtration_value> params;
186 };
187 
188 } // namespace rips_complex
189 
190 } // namespace Gudhi
191 
192 #endif // SPARSE_RIPS_COMPLEX_H_
void expansion(int max_dim)
Expands the simplicial complex containing only its one skeleton until a given maximal dimension as ex...
void insert_graph(const OneSkeletonGraph &skel_graph)
Inserts a given Gudhi::rips_complex::Rips_complex::OneSkeletonGraph in the simplicial complex...
void choose_n_farthest_points(Distance dist, Point_range const &input_pts, std::size_t final_size, std::size_t starting_point, PointOutputIterator output_it, DistanceOutputIterator dist_it={})
Subsample by a greedy strategy of iteratively adding the farthest point from the current chosen point...
Definition: choose_n_farthest_points.h:69
The concept SimplicialComplexForRips describes the requirements for a type to implement a simplicial ...
Definition: SimplicialComplexForRips.h:21
Definition: SimplicialComplexForAlpha.h:14
Sparse_rips_complex(const DistanceMatrix &distance_matrix, double epsilon, Filtration_value mini=-std::numeric_limits< Filtration_value >::infinity(), Filtration_value maxi=std::numeric_limits< Filtration_value >::infinity())
Sparse_rips_complex constructor from a distance matrix.
Definition: Sparse_rips_complex.h:86
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20
Sparse_rips_complex(const RandomAccessPointRange &points, Distance distance, double epsilon, Filtration_value mini=-std::numeric_limits< Filtration_value >::infinity(), Filtration_value maxi=std::numeric_limits< Filtration_value >::infinity())
Sparse_rips_complex constructor from a list of points.
Definition: Sparse_rips_complex.h:66
std::size_t num_vertices()
Returns the number of vertices in the simplicial complex.
unspecified Simplex_handle
Handle type to a simplex contained in the simplicial complex.
Definition: SimplicialComplexForRips.h:26
Sparse Rips complex data structure.
Definition: Sparse_rips_complex.h:45
Graph simplicial complex methods.
void create_complex(SimplicialComplexForRips &complex, int dim_max)
Fills the simplicial complex with the sparse Rips graph and expands it with all the cliques...
Definition: Sparse_rips_complex.h:102
GUDHI  Version 3.4.1  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : MIT Generated on Fri Jan 22 2021 09:41:15 for GUDHI by Doxygen 1.8.13