11#ifndef TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_
12#define TANGENTIAL_COMPLEX_SIMPLICIAL_COMPLEX_H_
14#include <gudhi/Tangential_complex/config.h>
15#include <gudhi/Tangential_complex/utilities.h>
16#include <gudhi/Debug_utils.h>
17#include <gudhi/console_color.h>
19#include <CGAL/iterator.h>
22#include <boost/graph/graph_traits.hpp>
23#include <boost/graph/adjacency_list.hpp>
24#include <boost/graph/connected_components.hpp>
25#include <boost/container/flat_set.hpp>
35namespace tangential_complex {
38class Simplicial_complex {
40 typedef boost::container::flat_set<std::size_t> Simplex;
41 typedef std::set<Simplex> Simplex_set;
48 const Simplex &s,
bool perform_checks =
true) {
50 unsigned int num_pts =
static_cast<int> (s.size());
51 std::vector<Complex::iterator> to_erase;
52 bool check_higher_dim_simpl =
true;
53 for (Complex::iterator it_simplex = m_complex.begin(),
54 it_simplex_end = m_complex.end();
55 it_simplex != it_simplex_end;
58 if (check_higher_dim_simpl
59 && it_simplex->size() > num_pts
60 && std::includes(it_simplex->begin(), it_simplex->end(),
61 s.begin(), s.end())) {
66 if (it_simplex->size() < num_pts
67 && std::includes(s.begin(), s.end(),
68 it_simplex->begin(), it_simplex->end())) {
69 to_erase.push_back(it_simplex);
71 check_higher_dim_simpl =
false;
74 for (std::vector<Complex::iterator>::const_iterator it = to_erase.begin();
75 it != to_erase.end(); ++it) {
79 return m_complex.insert(s).second;
82 const Simplex_set &simplex_range()
const {
87 return m_complex.empty();
94 template <
typename Test,
typename Output_it>
95 void get_simplices_matching_test(Test test, Output_it out) {
96 for (Complex::const_iterator it_simplex = m_complex.begin(),
97 it_simplex_end = m_complex.end();
98 it_simplex != it_simplex_end;
100 if (test(*it_simplex))
101 *out++ = *it_simplex;
108 void collapse(
int max_simplex_dim,
bool quiet =
false) {
111 std::cerr <<
"Collapsing... ";
114 int k = max_simplex_dim - 1;
116 typedef Complex::iterator Simplex_iterator;
117 typedef std::vector<Simplex_iterator> Simplex_iterator_list;
118 typedef std::map<Simplex, Simplex_iterator_list> Cofaces_map;
120 std::size_t num_collapsed_maximal_simplices = 0;
122 num_collapsed_maximal_simplices = 0;
125 Cofaces_map cofaces_map;
126 for (Complex::const_iterator it_simplex = m_complex.begin(),
127 it_simplex_end = m_complex.end();
128 it_simplex != it_simplex_end;
130 if (
static_cast<int> (it_simplex->size()) > k + 1) {
131 std::vector<Simplex> k_faces;
133 combinations(*it_simplex, k + 1, std::back_inserter(k_faces));
134 for (
const auto &comb : k_faces)
135 cofaces_map[comb].push_back(it_simplex);
146 for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
147 it_map_end = cofaces_map.end();
148 it_map_elt != it_map_end;
150 if (it_map_elt->second.size() == 1) {
151 std::vector<Simplex> k_faces;
152 const Simplex_iterator_list::value_type &it_Cf =
153 *it_map_elt->second.begin();
154 GUDHI_CHECK(it_Cf->size() == max_simplex_dim + 1,
155 std::logic_error(
"Wrong dimension"));
157 combinations(*it_Cf, k + 1, std::back_inserter(k_faces));
158 for (
const auto &f2 : k_faces) {
160 if (f2 != it_map_elt->first) {
161 Cofaces_map::iterator it_comb_in_map = cofaces_map.find(f2);
162 if (it_comb_in_map->second.size() == 1) {
163 it_comb_in_map->second.clear();
164 m_complex.insert(f2);
166 Simplex_iterator_list::iterator it = std::find(it_comb_in_map->second.begin(),
167 it_comb_in_map->second.end(),
169 GUDHI_CHECK(it != it_comb_in_map->second.end(),
170 std::logic_error(
"Error: it == it_comb_in_map->second.end()"));
171 it_comb_in_map->second.erase(it);
175 m_complex.erase(it_Cf);
176 ++num_collapsed_maximal_simplices;
180 }
while (num_collapsed_maximal_simplices > 0);
184 collapse(max_simplex_dim - 1,
true);
188 std::cerr <<
"done.\n";
192 void display_stats()
const {
193 std::cerr << yellow <<
"Complex stats:\n" << white;
195 if (m_complex.empty()) {
196 std::cerr <<
" * No simplices.\n";
199 std::map<int, std::size_t> simplex_stats;
201 for (Complex::const_iterator it_simplex = m_complex.begin(),
202 it_simplex_end = m_complex.end();
203 it_simplex != it_simplex_end;
205 ++simplex_stats[
static_cast<int> (it_simplex->size()) - 1];
208 for (std::map<int, std::size_t>::const_iterator it_map = simplex_stats.begin();
209 it_map != simplex_stats.end(); ++it_map) {
210 std::cerr <<
" * " << it_map->first <<
"-simplices: "
211 << it_map->second <<
"\n";
217 bool is_pure_pseudomanifold__do_not_check_if_stars_are_connected(
int simplex_dim,
218 bool allow_borders =
false,
219 bool exit_at_the_first_problem =
false,
220 int verbose_level = 0,
221 std::size_t *p_num_wrong_dim_simplices = NULL,
222 std::size_t *p_num_wrong_number_of_cofaces = NULL)
const {
223 typedef Simplex K_1_face;
224 typedef std::map<K_1_face, std::size_t> Cofaces_map;
226 std::size_t num_wrong_dim_simplices = 0;
227 std::size_t num_wrong_number_of_cofaces = 0;
233 Cofaces_map cofaces_map;
234 for (Complex::const_iterator it_simplex = m_complex.begin(),
235 it_simplex_end = m_complex.end();
236 it_simplex != it_simplex_end;
238 if (
static_cast<int> (it_simplex->size()) != simplex_dim + 1) {
239 if (verbose_level >= 2)
240 std::cerr <<
"Found a simplex with dim = "
241 << it_simplex->size() - 1 <<
"\n";
242 ++num_wrong_dim_simplices;
244 std::vector<K_1_face> k_1_faces;
247 *it_simplex, simplex_dim, std::back_inserter(k_1_faces));
248 for (
const auto &k_1_face : k_1_faces) {
249 ++cofaces_map[k_1_face];
254 for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
255 it_map_end = cofaces_map.end();
256 it_map_elt != it_map_end;
258 if (it_map_elt->second != 2
259 && (!allow_borders || it_map_elt->second != 1)) {
260 if (verbose_level >= 2)
261 std::cerr <<
"Found a k-1-face with "
262 << it_map_elt->second <<
" cofaces\n";
264 if (exit_at_the_first_problem)
267 ++num_wrong_number_of_cofaces;
271 bool ret = num_wrong_dim_simplices == 0 && num_wrong_number_of_cofaces == 0;
273 if (verbose_level >= 1) {
274 std::cerr <<
"Pure pseudo-manifold: ";
276 std::cerr << green <<
"YES" << white <<
"\n";
278 std::cerr << red <<
"NO" << white <<
"\n"
279 <<
" * Number of wrong dimension simplices: "
280 << num_wrong_dim_simplices <<
"\n"
281 <<
" * Number of wrong number of cofaces: "
282 << num_wrong_number_of_cofaces <<
"\n";
286 if (p_num_wrong_dim_simplices)
287 *p_num_wrong_dim_simplices = num_wrong_dim_simplices;
288 if (p_num_wrong_number_of_cofaces)
289 *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
295 std::size_t num_K_simplices()
const {
296 Simplex_set k_simplices;
298 for (Complex::const_iterator it_simplex = m_complex.begin(),
299 it_simplex_end = m_complex.end();
300 it_simplex != it_simplex_end;
302 if (it_simplex->size() == K + 1) {
303 k_simplices.insert(*it_simplex);
304 }
else if (it_simplex->size() > K + 1) {
307 *it_simplex, K + 1, std::inserter(k_simplices, k_simplices.begin()));
311 return k_simplices.size();
314 std::ptrdiff_t euler_characteristic(
bool verbose =
false)
const {
316 std::cerr <<
"\nComputing Euler characteristic of the complex...\n";
318 std::size_t num_vertices = num_K_simplices<0>();
319 std::size_t num_edges = num_K_simplices<1>();
320 std::size_t num_triangles = num_K_simplices<2>();
323 (std::ptrdiff_t) num_vertices
324 - (std::ptrdiff_t) num_edges
325 + (std::ptrdiff_t) num_triangles;
328 std::cerr <<
"Euler characteristic: V - E + F = "
329 << num_vertices <<
" - " << num_edges <<
" + " << num_triangles <<
" = "
339 bool is_pure_pseudomanifold(
341 std::size_t num_vertices,
342 bool allow_borders =
false,
343 bool exit_at_the_first_problem =
false,
344 int verbose_level = 0,
345 std::size_t *p_num_wrong_dim_simplices = NULL,
346 std::size_t *p_num_wrong_number_of_cofaces = NULL,
347 std::size_t *p_num_unconnected_stars = NULL,
348 Simplex_set *p_wrong_dim_simplices = NULL,
349 Simplex_set *p_wrong_number_of_cofaces_simplices = NULL,
350 Simplex_set *p_unconnected_stars_simplices = NULL)
const {
352 if (simplex_dim == 1) {
353 if (p_num_unconnected_stars)
354 *p_num_unconnected_stars = 0;
355 return is_pure_pseudomanifold__do_not_check_if_stars_are_connected(simplex_dim,
357 exit_at_the_first_problem,
359 p_num_wrong_dim_simplices,
360 p_num_wrong_number_of_cofaces);
364 typedef std::vector<std::vector<Complex::const_iterator> > Stars;
365 std::size_t num_wrong_dim_simplices = 0;
366 std::size_t num_wrong_number_of_cofaces = 0;
367 std::size_t num_unconnected_stars = 0;
371 stars.resize(num_vertices);
372 for (Complex::const_iterator it_simplex = m_complex.begin(),
373 it_simplex_end = m_complex.end();
374 it_simplex != it_simplex_end;
376 if (
static_cast<int> (it_simplex->size()) != simplex_dim + 1) {
377 if (verbose_level >= 2)
378 std::cerr <<
"Found a simplex with dim = "
379 << it_simplex->size() - 1 <<
"\n";
380 ++num_wrong_dim_simplices;
381 if (p_wrong_dim_simplices)
382 p_wrong_dim_simplices->insert(*it_simplex);
384 for (Simplex::const_iterator it_point_idx = it_simplex->begin();
385 it_point_idx != it_simplex->end();
387 stars[*it_point_idx].push_back(it_simplex);
396 std::size_t center_vertex_index = 0;
397 for (Stars::const_iterator it_star = stars.begin();
398 it_star != stars.end();
399 ++it_star, ++center_vertex_index) {
400 typedef std::map<Simplex, std::vector<std::size_t> >
401 Dm1_faces_to_adj_D_faces;
402 Dm1_faces_to_adj_D_faces dm1_faces_to_adj_d_faces;
404 for (std::size_t i_dsimpl = 0; i_dsimpl < it_star->size(); ++i_dsimpl) {
405 Simplex dm1_simpl_of_link = *((*it_star)[i_dsimpl]);
406 dm1_simpl_of_link.erase(center_vertex_index);
408 std::vector<std::size_t> dm1_simpl_of_link_vec(
409 dm1_simpl_of_link.begin(), dm1_simpl_of_link.end());
411 CGAL::Combination_enumerator<int> dm2_simplices(
412 simplex_dim - 1, 0, simplex_dim);
413 for (; !dm2_simplices.finished(); ++dm2_simplices) {
415 for (
int j = 0; j < simplex_dim - 1; ++j)
416 dm2_simpl.insert(dm1_simpl_of_link_vec[dm2_simplices[j]]);
417 dm1_faces_to_adj_d_faces[dm2_simpl].push_back(i_dsimpl);
422 std::vector<Graph_vertex> d_faces_descriptors;
423 d_faces_descriptors.resize(it_star->size());
424 for (std::size_t j = 0; j < it_star->size(); ++j)
425 d_faces_descriptors[j] = boost::add_vertex(adj_graph);
427 Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it =
428 dm1_faces_to_adj_d_faces.begin();
429 Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it_end =
430 dm1_faces_to_adj_d_faces.end();
431 for (std::size_t i_km1_face = 0;
432 dm1_to_d_it != dm1_to_d_it_end;
433 ++dm1_to_d_it, ++i_km1_face) {
434 Graph_vertex km1_gv = boost::add_vertex(adj_graph);
436 for (std::vector<std::size_t>::const_iterator kface_it =
437 dm1_to_d_it->second.begin();
438 kface_it != dm1_to_d_it->second.end();
440 boost::add_edge(km1_gv, *kface_it, adj_graph);
443 if (dm1_to_d_it->second.size() != 2
444 && (!allow_borders || dm1_to_d_it->second.size() != 1)) {
445 ++num_wrong_number_of_cofaces;
446 if (p_wrong_number_of_cofaces_simplices) {
447 for (
auto idx : dm1_to_d_it->second)
448 p_wrong_number_of_cofaces_simplices->insert(*((*it_star)[idx]));
454 bool is_connected =
true;
455 if (boost::num_vertices(adj_graph) > 0) {
456 std::vector<int> components(boost::num_vertices(adj_graph));
458 (boost::connected_components(adj_graph, &components[0]) == 1);
462 if (verbose_level >= 2)
463 std::cerr <<
"Error: star #" << center_vertex_index
464 <<
" is not connected\n";
465 ++num_unconnected_stars;
466 if (p_unconnected_stars_simplices) {
467 for (std::vector<Complex::const_iterator>::const_iterator
468 it_simpl = it_star->begin(),
469 it_simpl_end = it_star->end();
470 it_simpl != it_simpl_end;
472 p_unconnected_stars_simplices->insert(**it_simpl);
479 num_wrong_number_of_cofaces /= simplex_dim;
482 num_wrong_dim_simplices == 0
483 && num_wrong_number_of_cofaces == 0
484 && num_unconnected_stars == 0;
486 if (verbose_level >= 1) {
487 std::cerr <<
"Pure pseudo-manifold: ";
489 std::cerr << green <<
"YES" << white <<
"\n";
491 std::cerr << red <<
"NO" << white <<
"\n"
492 <<
" * Number of wrong dimension simplices: "
493 << num_wrong_dim_simplices <<
"\n"
494 <<
" * Number of wrong number of cofaces: "
495 << num_wrong_number_of_cofaces <<
"\n"
496 <<
" * Number of not-connected stars: "
497 << num_unconnected_stars <<
"\n";
501 if (p_num_wrong_dim_simplices)
502 *p_num_wrong_dim_simplices = num_wrong_dim_simplices;
503 if (p_num_wrong_number_of_cofaces)
504 *p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
505 if (p_num_unconnected_stars)
506 *p_num_unconnected_stars = num_unconnected_stars;
515 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph;
517 typedef boost::graph_traits<Adj_graph>::vertex_descriptor Graph_vertex;
518 typedef boost::graph_traits<Adj_graph>::edge_descriptor Graph_edge;
Class that represents a geometric complex that can be simplified. The class allows access to points o...
Definition: Skeleton_blocker_geometric_complex.h:29