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>
15 #include <gudhi/graph_simplicial_complex.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  Ker<decltype(dist_fun)> kernel(dist_fun);
71  subsampling::choose_n_farthest_points(kernel, boost::irange<Vertex_handle>(0, boost::size(points)), -1, -1,
72  std::back_inserter(sorted_points), std::back_inserter(params));
73  compute_sparse_graph(dist_fun, epsilon, mini, maxi);
74  }
75 
86  template <typename DistanceMatrix>
87  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())
88  : Sparse_rips_complex(boost::irange<Vertex_handle>(0, boost::size(distance_matrix)),
89  [&](Vertex_handle i, Vertex_handle j) { return (i==j) ? 0 : (i<j) ? distance_matrix[j][i] : distance_matrix[i][j]; },
90  epsilon, mini, maxi) {}
91 
102  template <typename SimplicialComplexForRips>
103  void create_complex(SimplicialComplexForRips& complex, int dim_max) {
104  GUDHI_CHECK(complex.num_vertices() == 0,
105  std::invalid_argument("Sparse_rips_complex::create_complex - simplicial complex is not empty"));
106 
107  complex.insert_graph(graph_);
108  if(epsilon_ >= 1) {
109  complex.expansion(dim_max);
110  return;
111  }
112  const int n = boost::size(params);
113  std::vector<Filtration_value> lambda(n);
114  // lambda[original_order]=params[sorted_order]
115  for(int i=0;i<n;++i)
116  lambda[sorted_points[i]] = params[i];
117  double cst = epsilon_ * (1 - epsilon_) / 2;
118  auto block = [cst,&complex,&lambda](typename SimplicialComplexForRips::Simplex_handle sh){
119  auto filt = complex.filtration(sh);
120  auto mini = filt * cst;
121  for(auto v : complex.simplex_vertex_range(sh)){
122  if(lambda[v] < mini)
123  return true; // v died before this simplex could be born
124  }
125  return false;
126  };
127  complex.expansion_with_blockers(dim_max, block);
128  }
129 
130  private:
131  // choose_n_farthest_points wants the distance function in this form...
132  template <class Distance>
133  struct Ker {
134  typedef std::size_t Point_d; // index into point range
135  Ker(Distance& d) : dist(d) {}
136  // Despite the name, this is not squared...
137  typedef Distance Squared_distance_d;
138  Squared_distance_d& squared_distance_d_object() const { return dist; }
139  Distance& dist;
140  };
141 
142  // PointRange must be random access.
143  template <typename Distance>
144  void compute_sparse_graph(Distance& dist, double epsilon, Filtration_value mini, Filtration_value maxi) {
145  const auto& points = sorted_points; // convenience alias
146  const int n = boost::size(points);
147  double cst = epsilon * (1 - epsilon) / 2;
148  graph_.~Graph();
149  new (&graph_) Graph(n);
150  // for(auto v : vertices(g)) // doesn't work :-(
151  typename boost::graph_traits<Graph>::vertex_iterator v_i, v_e;
152  for (std::tie(v_i, v_e) = vertices(graph_); v_i != v_e; ++v_i) {
153  auto v = *v_i;
154  // This whole loop might not be necessary, leave it until someone investigates if it is safe to remove.
155  put(vertex_filtration_t(), graph_, v, 0);
156  }
157 
158  // TODO(MG):
159  // - make it parallel
160  // - only test near-enough neighbors
161  for (int i = 0; i < n; ++i) {
162  auto&& pi = points[i];
163  auto li = params[i];
164  if (li < mini) break;
165  for (int j = i + 1; j < n; ++j) {
166  auto&& pj = points[j];
167  auto d = dist(pi, pj);
168  auto lj = params[j];
169  if (lj < mini) break;
170  GUDHI_CHECK(lj <= li, "Bad furthest point sorting");
171  Filtration_value alpha;
172 
173  // The paper has d/2 and d-lj/e to match the Cech, but we use doubles to match the Rips
174  if (d * epsilon <= 2 * lj)
175  alpha = d;
176  else if (d * epsilon > li + lj)
177  continue;
178  else {
179  alpha = (d - lj / epsilon) * 2;
180  // Keep the test exactly the same as in block to avoid inconsistencies
181  if (epsilon < 1 && alpha * cst > lj)
182  continue;
183  }
184 
185  if (alpha <= maxi)
186  add_edge(pi, pj, alpha, graph_);
187  }
188  }
189  }
190 
191  Graph graph_;
192  double epsilon_;
193  // Because of the arbitrary split between constructor and create_complex
194  // sorted_points[sorted_order]=original_order
195  std::vector<Vertex_handle> sorted_points;
196  // params[sorted_order]=distance to previous points
197  std::vector<Filtration_value> params;
198 };
199 
200 } // namespace rips_complex
201 
202 } // namespace Gudhi
203 
204 #endif // SPARSE_RIPS_COMPLEX_H_
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={})
Subsample by a greedy strategy of iteratively adding the farthest point from the current chosen point...
Definition: choose_n_farthest_points.h:66
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...
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:87
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
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:103
GUDHI  Version 3.1.1  - C++ library for Topological Data Analysis (TDA) and Higher Dimensional Geometry Understanding.  - Copyright : MIT Generated on Fri Feb 7 2020 16:35:36 for GUDHI by Doxygen 1.8.13