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