Loading...
Searching...
No Matches
GIC.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: Mathieu Carriere
4 *
5 * Copyright (C) 2017 Inria
6 *
7 * Modification(s):
8 * - 2019/08 Vincent Rouvreau: Fix issue #10 for CGAL
9 * - YYYY/MM Author: Description of the modification
10 */
11
12#ifndef GIC_H_
13#define GIC_H_
14
15#ifdef GUDHI_USE_TBB
16#include <tbb/parallel_for.h>
17#include <mutex>
18#endif
19
20#if __has_include(<CGAL/version.h>)
21# define GUDHI_GIC_USE_CGAL 1
22# include <gudhi/Bottleneck.h>
23#elif __has_include(<hera/bottleneck.h>)
24# define GUDHI_GIC_USE_HERA 1
25# ifdef _MSC_VER
26// https://github.com/grey-narn/hera/issues/3
27// ssize_t is a non-standard type (well, posix)
28# include <type_traits>
29# include <cstdlib>
30using ssize_t = std::make_signed_t<std::size_t>;
31# endif
32# include <hera/bottleneck.h>
33#endif
34
35#include <gudhi/Debug_utils.h>
37#include <gudhi/reader_utils.h>
38#include <gudhi/Simplex_tree.h>
39#include <gudhi/Rips_complex.h>
40#include <gudhi/Points_off_io.h>
42#include <gudhi/Persistent_cohomology.h>
43
44#include <boost/config.hpp>
45#include <boost/graph/graph_traits.hpp>
46#include <boost/graph/adjacency_list.hpp>
47#include <boost/graph/connected_components.hpp>
48#include <boost/graph/dijkstra_shortest_paths.hpp>
49#include <boost/graph/subgraph.hpp>
50#include <boost/graph/graph_utility.hpp>
51
52#include <iostream>
53#include <vector>
54#include <map>
55#include <string>
56#include <limits> // for numeric_limits
57#include <utility> // for std::pair<>
58#include <algorithm> // for (std::max)
59#include <random>
60#include <cassert>
61#include <cmath>
62
63namespace Gudhi {
64
65namespace cover_complex {
66
70using Persistence_diagram = std::vector<std::pair<double, double> >;
71using Graph = boost::subgraph<
72 boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, boost::no_property,
73 boost::property<boost::edge_index_t, int, boost::property<boost::edge_weight_t, double> > > >;
74using Vertex_t = boost::graph_traits<Graph>::vertex_descriptor;
75using Index_map = boost::property_map<Graph, boost::vertex_index_t>::type;
76using Weight_map = boost::property_map<Graph, boost::edge_weight_t>::type;
77
98template <typename Point>
100 private:
101 bool verbose = false; // whether to display information.
102 std::string type; // Nerve or GIC
103
104 std::vector<Point> point_cloud; // input point cloud.
105 std::vector<std::vector<double> > distances; // all pairwise distances.
106 int maximal_dim; // maximal dimension of output simplicial complex.
107 int data_dimension; // dimension of input data.
108 int num_points; // number of points.
109
110 std::vector<double> func; // function used to compute the output simplicial complex.
111 std::vector<double> func_color; // function used to compute the colors of the nodes of the output simplicial complex.
112 bool functional_cover = false; // whether we use a cover with preimages of a function or not.
113
114 Graph one_skeleton_OFF; // one-skeleton given by the input OFF file (if it exists).
115 Graph one_skeleton; // one-skeleton used to compute the connected components.
116 std::vector<Vertex_t> vertices; // vertices of one_skeleton.
117
118 std::vector<std::vector<int> > simplices; // simplices of output simplicial complex.
119 std::vector<int> voronoi_subsamples; // Voronoi germs (in case of Voronoi cover).
120
121 Persistence_diagram PD;
122 std::vector<double> distribution;
123
124 std::vector<std::vector<int> >
125 cover; // function associating to each data point the vector of cover elements to which it belongs.
126 std::map<int, std::vector<int> >
127 cover_back; // inverse of cover, in order to get the data points associated to a specific cover element.
128 std::map<int, double> cover_std; // standard function (induced by func) used to compute the extended persistence
129 // diagram of the output simplicial complex.
130 std::map<int, int>
131 cover_fct; // integer-valued function that allows to state if two elements of the cover are consecutive or not.
132 std::map<int, std::pair<int, double> >
133 cover_color; // size and coloring (induced by func_color) of the vertices of the output simplicial complex.
134
135 int resolution_int = -1;
136 double resolution_double = -1;
137 double gain = -1;
138 double rate_constant = 10; // Constant in the subsampling.
139 double rate_power = 0.001; // Power in the subsampling.
140 int mask = 0; // Ignore nodes containing less than mask points.
141
142 std::map<int, int> name2id, name2idinv;
143
144 std::string cover_name;
145 std::string point_cloud_name;
146 std::string color_name;
147
148 // Remove all edges of a graph.
149 void remove_edges(Graph& G) {
150 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
151 for (boost::tie(ei, ei_end) = boost::edges(G); ei != ei_end; ++ei) boost::remove_edge(*ei, G);
152 }
153
154 // Find random number in [0,1].
155 double GetUniform() {
156 thread_local std::default_random_engine re;
157 std::uniform_real_distribution<double> Dist(0, 1);
158 return Dist(re);
159 }
160
161 // Subsample points.
162 void SampleWithoutReplacement(int populationSize, int sampleSize, std::vector<int>& samples) {
163 int t = 0;
164 int m = 0;
165 double u;
166 while (m < sampleSize) {
167 u = GetUniform();
168 if ((populationSize - t) * u >= sampleSize - m) {
169 t++;
170 } else {
171 samples[m] = t;
172 t++;
173 m++;
174 }
175 }
176 }
177
178 // *******************************************************************************************************************
179 // Utils.
180 // *******************************************************************************************************************
181
182 public:
188 void set_type(const std::string& t) { type = t; }
189
190 public:
196 void set_verbose(bool verb = false) { verbose = verb; }
197
198 public:
206 void set_subsampling(double constant, double power) {
207 rate_constant = constant;
208 rate_power = power;
209 }
210
211 public:
219 void set_mask(int nodemask) { mask = nodemask; }
220
221 public:
222
223
229 void set_point_cloud_from_range(const std::vector<std::vector<double> > & point_cloud) {
230 this->num_points = point_cloud.size(); data_dimension = point_cloud[0].size();
231 point_cloud_name = "cloud"; cover.resize(this->num_points);
232 for(int i = 0; i < this->num_points; i++){
233 boost::add_vertex(one_skeleton_OFF);
234 vertices.push_back(boost::add_vertex(one_skeleton));
235 }
236 this->point_cloud = point_cloud;
237 }
238
244 bool read_point_cloud(const std::string& off_file_name) {
245 point_cloud_name = off_file_name;
246 std::ifstream input(off_file_name);
247 std::string line;
248
249 char comment = '#';
250 while (comment == '#') {
251 std::getline(input, line);
252 if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
253 comment = line[line.find_first_not_of(' ')];
254 }
255 if (strcmp((char*)line.c_str(), "nOFF") == 0) {
256 comment = '#';
257 while (comment == '#') {
258 std::getline(input, line);
259 if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
260 comment = line[line.find_first_not_of(' ')];
261 }
262 std::stringstream stream(line);
263 stream >> data_dimension;
264 } else {
265 data_dimension = 3;
266 }
267
268 comment = '#';
269 int numedges, numfaces, i, dim;
270 while (comment == '#') {
271 std::getline(input, line);
272 if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace))
273 comment = line[line.find_first_not_of(' ')];
274 }
275 std::stringstream stream(line);
276 stream >> this->num_points;
277 stream >> numfaces;
278 stream >> numedges;
279
280 i = 0;
281 while (i < this->num_points) {
282 std::getline(input, line);
283 if (!line.empty() && line[line.find_first_not_of(' ')] != '#' &&
284 !all_of(line.begin(), line.end(), (int (*)(int))isspace)) {
285 std::stringstream iss(line);
286 std::vector<double> point;
287 point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>());
288 point_cloud.emplace_back(point.begin(), point.begin() + data_dimension);
289 boost::add_vertex(one_skeleton_OFF);
290 vertices.push_back(boost::add_vertex(one_skeleton));
291 cover.emplace_back();
292 i++;
293 }
294 }
295
296 i = 0;
297 while (i < numfaces) {
298 std::getline(input, line);
299 if (!line.empty() && line[line.find_first_not_of(' ')] != '#' &&
300 !all_of(line.begin(), line.end(), (int (*)(int))isspace)) {
301 std::vector<int> simplex;
302 std::stringstream iss(line);
303 simplex.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>());
304 dim = simplex[0];
305 for (int j = 1; j <= dim; j++)
306 for (int k = j + 1; k <= dim; k++)
307 boost::add_edge(vertices[simplex[j]], vertices[simplex[k]], one_skeleton_OFF);
308 i++;
309 }
310 }
311
312 return input.is_open();
313 }
314
315 // *******************************************************************************************************************
316 // Graphs.
317 // *******************************************************************************************************************
318
319 public: // Set graph from file.
327 void set_graph_from_file(const std::string& graph_file_name) {
328 remove_edges(one_skeleton);
329 int neighb;
330 std::ifstream input(graph_file_name);
331 std::string line;
332 int source;
333 while (std::getline(input, line)) {
334 std::stringstream stream(line);
335 stream >> source;
336 while (stream >> neighb) boost::add_edge(vertices[source], vertices[neighb], one_skeleton);
337 }
338 }
339
340 public: // Set graph from OFF file.
345 remove_edges(one_skeleton);
346 if (num_edges(one_skeleton_OFF))
347 one_skeleton = one_skeleton_OFF;
348 else
349 std::cerr << "No triangulation read in OFF file!" << std::endl;
350 }
351
352 public: // Set graph from Rips complex.
359 template <typename Distance>
360 void set_graph_from_rips(double threshold, Distance distance) {
361 remove_edges(one_skeleton);
362 if (distances.size() == 0) compute_pairwise_distances(distance);
363 for (int i = 0; i < this->num_points; i++) {
364 for (int j = i + 1; j < this->num_points; j++) {
365 if (distances[i][j] <= threshold) {
366 boost::add_edge(vertices[i], vertices[j], one_skeleton);
367 boost::put(boost::edge_weight, one_skeleton, boost::edge(vertices[i], vertices[j], one_skeleton).first,
368 distances[i][j]);
369 }
370 }
371 }
372 }
373
374 public:
375 void set_graph_weights() {
376 Index_map index = boost::get(boost::vertex_index, one_skeleton);
377 Weight_map weight = boost::get(boost::edge_weight, one_skeleton);
378 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
379 for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
380 boost::put(weight, *ei,
381 distances[index[boost::source(*ei, one_skeleton)]][index[boost::target(*ei, one_skeleton)]]);
382 }
383
384 public:
390 void set_distances_from_range(const std::vector<std::vector<double> > & distance_matrix) {
391 this->num_points = distance_matrix.size(); data_dimension = 0; point_cloud_name = "matrix";
392 cover.resize(this->num_points); point_cloud.resize(this->num_points);
393 for(int i = 0; i < this->num_points; i++){
394 boost::add_vertex(one_skeleton_OFF);
395 vertices.push_back(boost::add_vertex(one_skeleton));
396 }
397 distances = distance_matrix;
398 }
399
400 public: // Pairwise distances.
403 template <typename Distance>
404 void compute_pairwise_distances(Distance ref_distance) {
405 std::vector<double> zeros(this->num_points);
406 for (int i = 0; i < this->num_points; i++) distances.push_back(zeros);
407 if (verbose) std::clog << "Computing distances..." << std::endl;
408 for (int i = 0; i < this->num_points; i++) {
409 int state = 100 * (i + 1) / this->num_points;
410 if (verbose && state % 10 == 0) std::clog << "\r" << state << "%" << std::flush;
411 for (int j = i; j < this->num_points; j++) {
412 double dis = ref_distance(point_cloud[i], point_cloud[j]);
413 distances[i][j] = dis;
414 distances[j][i] = dis;
415 }
416 }
417 if (verbose) std::clog << std::endl;
418 }
419
420 public: // Automatic tuning of Rips complex.
430 template <typename Distance>
431 double set_graph_from_automatic_rips(Distance distance, int N = 100) {
432 int m = floor(this->num_points / std::exp((1 + rate_power) * std::log(std::log(this->num_points) / std::log(rate_constant))));
433 m = (std::min)(m, this->num_points - 1);
434 double delta = 0;
435
436 if (verbose) std::clog << this->num_points << " points in R^" << data_dimension << std::endl;
437 if (verbose) std::clog << "Subsampling " << m << " points" << std::endl;
438
439 if (distances.size() == 0) compute_pairwise_distances(distance);
440
441 #ifdef GUDHI_USE_TBB
442 std::mutex deltamutex;
443 tbb::parallel_for(0, N, [&](int i){
444 std::vector<int> samples(m);
445 SampleWithoutReplacement(this->num_points, m, samples);
446 double hausdorff_dist = 0;
447 for (int j = 0; j < this->num_points; j++) {
448 double mj = distances[j][samples[0]];
449 for (int k = 1; k < m; k++) mj = (std::min)(mj, distances[j][samples[k]]);
450 hausdorff_dist = (std::max)(hausdorff_dist, mj);
451 }
452 deltamutex.lock();
453 delta += hausdorff_dist / N;
454 deltamutex.unlock();
455 });
456 #else
457 for (int i = 0; i < N; i++) {
458 std::vector<int> samples(m);
459 SampleWithoutReplacement(this->num_points, m, samples);
460 double hausdorff_dist = 0;
461 for (int j = 0; j < this->num_points; j++) {
462 double mj = distances[j][samples[0]];
463 for (int k = 1; k < m; k++) mj = (std::min)(mj, distances[j][samples[k]]);
464 hausdorff_dist = (std::max)(hausdorff_dist, mj);
465 }
466 delta += hausdorff_dist / N;
467 }
468 #endif
469
470 if (verbose) std::clog << "delta = " << delta << std::endl;
471 set_graph_from_rips(delta, distance);
472 return delta;
473 }
474
475 // *******************************************************************************************************************
476 // Functions.
477 // *******************************************************************************************************************
478
479 public: // Set function from file.
485 void set_function_from_file(const std::string& func_file_name) {
486 int i = 0;
487 std::ifstream input(func_file_name);
488 std::string line;
489 double f;
490 while (std::getline(input, line)) {
491 std::stringstream stream(line);
492 stream >> f;
493 func.push_back(f);
494 i++;
495 }
496 functional_cover = true;
497 cover_name = func_file_name;
498 }
499
500 public: // Set function from kth coordinate
507 if(point_cloud[0].size() > 0){
508 for (int i = 0; i < this->num_points; i++) func.push_back(point_cloud[i][k]);
509 functional_cover = true;
510 cover_name = "coordinate " + std::to_string(k);
511 }
512 else{
513 std::cerr << "Only pairwise distances provided---cannot access " << k << "th coordinate; returning null vector instead" << std::endl;
514 for (int i = 0; i < this->num_points; i++) func.push_back(0.0);
515 functional_cover = true;
516 cover_name = "null";
517 }
518 }
519
520 public: // Set function from vector.
526 template <class InputRange>
527 void set_function_from_range(InputRange const& function) {
528 for (int i = 0; i < this->num_points; i++) func.push_back(function[i]);
529 functional_cover = true;
530 }
531
532 // *******************************************************************************************************************
533 // Covers.
534 // *******************************************************************************************************************
535
536 public: // Automatic tuning of resolution.
545 if (!functional_cover) {
546 std::cerr << "Cover needs to come from the preimages of a function." << std::endl;
547 return 0;
548 }
549 if (type != "Nerve" && type != "GIC") {
550 std::cerr << "Type of complex needs to be specified." << std::endl;
551 return 0;
552 }
553
554 double reso = 0;
555 Index_map index = boost::get(boost::vertex_index, one_skeleton);
556
557 if (type == "GIC") {
558 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
559 for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
560 reso = (std::max)(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] -
561 func[index[boost::target(*ei, one_skeleton)]]));
562 if (verbose) std::clog << "resolution = " << reso << std::endl;
563 resolution_double = reso;
564 }
565
566 if (type == "Nerve") {
567 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
568 for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
569 reso = (std::max)(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] -
570 func[index[boost::target(*ei, one_skeleton)]]) /
571 gain);
572 if (verbose) std::clog << "resolution = " << reso << std::endl;
573 resolution_double = reso;
574 }
575
576 return reso;
577 }
578
579 public:
585 void set_resolution_with_interval_length(double reso) { resolution_double = reso; }
591 void set_resolution_with_interval_number(int reso) { resolution_int = reso; }
597 void set_gain(double g = 0.3) { gain = g; }
598
599 public: // Set cover with preimages of function.
604 if (resolution_double == -1 && resolution_int == -1) {
605 std::cerr << "Number and/or length of intervals not specified" << std::endl;
606 return;
607 }
608 if (gain == -1) {
609 std::cerr << "Gain not specified" << std::endl;
610 return;
611 }
612
613 // Read function values and compute min and max
614 double minf = (std::numeric_limits<float>::max)();
615 double maxf = std::numeric_limits<float>::lowest();
616 for (int i = 0; i < this->num_points; i++) {
617 minf = (std::min)(minf, func[i]);
618 maxf = (std::max)(maxf, func[i]);
619 }
620 if (verbose) std::clog << "Min function value = " << minf << " and Max function value = " << maxf << std::endl;
621
622 // Compute cover of im(f)
623 std::vector<std::pair<double, double> > intervals;
624 int res;
625
626 if (resolution_double == -1) { // Case we use an integer for the number of intervals.
627 double incr = (maxf - minf) / resolution_int;
628 double x = minf;
629 double alpha = (incr * gain) / (2 - 2 * gain);
630 double y = minf + incr + alpha;
631 std::pair<double, double> interm(x, y);
632 intervals.push_back(interm);
633 for (int i = 1; i < resolution_int - 1; i++) {
634 x = minf + i * incr - alpha;
635 y = minf + (i + 1) * incr + alpha;
636 std::pair<double, double> inter(x, y);
637 intervals.push_back(inter);
638 }
639 x = minf + (resolution_int - 1) * incr - alpha;
640 y = maxf;
641 std::pair<double, double> interM(x, y);
642 intervals.push_back(interM);
643 res = intervals.size();
644 if (verbose) {
645 for (int i = 0; i < res; i++)
646 std::clog << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
647 << std::endl;
648 }
649 } else {
650 if (resolution_int == -1) { // Case we use a double for the length of the intervals.
651 double x = minf;
652 double y = x + resolution_double;
653 while (y <= maxf && maxf - (y - gain * resolution_double) >= resolution_double) {
654 std::pair<double, double> inter(x, y);
655 intervals.push_back(inter);
656 x = y - gain * resolution_double;
657 y = x + resolution_double;
658 }
659 std::pair<double, double> interM(x, maxf);
660 intervals.push_back(interM);
661 res = intervals.size();
662 if (verbose) {
663 for (int i = 0; i < res; i++)
664 std::clog << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
665 << std::endl;
666 }
667 } else { // Case we use an integer and a double for the length of the intervals.
668 double x = minf;
669 double y = x + resolution_double;
670 int count = 0;
671 while (count < resolution_int && y <= maxf && maxf - (y - gain * resolution_double) >= resolution_double) {
672 std::pair<double, double> inter(x, y);
673 intervals.push_back(inter);
674 count++;
675 x = y - gain * resolution_double;
676 y = x + resolution_double;
677 }
678 res = intervals.size();
679 if (verbose) {
680 for (int i = 0; i < res; i++)
681 std::clog << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]"
682 << std::endl;
683 }
684 }
685 }
686
687 // Sort points according to function values
688 std::vector<int> points(this->num_points);
689 for (int i = 0; i < this->num_points; i++) points[i] = i;
690 std::sort(points.begin(), points.end(), [this](int p1, int p2){return (this->func[p1] < this->func[p2]);});
691
692 int id = 0;
693 int pos = 0;
694 Index_map index = boost::get(boost::vertex_index, one_skeleton); // int maxc = -1;
695 std::map<int, std::vector<int> > preimages;
696 std::map<int, double> funcstd;
697
698 if (verbose) std::clog << "Computing preimages..." << std::endl;
699 for (int i = 0; i < res; i++) {
700 // Find points in the preimage
701 std::pair<double, double> inter1 = intervals[i];
702 int tmp = pos;
703 double u, v;
704
705 if (i != res - 1) {
706 if (i != 0) {
707 std::pair<double, double> inter3 = intervals[i - 1];
708 while (func[points[tmp]] < inter3.second && tmp != this->num_points) {
709 preimages[i].push_back(points[tmp]);
710 tmp++;
711 }
712 u = inter3.second;
713 } else {
714 u = inter1.first;
715 }
716
717 std::pair<double, double> inter2 = intervals[i + 1];
718 while (func[points[tmp]] < inter2.first && tmp != this->num_points) {
719 preimages[i].push_back(points[tmp]);
720 tmp++;
721 }
722 v = inter2.first;
723 pos = tmp;
724 while (func[points[tmp]] < inter1.second && tmp != this->num_points) {
725 preimages[i].push_back(points[tmp]);
726 tmp++;
727 }
728
729 } else {
730 std::pair<double, double> inter3 = intervals[i - 1];
731 while (func[points[tmp]] < inter3.second && tmp != this->num_points) {
732 preimages[i].push_back(points[tmp]);
733 tmp++;
734 }
735 while (tmp != this->num_points) {
736 preimages[i].push_back(points[tmp]);
737 tmp++;
738 }
739 u = inter3.second;
740 v = inter1.second;
741 }
742
743 funcstd[i] = 0.5 * (u + v);
744 }
745
746 #ifdef GUDHI_USE_TBB
747 if (verbose) std::clog << "Computing connected components (parallelized)..." << std::endl;
748 std::mutex covermutex, idmutex;
749 tbb::parallel_for(0, res, [&](int i){
750 // Compute connected components
751 Graph G = one_skeleton.create_subgraph();
752 int num = preimages[i].size();
753 std::vector<int> component(num);
754 for (int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G);
755 boost::connected_components(G, &component[0]);
756 int max = 0;
757
758 // For each point in preimage
759 for (int j = 0; j < num; j++) {
760 // Update number of components in preimage
761 if (component[j] > max) max = component[j];
762
763 // Identify component with Cantor polynomial N^2 -> N
764 int identifier = ((i + component[j])*(i + component[j]) + 3 * i + component[j]) / 2;
765
766 // Update covers
767 covermutex.lock();
768 cover[preimages[i][j]].push_back(identifier);
769 cover_back[identifier].push_back(preimages[i][j]);
770 cover_fct[identifier] = i;
771 cover_std[identifier] = funcstd[i];
772 cover_color[identifier].second += func_color[preimages[i][j]];
773 cover_color[identifier].first += 1;
774 covermutex.unlock();
775 }
776
777 // Maximal dimension is total number of connected components
778 idmutex.lock();
779 id += max + 1;
780 idmutex.unlock();
781 });
782 #else
783 if (verbose) std::clog << "Computing connected components..." << std::endl;
784 for (int i = 0; i < res; i++) {
785 // Compute connected components
786 Graph G = one_skeleton.create_subgraph();
787 int num = preimages[i].size();
788 std::vector<int> component(num);
789 for (int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G);
790 boost::connected_components(G, &component[0]);
791 int max = 0;
792
793 // For each point in preimage
794 for (int j = 0; j < num; j++) {
795 // Update number of components in preimage
796 if (component[j] > max) max = component[j];
797
798 // Identify component with Cantor polynomial N^2 -> N
799 int identifier = (std::pow(i + component[j], 2) + 3 * i + component[j]) / 2;
800
801 // Update covers
802 cover[preimages[i][j]].push_back(identifier);
803 cover_back[identifier].push_back(preimages[i][j]);
804 cover_fct[identifier] = i;
805 cover_std[identifier] = funcstd[i];
806 cover_color[identifier].second += func_color[preimages[i][j]];
807 cover_color[identifier].first += 1;
808 }
809
810 // Maximal dimension is total number of connected components
811 id += max + 1;
812 }
813 #endif
814
815 maximal_dim = id - 1;
816 for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++)
817 iit->second.second /= iit->second.first;
818 }
819
820 public: // Set cover from file.
827 void set_cover_from_file(const std::string& cover_file_name) {
828 int i = 0;
829 int cov;
830 std::vector<int> cov_elts, cov_number;
831 std::ifstream input(cover_file_name);
832 std::string line;
833 while (std::getline(input, line)) {
834 cov_elts.clear();
835 std::stringstream stream(line);
836 while (stream >> cov) {
837 cov_elts.push_back(cov);
838 cov_number.push_back(cov);
839 cover_fct[cov] = cov;
840 cover_color[cov].second += func_color[i];
841 cover_color[cov].first++;
842 cover_back[cov].push_back(i);
843 }
844 cover[i] = cov_elts;
845 i++;
846 }
847
848 std::sort(cov_number.begin(), cov_number.end());
849 std::vector<int>::iterator it = std::unique(cov_number.begin(), cov_number.end());
850 cov_number.resize(std::distance(cov_number.begin(), it));
851
852 maximal_dim = cov_number.size() - 1;
853 for (int i = 0; i <= maximal_dim; i++) cover_color[i].second /= cover_color[i].first;
854 cover_name = cover_file_name;
855 }
856
857 public: // Set cover from range.
864 template <class AssignmentRange>
865 void set_cover_from_range(AssignmentRange const& assignments) {
866 std::vector<int> cov_elts, cov_number;
867 for(int i=0; i < static_cast<int>(assignments.size()); i++){
868 cov_elts.clear();
869 for (int cov : assignments[i]){
870 cov_elts.push_back(cov);
871 cov_number.push_back(cov);
872 cover_fct[cov] = cov;
873 auto& cc = cover_color[cov];
874 cc.second += func_color[i];
875 cc.first++;
876 cover_back[cov].push_back(i);
877 }
878 cover[i] = cov_elts;
879 }
880
881 std::sort(cov_number.begin(), cov_number.end());
882 std::vector<int>::iterator it = std::unique(cov_number.begin(), cov_number.end());
883 cov_number.resize(std::distance(cov_number.begin(), it));
884
885 maximal_dim = cov_number.size() - 1;
886 for (int i = 0; i <= maximal_dim; i++) cover_color[i].second /= cover_color[i].first;
887 }
888
889 public: // Set cover from Voronoi
896 template <typename Distance>
897 void set_cover_from_Voronoi(Distance distance, int m = 100) {
898 voronoi_subsamples.resize(m);
899 SampleWithoutReplacement(this->num_points, m, voronoi_subsamples);
900 if (distances.size() == 0) compute_pairwise_distances(distance);
901 set_graph_weights();
902 Weight_map weight = boost::get(boost::edge_weight, one_skeleton);
903 Index_map index = boost::get(boost::vertex_index, one_skeleton);
904 std::vector<double> mindist(this->num_points);
905 for (int j = 0; j < this->num_points; j++) mindist[j] = (std::numeric_limits<double>::max)();
906
907 // Compute the geodesic distances to subsamples with Dijkstra
908 #ifdef GUDHI_USE_TBB
909 if (verbose) std::clog << "Computing geodesic distances (parallelized)..." << std::endl;
910 std::mutex coverMutex; std::mutex mindistMutex;
911 tbb::parallel_for(0, m, [&](int i){
912 int seed = voronoi_subsamples[i];
913 std::vector<double> dmap(this->num_points);
914 boost::dijkstra_shortest_paths(
915 one_skeleton, vertices[seed],
916 boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index)));
917
918 coverMutex.lock(); mindistMutex.lock();
919 for (int j = 0; j < this->num_points; j++)
920 if (mindist[j] > dmap[j]) {
921 mindist[j] = dmap[j];
922 if (cover[j].size() == 0)
923 cover[j].push_back(i);
924 else
925 cover[j][0] = i;
926 }
927 coverMutex.unlock(); mindistMutex.unlock();
928 });
929 #else
930 for (int i = 0; i < m; i++) {
931 if (verbose) std::clog << "Computing geodesic distances to seed " << i << "..." << std::endl;
932 int seed = voronoi_subsamples[i];
933 std::vector<double> dmap(this->num_points);
934 boost::dijkstra_shortest_paths(
935 one_skeleton, vertices[seed],
936 boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index)));
937
938 for (int j = 0; j < this->num_points; j++)
939 if (mindist[j] > dmap[j]) {
940 mindist[j] = dmap[j];
941 if (cover[j].size() == 0)
942 cover[j].push_back(i);
943 else
944 cover[j][0] = i;
945 }
946 }
947 #endif
948
949 for (int i = 0; i < this->num_points; i++) {
950 cover_back[cover[i][0]].push_back(i);
951 cover_color[cover[i][0]].second += func_color[i];
952 cover_color[cover[i][0]].first++;
953 }
954 for (int i = 0; i < m; i++) cover_color[i].second /= cover_color[i].first;
955 maximal_dim = m - 1;
956 cover_name = "Voronoi";
957 }
958
959 public: // return subset of data corresponding to a node
966 const std::vector<int>& subpopulation(int c) { return cover_back[c]; }
967
968
969 public:
976 double subcolor(int c) { return cover_color[c].second; }
977
978 // *******************************************************************************************************************
979 // Visualization.
980 // *******************************************************************************************************************
981
982 public: // Set color from file.
989 void set_color_from_file(const std::string& color_file_name) {
990 int i = 0;
991 std::ifstream input(color_file_name);
992 std::string line;
993 double f;
994 while (std::getline(input, line)) {
995 std::stringstream stream(line);
996 stream >> f;
997 func_color.push_back(f);
998 i++;
999 }
1000 color_name = color_file_name;
1001 }
1002
1003 public: // Set color from kth coordinate
1010 if(point_cloud[0].size() > 0){
1011 for (int i = 0; i < this->num_points; i++) func_color.push_back(point_cloud[i][k]);
1012 color_name = "coordinate ";
1013 color_name.append(std::to_string(k));
1014 }
1015 else{
1016 std::cerr << "Only pairwise distances provided---cannot access " << k << "th coordinate; returning null vector instead" << std::endl;
1017 for (int i = 0; i < this->num_points; i++) func.push_back(0.0);
1018 functional_cover = true;
1019 cover_name = "null";
1020 }
1021 }
1022
1023 public: // Set color from vector.
1029 void set_color_from_range(std::vector<double> color) {
1030 for (unsigned int i = 0; i < color.size(); i++) func_color.push_back(color[i]);
1031 }
1032
1033 public: // Create a .dot file that can be compiled with neato to produce a .pdf file.
1038 void plot_DOT() {
1039 std::string mapp = point_cloud_name + "_sc.dot";
1040 std::ofstream graphic(mapp);
1041
1042 double maxv = std::numeric_limits<double>::lowest();
1043 double minv = (std::numeric_limits<double>::max)();
1044 for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
1045 maxv = (std::max)(maxv, iit->second.second);
1046 minv = (std::min)(minv, iit->second.second);
1047 }
1048
1049 int k = 0;
1050 std::vector<int> nodes;
1051 nodes.clear();
1052
1053 graphic << "graph GIC {" << std::endl;
1054 int id = 0;
1055 for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
1056 if (iit->second.first > mask) {
1057 nodes.push_back(iit->first);
1058 name2id[iit->first] = id;
1059 name2idinv[id] = iit->first;
1060 id++;
1061 graphic << name2id[iit->first] << "[shape=circle fontcolor=black color=black label=\"" << name2id[iit->first]
1062 << ":" << iit->second.first << "\" style=filled fillcolor=\""
1063 << (1 - (maxv - iit->second.second) / (maxv - minv)) * 0.6 << ", 1, 1\"]" << std::endl;
1064 k++;
1065 }
1066 }
1067 int ke = 0;
1068 int num_simplices = simplices.size();
1069 for (int i = 0; i < num_simplices; i++)
1070 if (simplices[i].size() == 2) {
1071 if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) {
1072 graphic << " " << name2id[simplices[i][0]] << " -- " << name2id[simplices[i][1]] << " [weight=15];"
1073 << std::endl;
1074 ke++;
1075 }
1076 }
1077 graphic << "}";
1078 graphic.close();
1079 std::clog << mapp << " file generated. It can be visualized with e.g. neato." << std::endl;
1080 }
1081
1082 public: // Create a .txt file that can be compiled with KeplerMapper.
1086 void write_info() {
1087 int num_simplices = simplices.size();
1088 int num_edges = 0;
1089 std::string mapp = point_cloud_name + "_sc.txt";
1090 std::ofstream graphic(mapp);
1091
1092 for (int i = 0; i < num_simplices; i++)
1093 if (simplices[i].size() == 2)
1094 if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) num_edges++;
1095
1096 graphic << point_cloud_name << std::endl;
1097 graphic << cover_name << std::endl;
1098 graphic << color_name << std::endl;
1099 graphic << resolution_double << " " << gain << std::endl;
1100 graphic << cover_color.size() << " " << num_edges << std::endl;
1101
1102 int id = 0;
1103 for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) {
1104 graphic << id << " " << iit->second.second << " " << iit->second.first << std::endl;
1105 name2id[iit->first] = id;
1106 name2idinv[id] = iit->first;
1107 id++;
1108 }
1109
1110 for (int i = 0; i < num_simplices; i++)
1111 if (simplices[i].size() == 2)
1112 if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask)
1113 graphic << name2id[simplices[i][0]] << " " << name2id[simplices[i][1]] << std::endl;
1114 graphic.close();
1115 std::clog << mapp
1116 << " generated. It can be visualized with e.g. python KeplerMapperVisuFromTxtFile.py and firefox."
1117 << std::endl;
1118 }
1119
1120 public: // Create a .off file that can be visualized (e.g. with Geomview).
1125 void plot_OFF() {
1126 assert(cover_name == "Voronoi");
1127
1128 int m = voronoi_subsamples.size();
1129 int numedges = 0;
1130 int numfaces = 0;
1131 std::vector<std::vector<int> > edges, faces;
1132 int numsimplices = simplices.size();
1133
1134 std::string mapp = point_cloud_name + "_sc.off";
1135 std::ofstream graphic(mapp);
1136
1137 graphic << "OFF" << std::endl;
1138 for (int i = 0; i < numsimplices; i++) {
1139 if (simplices[i].size() == 2) {
1140 numedges++;
1141 edges.push_back(simplices[i]);
1142 }
1143 if (simplices[i].size() == 3) {
1144 numfaces++;
1145 faces.push_back(simplices[i]);
1146 }
1147 }
1148 graphic << m << " " << numedges + numfaces << std::endl;
1149 for (int i = 0; i < m; i++) {
1150 if (data_dimension <= 3) {
1151 for (int j = 0; j < data_dimension; j++) graphic << point_cloud[voronoi_subsamples[i]][j] << " ";
1152 for (int j = data_dimension; j < 3; j++) graphic << 0 << " ";
1153 graphic << std::endl;
1154 } else {
1155 for (int j = 0; j < 3; j++) graphic << point_cloud[voronoi_subsamples[i]][j] << " ";
1156 }
1157 }
1158 for (int i = 0; i < numedges; i++) graphic << 2 << " " << edges[i][0] << " " << edges[i][1] << std::endl;
1159 for (int i = 0; i < numfaces; i++)
1160 graphic << 3 << " " << faces[i][0] << " " << faces[i][1] << " " << faces[i][2] << std::endl;
1161 graphic.close();
1162 std::clog << mapp << " generated. It can be visualized with e.g. geomview." << std::endl;
1163 }
1164
1165 // *******************************************************************************************************************
1166 // Extended Persistence Diagrams.
1167 // *******************************************************************************************************************
1168
1169 public:
1173 Persistence_diagram compute_PD() {
1174 Simplex_tree st;
1175
1176 // Compute max and min
1177 double maxf = std::numeric_limits<double>::lowest();
1178 double minf = (std::numeric_limits<double>::max)();
1179 for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) {
1180 maxf = (std::max)(maxf, it->second);
1181 minf = (std::min)(minf, it->second);
1182 }
1183
1184 // Build filtration
1185 for (auto const& simplex : simplices) {
1186 std::vector<int> splx = simplex;
1187 splx.push_back(-2);
1188 st.insert_simplex_and_subfaces(splx, -3);
1189 }
1190
1191 for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) {
1192 int vertex = it->first; float val = it->second;
1193 int vert[] = {vertex}; int edge[] = {vertex, -2};
1194 if(st.find(vert) != st.null_simplex()){
1195 st.assign_filtration(st.find(vert), -2 + (val - minf)/(maxf - minf));
1196 st.assign_filtration(st.find(edge), 2 - (val - minf)/(maxf - minf));
1197 }
1198 }
1200
1201 // Compute PD
1204
1205 // Output PD
1206 int max_dim = st.dimension();
1207 for (int i = 0; i < max_dim; i++) {
1208 std::vector<std::pair<double, double> > bars = pcoh.intervals_in_dimension(i);
1209 int num_bars = bars.size(); if(i == 0) num_bars -= 1;
1210 if(verbose) std::clog << num_bars << " interval(s) in dimension " << i << ":" << std::endl;
1211 for (int j = 0; j < num_bars; j++) {
1212 double birth = bars[j].first;
1213 double death = bars[j].second;
1214 if (i == 0 && std::isinf(death)) continue;
1215 if (birth < 0)
1216 birth = minf + (birth + 2) * (maxf - minf);
1217 else
1218 birth = minf + (2 - birth) * (maxf - minf);
1219 if (death < 0)
1220 death = minf + (death + 2) * (maxf - minf);
1221 else
1222 death = minf + (2 - death) * (maxf - minf);
1223 PD.push_back(std::pair<double, double>(birth, death));
1224 if (verbose) std::clog << " [" << birth << ", " << death << "]" << std::endl;
1225 }
1226 }
1227 return PD;
1228 }
1229
1230 public:
1236 void compute_distribution(unsigned int N = 100) {
1237 unsigned int sz = distribution.size();
1238 if (sz < N) {
1239 for (unsigned int i = 0; i < N - sz; i++) {
1240 if (verbose) std::clog << "Computing " << i << "th bootstrap, bottleneck distance = ";
1241
1242 Cover_complex Cboot; Cboot.num_points = this->num_points; Cboot.data_dimension = this->data_dimension; Cboot.type = this->type; Cboot.functional_cover = true;
1243
1244 std::vector<int> boot(this->num_points);
1245 for (int j = 0; j < this->num_points; j++) {
1246 double u = GetUniform();
1247 int id = std::floor(u * (this->num_points)); boot[j] = id;
1248 Cboot.point_cloud.push_back(this->point_cloud[id]); Cboot.cover.emplace_back(); Cboot.func.push_back(this->func[id]);
1249 boost::add_vertex(Cboot.one_skeleton_OFF); Cboot.vertices.push_back(boost::add_vertex(Cboot.one_skeleton));
1250 }
1251 Cboot.set_color_from_range(Cboot.func);
1252
1253 for (int j = 0; j < this->num_points; j++) {
1254 std::vector<double> dist(this->num_points);
1255 for (int k = 0; k < this->num_points; k++) dist[k] = distances[boot[j]][boot[k]];
1256 Cboot.distances.push_back(dist);
1257 }
1258
1260 Cboot.set_gain();
1263 Cboot.find_simplices();
1264 Cboot.compute_PD();
1265#ifdef GUDHI_GIC_USE_CGAL
1266 double db = Gudhi::persistence_diagram::bottleneck_distance(this->PD, Cboot.PD);
1267#elif defined GUDHI_GIC_USE_HERA
1268 double db = hera::bottleneckDistExact(this->PD, Cboot.PD);
1269#else
1270 double db;
1271 throw std::logic_error("This function requires CGAL or Hera for the bottleneck distance.");
1272#endif
1273 if (verbose) std::clog << db << std::endl;
1274 distribution.push_back(db);
1275 }
1276
1277 std::sort(distribution.begin(), distribution.end());
1278 }
1279 }
1280
1281 public:
1288 unsigned int N = distribution.size();
1289 double d = distribution[std::floor(alpha * N)];
1290 if (verbose) std::clog << "Distance corresponding to confidence " << alpha << " is " << d << std::endl;
1291 return d;
1292 }
1293
1294 public:
1301 unsigned int N = distribution.size();
1302 double level = 1;
1303 for (unsigned int i = 0; i < N; i++)
1304 if (distribution[i] >= d){ level = i * 1.0 / N; break; }
1305 if (verbose) std::clog << "Confidence level of distance " << d << " is " << level << std::endl;
1306 return level;
1307 }
1308
1309 public:
1315 double distancemin = (std::numeric_limits<double>::max)(); int N = PD.size();
1316 for (int i = 0; i < N; i++) distancemin = (std::min)(distancemin, 0.5 * std::abs(PD[i].second - PD[i].first));
1317 double p_value = 1 - compute_confidence_level_from_distance(distancemin);
1318 if (verbose) std::clog << "p value = " << p_value << std::endl;
1319 return p_value;
1320 }
1321
1322 // *******************************************************************************************************************
1323 // Computation of simplices.
1324 // *******************************************************************************************************************
1325
1326 public:
1332 template <typename SimplicialComplex>
1333 void create_complex(SimplicialComplex& complex) {
1334 unsigned int dimension = 0;
1335 for (auto const& simplex : simplices) {
1336 int numvert = simplex.size();
1337 double filt = std::numeric_limits<double>::lowest();
1338 for (int i = 0; i < numvert; i++) filt = (std::max)(cover_color[simplex[i]].second, filt);
1339 complex.insert_simplex_and_subfaces(simplex, filt);
1340 if (dimension < simplex.size() - 1) dimension = simplex.size() - 1;
1341 }
1342 }
1343
1344 public:
1348 if (type != "Nerve" && type != "GIC") {
1349 std::cerr << "Type of complex needs to be specified." << std::endl;
1350 return;
1351 }
1352
1353 if (type == "Nerve") {
1354 simplices = cover;
1355 std::sort(simplices.begin(), simplices.end());
1356 std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
1357 simplices.resize(std::distance(simplices.begin(), it));
1358 }
1359
1360 if (type == "GIC") {
1361 Index_map index = boost::get(boost::vertex_index, one_skeleton);
1362
1363 if (functional_cover) {
1364 // Computes the simplices in the GIC by looking at all the edges of the graph and adding the
1365 // corresponding edges in the GIC if the images of the endpoints belong to consecutive intervals.
1366
1367 if (gain >= 0.5)
1368 throw std::invalid_argument(
1369 "the output of this function is correct ONLY if the cover is minimal, i.e. the gain is less than 0.5.");
1370
1371 // Loop on all edges.
1372 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
1373 for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) {
1374 int nums = cover[index[boost::source(*ei, one_skeleton)]].size();
1375 for (int i = 0; i < nums; i++) {
1376 int vs = cover[index[boost::source(*ei, one_skeleton)]][i];
1377 int numt = cover[index[boost::target(*ei, one_skeleton)]].size();
1378 for (int j = 0; j < numt; j++) {
1379 int vt = cover[index[boost::target(*ei, one_skeleton)]][j];
1380 if (cover_fct[vs] == cover_fct[vt] + 1 || cover_fct[vt] == cover_fct[vs] + 1) {
1381 std::vector<int> edge(2);
1382 edge[0] = (std::min)(vs, vt);
1383 edge[1] = (std::max)(vs, vt);
1384 simplices.push_back(edge);
1385 goto afterLoop;
1386 }
1387 }
1388 }
1389 afterLoop:;
1390 }
1391 std::sort(simplices.begin(), simplices.end());
1392 std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
1393 simplices.resize(std::distance(simplices.begin(), it));
1394
1395 } else {
1396 // Find edges to keep
1397 Simplex_tree st;
1398 boost::graph_traits<Graph>::edge_iterator ei, ei_end;
1399 for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei)
1400 if (!(cover[index[boost::target(*ei, one_skeleton)]].size() == 1 &&
1401 cover[index[boost::target(*ei, one_skeleton)]] == cover[index[boost::source(*ei, one_skeleton)]])) {
1402 std::vector<int> edge(2);
1403 edge[0] = index[boost::source(*ei, one_skeleton)];
1404 edge[1] = index[boost::target(*ei, one_skeleton)];
1406 }
1407
1408 // st.insert_graph(one_skeleton);
1409
1410 // Build the Simplex Tree corresponding to the graph
1411 st.expansion(maximal_dim);
1412
1413 // Find simplices of GIC
1414 simplices.clear();
1415 for (auto simplex : st.complex_simplex_range()) {
1416 if (!st.has_children(simplex)) {
1417 std::vector<int> simplx;
1418 for (auto vertex : st.simplex_vertex_range(simplex)) {
1419 unsigned int sz = cover[vertex].size();
1420 for (unsigned int i = 0; i < sz; i++) {
1421 simplx.push_back(cover[vertex][i]);
1422 }
1423 }
1424 std::sort(simplx.begin(), simplx.end());
1425 std::vector<int>::iterator it = std::unique(simplx.begin(), simplx.end());
1426 simplx.resize(std::distance(simplx.begin(), it));
1427 simplices.push_back(simplx);
1428 }
1429 }
1430 std::sort(simplices.begin(), simplices.end());
1431 std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end());
1432 simplices.resize(std::distance(simplices.begin(), it));
1433 }
1434 }
1435 }
1436};
1437
1438} // namespace cover_complex
1439
1440} // namespace Gudhi
1441
1442#endif // GIC_H_
Compute the Euclidean distance between two Points given by a range of coordinates....
Definition: distance_functions.h:32
Options::Filtration_value Filtration_value
Type for the value of the filtration function.
Definition: Simplex_tree.h:102
void assign_filtration(Simplex_handle sh, Filtration_value fv)
Sets the filtration value of a simplex.
Definition: Simplex_tree.h:625
bool make_filtration_non_decreasing()
This function ensures that each simplex has a higher filtration value than its faces by increasing th...
Definition: Simplex_tree.h:1895
Simplex_vertex_range simplex_vertex_range(Simplex_handle sh) const
Returns a range over the vertices of a simplex.
Definition: Simplex_tree.h:349
bool has_children(SimplexHandle sh) const
Returns true if the node in the simplex tree pointed by the given simplex handle has children.
Definition: Simplex_tree.h:742
Simplex_handle find(const InputVertexRange &s)
Given a range of Vertex_handles, returns the Simplex_handle of the simplex in the simplicial complex ...
Definition: Simplex_tree.h:767
void expansion(int max_dim)
Expands the Simplex_tree containing only its one skeleton until dimension max_dim.
Definition: Simplex_tree.h:1360
std::pair< Simplex_handle, bool > insert_simplex_and_subfaces(const InputVertexRange &Nsimplex, Filtration_value filtration=0)
Insert a N-simplex and all his subfaces, from a N-simplex represented by a range of Vertex_handles,...
Definition: Simplex_tree.h:942
static Simplex_handle null_simplex()
Returns a Simplex_handle different from all Simplex_handles associated to the simplices in the simpli...
Definition: Simplex_tree.h:635
Complex_simplex_range complex_simplex_range()
Returns a range over the simplices of the simplicial complex.
Definition: Simplex_tree.h:304
Cover complex data structure.
Definition: GIC.h:99
void set_function_from_file(const std::string &func_file_name)
Creates the function f from a file containing the function values.
Definition: GIC.h:485
double set_automatic_resolution()
Computes the optimal length of intervals (i.e. the smallest interval length avoiding discretization a...
Definition: GIC.h:544
void set_cover_from_Voronoi(Distance distance, int m=100)
Creates the cover C from the Voronoï cells of a subsampling of the point cloud.
Definition: GIC.h:897
void set_resolution_with_interval_number(int reso)
Sets a number of intervals from a value stored in memory.
Definition: GIC.h:591
void set_mask(int nodemask)
Sets the mask, which is a threshold integer such that nodes in the complex that contain a number of d...
Definition: GIC.h:219
Persistence_diagram compute_PD()
Computes the extended persistence diagram of the complex.
Definition: GIC.h:1173
double compute_distance_from_confidence_level(double alpha)
Computes the bottleneck distance threshold corresponding to a specific confidence level.
Definition: GIC.h:1287
void set_graph_from_rips(double threshold, Distance distance)
Creates a graph G from a Rips complex.
Definition: GIC.h:360
void set_cover_from_file(const std::string &cover_file_name)
Creates the cover C from a file containing the cover elements of each point (the order has to be the ...
Definition: GIC.h:827
void set_graph_from_file(const std::string &graph_file_name)
Creates a graph G from a file containing the edges.
Definition: GIC.h:327
void set_cover_from_range(AssignmentRange const &assignments)
Creates the cover C from a vector of assignments stored in memory. The assignments,...
Definition: GIC.h:865
void create_complex(SimplicialComplex &complex)
Creates the simplicial complex.
Definition: GIC.h:1333
void set_type(const std::string &t)
Specifies whether the type of the output simplicial complex.
Definition: GIC.h:188
void set_distances_from_range(const std::vector< std::vector< double > > &distance_matrix)
Reads and stores the distance matrices from vector stored in memory.
Definition: GIC.h:390
void find_simplices()
Computes the simplices of the simplicial complex.
Definition: GIC.h:1347
void set_function_from_range(InputRange const &function)
Creates the function f from a vector stored in memory.
Definition: GIC.h:527
void set_cover_from_function()
Creates a cover C from the preimages of the function f.
Definition: GIC.h:603
double subcolor(int c)
Returns the mean color corresponding to a specific node of the created complex.
Definition: GIC.h:976
void set_color_from_file(const std::string &color_file_name)
Computes the function used to color the nodes of the simplicial complex from a file containing the fu...
Definition: GIC.h:989
void write_info()
Creates a .txt file called SC.txt describing the 1-skeleton, which can then be plotted with e....
Definition: GIC.h:1086
void plot_OFF()
Creates a .off file called SC.off for 3D visualization, which contains the 2-skeleton of the GIC....
Definition: GIC.h:1125
void plot_DOT()
Creates a .dot file called SC.dot for neato (part of the graphviz package) once the simplicial comple...
Definition: GIC.h:1038
void set_color_from_range(std::vector< double > color)
Computes the function used to color the nodes of the simplicial complex from a vector stored in memor...
Definition: GIC.h:1029
void set_subsampling(double constant, double power)
Sets the constants used to subsample the data set. These constants are explained in .
Definition: GIC.h:206
void set_point_cloud_from_range(const std::vector< std::vector< double > > &point_cloud)
Reads and stores the input point cloud from vector stored in memory.
Definition: GIC.h:229
double set_graph_from_automatic_rips(Distance distance, int N=100)
Creates a graph G from a Rips complex whose threshold value is automatically tuned with subsampling—s...
Definition: GIC.h:431
void set_resolution_with_interval_length(double reso)
Sets a length of intervals from a value stored in memory.
Definition: GIC.h:585
const std::vector< int > & subpopulation(int c)
Returns the data subset corresponding to a specific node of the created complex.
Definition: GIC.h:966
void set_gain(double g=0.3)
Sets a gain from a value stored in memory (default value 0.3).
Definition: GIC.h:597
void set_function_from_coordinate(int k)
Creates the function f from the k-th coordinate of the point cloud P.
Definition: GIC.h:506
void set_color_from_coordinate(int k=0)
Computes the function used to color the nodes of the simplicial complex from the k-th coordinate.
Definition: GIC.h:1009
void compute_distribution(unsigned int N=100)
Computes bootstrapped distances distribution.
Definition: GIC.h:1236
double compute_confidence_level_from_distance(double d)
Computes the confidence level of a specific bottleneck distance threshold.
Definition: GIC.h:1300
void set_graph_from_OFF()
Creates a graph G from the triangulation given by the input .OFF file.
Definition: GIC.h:344
double compute_p_value()
Computes the p-value, i.e. the opposite of the confidence level of the largest bottleneck distance pr...
Definition: GIC.h:1314
bool read_point_cloud(const std::string &off_file_name)
Reads and stores the input point cloud from .(n)OFF file.
Definition: GIC.h:244
void set_verbose(bool verb=false)
Specifies whether the program should display information or not.
Definition: GIC.h:196
Computes the persistent cohomology of a filtered complex.
Definition: Persistent_cohomology.h:54
std::vector< std::pair< Filtration_value, Filtration_value > > intervals_in_dimension(int dimension)
Returns persistence intervals for a given dimension.
Definition: Persistent_cohomology.h:677
void compute_persistent_cohomology(Filtration_value min_interval_length=0)
Compute the persistent homology of the filtered simplicial complex.
Definition: Persistent_cohomology.h:168
void init_coefficients(int charac)
Initializes the coefficient field.
Definition: Persistent_cohomology.h:152
Rips complex data structure.
Definition: Rips_complex.h:45
Global distance functions.
Graph simplicial complex methods.
double bottleneck_distance(const Persistence_diagram1 &diag1, const Persistence_diagram2 &diag2, double e=(std::numeric_limits< double >::min)())
Function to compute the Bottleneck distance between two persistence diagrams.
Definition: Bottleneck.h:116
This file includes common file reader for GUDHI.
Value type for a filtration function on a cell complex.
Definition: FiltrationValue.h:20