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