diff options
Diffstat (limited to 'src/Nerve_GIC')
-rw-r--r-- | src/Nerve_GIC/doc/Intro_graph_induced_complex.h | 10 | ||||
-rw-r--r-- | src/Nerve_GIC/example/CoordGIC.cpp | 2 | ||||
-rw-r--r-- | src/Nerve_GIC/example/FuncGIC.cpp | 4 | ||||
-rw-r--r-- | src/Nerve_GIC/example/GIC.cpp | 2 | ||||
-rwxr-xr-x | src/Nerve_GIC/example/KeplerMapperVisuFromTxtFile.py | 2 | ||||
-rw-r--r-- | src/Nerve_GIC/example/Nerve.cpp | 14 | ||||
-rw-r--r-- | src/Nerve_GIC/example/VoronoiGIC.cpp | 2 | ||||
-rw-r--r-- | src/Nerve_GIC/include/gudhi/GIC.h | 910 |
8 files changed, 379 insertions, 567 deletions
diff --git a/src/Nerve_GIC/doc/Intro_graph_induced_complex.h b/src/Nerve_GIC/doc/Intro_graph_induced_complex.h index 6668d850..7578cc53 100644 --- a/src/Nerve_GIC/doc/Intro_graph_induced_complex.h +++ b/src/Nerve_GIC/doc/Intro_graph_induced_complex.h @@ -70,7 +70,7 @@ namespace cover_complex { * * When launching: * - * \code $> ./Nerve ../../../../data/points/human.off 2 10 0.3 --v + * \code $> ./Nerve ../../data/points/human.off 2 10 0.3 --v * \endcode * * the program output is: @@ -113,7 +113,7 @@ namespace cover_complex { * * When launching: * - * \code $> ./VoronoiGIC ../../../../data/points/human.off 700 --v + * \code $> ./VoronoiGIC ../../data/points/human.off 700 --v * \endcode * * the program outputs SC.off. Using e.g. @@ -146,7 +146,7 @@ namespace cover_complex { * * When launching: * - * \code $> ./CoordGIC ../../../../data/points/KleinBottle5D.off 0 --v + * \code $> ./CoordGIC ../../data/points/KleinBottle5D.off 0 --v * \endcode * * the program outputs SC.dot. Using e.g. @@ -169,7 +169,7 @@ namespace cover_complex { * * When launching: * - * \code $> ./FuncGIC ../../../../data/points/COIL_database/lucky_cat.off ../../../../data/points/COIL_database/lucky_cat_PCA1 --v + * \code $> ./FuncGIC ../../data/points/COIL_database/lucky_cat.off ../../data/points/COIL_database/lucky_cat_PCA1 --v * \endcode * * the program outputs again SC.dot which gives the following visualization after using neato: @@ -201,7 +201,7 @@ namespace cover_complex { * * When launching: * - * \code $> ./GIC ../../../../data/points/human.off 0.075 2 0.075 0 --v + * \code $> ./GIC ../../data/points/human.off 0.075 2 0.075 0 --v * \endcode * * the program outputs SC.txt, which can be visualized with python and firefox as before: diff --git a/src/Nerve_GIC/example/CoordGIC.cpp b/src/Nerve_GIC/example/CoordGIC.cpp index 0d06c2ba..c03fcbb3 100644 --- a/src/Nerve_GIC/example/CoordGIC.cpp +++ b/src/Nerve_GIC/example/CoordGIC.cpp @@ -28,7 +28,7 @@ void usage(int nbArgs, char *const progName) { std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; std::cerr << "Usage: " << progName << " filename.off coordinate [--v] \n"; - std::cerr << " i.e.: " << progName << " ../../../../data/points/human.off 2 --v \n"; + std::cerr << " i.e.: " << progName << " ../../data/points/human.off 2 --v \n"; exit(-1); // ----- >> } diff --git a/src/Nerve_GIC/example/FuncGIC.cpp b/src/Nerve_GIC/example/FuncGIC.cpp index 081b3a2f..3762db4e 100644 --- a/src/Nerve_GIC/example/FuncGIC.cpp +++ b/src/Nerve_GIC/example/FuncGIC.cpp @@ -28,8 +28,8 @@ void usage(int nbArgs, char *const progName) { std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; std::cerr << "Usage: " << progName << " filename.off function [--v] \n"; - std::cerr << " i.e.: " << progName << " ../../../../data/points/COIL_database/lucky_cat.off " - "../../../../data/points/COIL_database/lucky_cat_PCA1 --v \n"; + std::cerr << " i.e.: " << progName << " ../../data/points/COIL_database/lucky_cat.off " + "../../data/points/COIL_database/lucky_cat_PCA1 --v \n"; exit(-1); // ----- >> } diff --git a/src/Nerve_GIC/example/GIC.cpp b/src/Nerve_GIC/example/GIC.cpp index 2f10fd17..2bc24a4d 100644 --- a/src/Nerve_GIC/example/GIC.cpp +++ b/src/Nerve_GIC/example/GIC.cpp @@ -28,7 +28,7 @@ void usage(int nbArgs, char *const progName) { std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; std::cerr << "Usage: " << progName << " filename.off threshold coordinate resolution gain [--v] \n"; - std::cerr << " i.e.: " << progName << " ../../../../data/points/human.off 0.075 2 0.075 0 --v \n"; + std::cerr << " i.e.: " << progName << " ../../data/points/human.off 0.075 2 0.075 0 --v \n"; exit(-1); // ----- >> } diff --git a/src/Nerve_GIC/example/KeplerMapperVisuFromTxtFile.py b/src/Nerve_GIC/example/KeplerMapperVisuFromTxtFile.py index 406264ba..d2897774 100755 --- a/src/Nerve_GIC/example/KeplerMapperVisuFromTxtFile.py +++ b/src/Nerve_GIC/example/KeplerMapperVisuFromTxtFile.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import km import numpy as np from collections import defaultdict diff --git a/src/Nerve_GIC/example/Nerve.cpp b/src/Nerve_GIC/example/Nerve.cpp index 6460836d..6abdedc7 100644 --- a/src/Nerve_GIC/example/Nerve.cpp +++ b/src/Nerve_GIC/example/Nerve.cpp @@ -25,21 +25,19 @@ #include <string> #include <vector> -using namespace std; - void usage(int nbArgs, char *const progName) { - cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; - cerr << "Usage: " << progName << " filename.off coordinate resolution gain [--v] \n"; - cerr << " i.e.: " << progName << " ../../../../data/points/human.off 2 10 0.3 --v \n"; + std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; + std::cerr << "Usage: " << progName << " filename.off coordinate resolution gain [--v] \n"; + std::cerr << " i.e.: " << progName << " ../../data/points/human.off 2 10 0.3 --v \n"; exit(-1); // ----- >> } int main(int argc, char **argv) { if ((argc != 5) && (argc != 6)) usage(argc, argv[0]); - using Point = vector<float>; + using Point = std::vector<float>; - string off_file_name(argv[1]); + std::string off_file_name(argv[1]); int coord = atoi(argv[2]); int resolution = atoi(argv[3]); double gain = atof(argv[4]); @@ -56,7 +54,7 @@ int main(int argc, char **argv) { bool check = SC.read_point_cloud(off_file_name); if (!check) { - cout << "Incorrect OFF file." << endl; + std::cout << "Incorrect OFF file." << std::endl; } else { SC.set_type("Nerve"); diff --git a/src/Nerve_GIC/example/VoronoiGIC.cpp b/src/Nerve_GIC/example/VoronoiGIC.cpp index 41ac9e5f..32431cc2 100644 --- a/src/Nerve_GIC/example/VoronoiGIC.cpp +++ b/src/Nerve_GIC/example/VoronoiGIC.cpp @@ -28,7 +28,7 @@ void usage(int nbArgs, char *const progName) { std::cerr << "Error: Number of arguments (" << nbArgs << ") is not correct\n"; std::cerr << "Usage: " << progName << " filename.off N [--v] \n"; - std::cerr << " i.e.: " << progName << " ../../../../data/points/human.off 100 --v \n"; + std::cerr << " i.e.: " << progName << " ../../data/points/human.off 100 --v \n"; exit(-1); // ----- >> } diff --git a/src/Nerve_GIC/include/gudhi/GIC.h b/src/Nerve_GIC/include/gudhi/GIC.h index 2bec27db..9dc754f4 100644 --- a/src/Nerve_GIC/include/gudhi/GIC.h +++ b/src/Nerve_GIC/include/gudhi/GIC.h @@ -55,14 +55,16 @@ namespace Gudhi { namespace cover_complex { -using Simplex_tree = Gudhi::Simplex_tree<>; -using Filtration_value = Simplex_tree::Filtration_value; -using Rips_complex = Gudhi::rips_complex::Rips_complex<Filtration_value>; -using PersistenceDiagram = std::vector<std::pair<double,double> >; -using Graph = boost::subgraph<boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, boost::no_property, boost::property<boost::edge_index_t, int, boost::property<boost::edge_weight_t, double> > > >; -using vertex_t = boost::graph_traits<Graph>::vertex_descriptor; -using IndexMap = boost::property_map<Graph, boost::vertex_index_t>::type; -using WeightMap = boost::property_map<Graph, boost::edge_weight_t>::type; +using Simplex_tree = Gudhi::Simplex_tree<>; +using Filtration_value = Simplex_tree::Filtration_value; +using Rips_complex = Gudhi::rips_complex::Rips_complex<Filtration_value>; +using PersistenceDiagram = std::vector<std::pair<double, double> >; +using Graph = boost::subgraph< + boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, boost::no_property, + boost::property<boost::edge_index_t, int, boost::property<boost::edge_weight_t, double> > > >; +using vertex_t = boost::graph_traits<Graph>::vertex_descriptor; +using IndexMap = boost::property_map<Graph, boost::vertex_index_t>::type; +using WeightMap = boost::property_map<Graph, boost::edge_weight_t>::type; /** * \class Cover_complex @@ -87,7 +89,6 @@ using WeightMap = boost::property_map<Graph, boost::edge_weight_t>::ty template <typename Point> class Cover_complex { private: - bool verbose = false; // whether to display information. std::string type; // Nerve or GIC @@ -97,25 +98,31 @@ class Cover_complex { int data_dimension; // dimension of input data. int n; // number of points. - std::map<int, double> func; // function used to compute the output simplicial complex. - std::map<int, double> func_color; // function used to compute the colors of the nodes of the output simplicial complex. - bool functional_cover = false; // whether we use a cover with preimages of a function or not. + std::map<int, double> func; // function used to compute the output simplicial complex. + std::map<int, double> + func_color; // function used to compute the colors of the nodes of the output simplicial complex. + bool functional_cover = false; // whether we use a cover with preimages of a function or not. Graph one_skeleton_OFF; // one-skeleton given by the input OFF file (if it exists). Graph one_skeleton; // one-skeleton used to compute the connected components. std::vector<vertex_t> vertices; // vertices of one_skeleton. - std::vector<std::vector<int> > simplices; // simplices of output simplicial complex. - std::vector<int> voronoi_subsamples; // Voronoi germs (in case of Voronoi cover). + std::vector<std::vector<int> > simplices; // simplices of output simplicial complex. + std::vector<int> voronoi_subsamples; // Voronoi germs (in case of Voronoi cover). PersistenceDiagram PD; std::vector<double> distribution; - std::map<int, std::vector<int> > cover; // function associating to each data point its vectors of cover elements to which it belongs. - std::map<int, std::vector<int> > cover_back; // inverse of cover, in order to get the data points associated to a specific cover element. - std::map<int, double> cover_std; // standard function (induced by func) used to compute the extended persistence diagram of the output simplicial complex. - std::map<int, int> cover_fct; // integer-valued function that allows to state if two elements of the cover are consecutive or not. - std::map<int, std::pair<int, double> > cover_color; // size and coloring (induced by func_color) of the vertices of the output simplicial complex. + std::map<int, std::vector<int> > + cover; // function associating to each data point its vectors of cover elements to which it belongs. + std::map<int, std::vector<int> > + cover_back; // inverse of cover, in order to get the data points associated to a specific cover element. + std::map<int, double> cover_std; // standard function (induced by func) used to compute the extended persistence + // diagram of the output simplicial complex. + std::map<int, int> + cover_fct; // integer-valued function that allows to state if two elements of the cover are consecutive or not. + std::map<int, std::pair<int, double> > + cover_color; // size and coloring (induced by func_color) of the vertices of the output simplicial complex. int resolution_int = -1; double resolution_double = -1; @@ -124,21 +131,12 @@ class Cover_complex { double rate_power = 0.001; // Power in the subsampling. int mask = 0; // Ignore nodes containing less than mask points. - std::map<int,int> name2id, name2idinv; + std::map<int, int> name2id, name2idinv; std::string cover_name; std::string point_cloud_name; std::string color_name; - - - - - - - - - // Point comparator struct Less { Less(std::map<int, double> func) { Fct = func; } @@ -152,9 +150,9 @@ class Cover_complex { }; // Remove all edges of a graph. - void remove_edges(Graph & G){ + void remove_edges(Graph& G) { boost::graph_traits<Graph>::edge_iterator ei, ei_end; - for (boost::tie(ei, ei_end) = boost::edges(G); ei != ei_end; ++ei) boost::remove_edge(*ei, G); + for (boost::tie(ei, ei_end) = boost::edges(G); ei != ei_end; ++ei) boost::remove_edge(*ei, G); } // Find random number in [0,1]. @@ -165,20 +163,22 @@ class Cover_complex { } // Subsample points. - void SampleWithoutReplacement(int populationSize, int sampleSize, std::vector<int> & samples) { - int t = 0; int m = 0; double u; - while (m < sampleSize){ + void SampleWithoutReplacement(int populationSize, int sampleSize, std::vector<int>& samples) { + int t = 0; + int m = 0; + double u; + while (m < sampleSize) { u = GetUniform(); - if ((populationSize - t) * u >= sampleSize - m) t++; - else{ samples[m] = t; t++; m++;} + if ((populationSize - t) * u >= sampleSize - m) + t++; + else { + samples[m] = t; + t++; + m++; + } } } - - - - - // ******************************************************************************************************************* // Utils. // ******************************************************************************************************************* @@ -189,7 +189,7 @@ class Cover_complex { * @param[in] t std::string (either "GIC" or "Nerve"). * */ - void set_type(const std::string & t) { type = t; } + void set_type(const std::string& t) { type = t; } public: /** \brief Specifies whether the program should display information or not. @@ -228,7 +228,7 @@ class Cover_complex { * @param[in] off_file_name name of the input .OFF or .nOFF file. * */ - bool read_point_cloud(const std::string & off_file_name) { + bool read_point_cloud(const std::string& off_file_name) { point_cloud_name = off_file_name; std::ifstream input(off_file_name); std::string line; @@ -236,13 +236,14 @@ class Cover_complex { char comment = '#'; while (comment == '#') { std::getline(input, line); - if (!line.empty() && !all_of(line.begin(), line.end(), (int(*)(int))isspace)) comment = line[line.find_first_not_of(' ')]; + if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace)) + comment = line[line.find_first_not_of(' ')]; } if (strcmp((char*)line.c_str(), "nOFF") == 0) { comment = '#'; while (comment == '#') { std::getline(input, line); - if (!line.empty() && !all_of(line.begin(), line.end(), (int(*)(int))isspace)) + if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace)) comment = line[line.find_first_not_of(' ')]; } std::stringstream stream(line); @@ -255,7 +256,8 @@ class Cover_complex { int numedges, numfaces, i, dim; while (comment == '#') { std::getline(input, line); - if (!line.empty() && !all_of(line.begin(), line.end(), (int(*)(int))isspace)) comment = line[line.find_first_not_of(' ')]; + if (!line.empty() && !all_of(line.begin(), line.end(), (int (*)(int))isspace)) + comment = line[line.find_first_not_of(' ')]; } std::stringstream stream(line); stream >> n; @@ -265,10 +267,14 @@ class Cover_complex { i = 0; while (i < n) { std::getline(input, line); - if (!line.empty() && line[line.find_first_not_of(' ')] != '#' && !all_of(line.begin(), line.end(), (int(*)(int))isspace)) { - std::stringstream iss(line); std::vector<double> point; point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>()); + if (!line.empty() && line[line.find_first_not_of(' ')] != '#' && + !all_of(line.begin(), line.end(), (int (*)(int))isspace)) { + std::stringstream iss(line); + std::vector<double> point; + point.assign(std::istream_iterator<double>(iss), std::istream_iterator<double>()); point_cloud.emplace_back(point.begin(), point.begin() + data_dimension); - boost::add_vertex(one_skeleton_OFF); vertices.push_back(boost::add_vertex(one_skeleton)); + boost::add_vertex(one_skeleton_OFF); + vertices.push_back(boost::add_vertex(one_skeleton)); i++; } } @@ -276,9 +282,12 @@ class Cover_complex { i = 0; while (i < numfaces) { std::getline(input, line); - if (!line.empty() && line[line.find_first_not_of(' ')] != '#' && !all_of(line.begin(), line.end(), (int(*)(int))isspace)) { - std::vector<int> simplex; std::stringstream iss(line); - simplex.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>()); dim = simplex[0]; + if (!line.empty() && line[line.find_first_not_of(' ')] != '#' && + !all_of(line.begin(), line.end(), (int (*)(int))isspace)) { + std::vector<int> simplex; + std::stringstream iss(line); + simplex.assign(std::istream_iterator<int>(iss), std::istream_iterator<int>()); + dim = simplex[0]; for (int j = 1; j <= dim; j++) for (int k = j + 1; k <= dim; k++) boost::add_edge(vertices[simplex[j]], vertices[simplex[k]], one_skeleton_OFF); @@ -289,23 +298,6 @@ class Cover_complex { return input.is_open(); } - - - - - - - - - - - - - - - - - // ******************************************************************************************************************* // Graphs. // ******************************************************************************************************************* @@ -318,12 +310,16 @@ class Cover_complex { * each edge being represented by the IDs of its two nodes. * */ - void set_graph_from_file(const std::string & graph_file_name){ + void set_graph_from_file(const std::string& graph_file_name) { remove_edges(one_skeleton); - int neighb; std::ifstream input(graph_file_name); std::string line; int source; - while (std::getline(input, line)){ - std::stringstream stream(line); stream >> source; - while (stream >> neighb) boost::add_edge(vertices[source], vertices[neighb], one_skeleton); + int neighb; + std::ifstream input(graph_file_name); + std::string line; + int source; + while (std::getline(input, line)) { + std::stringstream stream(line); + stream >> source; + while (stream >> neighb) boost::add_edge(vertices[source], vertices[neighb], one_skeleton); } } @@ -333,8 +329,10 @@ class Cover_complex { */ void set_graph_from_OFF() { remove_edges(one_skeleton); - if(num_edges(one_skeleton_OFF)) one_skeleton = one_skeleton_OFF; - else std::cout << "No triangulation read in OFF file!" << std::endl; + if (num_edges(one_skeleton_OFF)) + one_skeleton = one_skeleton_OFF; + else + std::cout << "No triangulation read in OFF file!" << std::endl; } public: // Set graph from Rips complex. @@ -347,23 +345,26 @@ class Cover_complex { template <typename Distance> void set_graph_from_rips(double threshold, Distance distance) { remove_edges(one_skeleton); - if(distances.size() == 0) compute_pairwise_distances(distance); - for(int i = 0; i < n; i++){ - for(int j = i+1; j < n; j++){ - if(distances[i][j] <= threshold){ + if (distances.size() == 0) compute_pairwise_distances(distance); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (distances[i][j] <= threshold) { boost::add_edge(vertices[i], vertices[j], one_skeleton); - boost::put(boost::edge_weight, one_skeleton, boost::edge(vertices[i], vertices[j], one_skeleton).first, distances[i][j]); + boost::put(boost::edge_weight, one_skeleton, boost::edge(vertices[i], vertices[j], one_skeleton).first, + distances[i][j]); } } } } public: - void set_graph_weights(){ - IndexMap index = boost::get(boost::vertex_index, one_skeleton); WeightMap weight = boost::get(boost::edge_weight, one_skeleton); + void set_graph_weights() { + IndexMap index = boost::get(boost::vertex_index, one_skeleton); + WeightMap weight = boost::get(boost::edge_weight, one_skeleton); boost::graph_traits<Graph>::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) - boost::put(weight, *ei, distances[index[boost::source(*ei, one_skeleton)]][index[boost::target(*ei, one_skeleton)]]); + boost::put(weight, *ei, + distances[index[boost::source(*ei, one_skeleton)]][index[boost::target(*ei, one_skeleton)]]); } public: // Pairwise distances. @@ -371,7 +372,9 @@ class Cover_complex { */ template <typename Distance> void compute_pairwise_distances(Distance ref_distance) { - double d; std::vector<double> zeros(n); for (int i = 0; i < n; i++) distances.push_back(zeros); + double d; + std::vector<double> zeros(n); + for (int i = 0; i < n; i++) distances.push_back(zeros); std::string distance = point_cloud_name; distance.append("_dist"); std::ifstream input(distance.c_str(), std::ios::out | std::ios::binary); @@ -381,19 +384,22 @@ class Cover_complex { for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { input.read((char*)&d, 8); - distances[i][j] = d; distances[j][i] = d; + distances[i][j] = d; + distances[j][i] = d; } } input.close(); } else { if (verbose) std::cout << "Computing distances..." << std::endl; - input.close(); std::ofstream output(distance, std::ios::out | std::ios::binary); + input.close(); + std::ofstream output(distance, std::ios::out | std::ios::binary); for (int i = 0; i < n; i++) { int state = (int)floor(100 * (i * 1.0 + 1) / n) % 10; if (state == 0 && verbose) std::cout << "\r" << state << "%" << std::flush; for (int j = i; j < n; j++) { double dis = ref_distance(point_cloud[i], point_cloud[j]); - distances[i][j] = dis; distances[j][i] = dis; + distances[i][j] = dis; + distances[j][i] = dis; output.write((char*)&dis, 8); } } @@ -441,29 +447,6 @@ class Cover_complex { return delta; } - - - - - - - - - - - - - - - - - - - - - - - // ******************************************************************************************************************* // Functions. // ******************************************************************************************************************* @@ -475,9 +458,15 @@ class Cover_complex { * */ void set_function_from_file(const std::string& func_file_name) { - int i = 0; std::ifstream input(func_file_name); std::string line; double f; + int i = 0; + std::ifstream input(func_file_name); + std::string line; + double f; while (std::getline(input, line)) { - std::stringstream stream(line); stream >> f; func.emplace(i, f); i++; + std::stringstream stream(line); + stream >> f; + func.emplace(i, f); + i++; } functional_cover = true; cover_name = func_file_name; @@ -504,32 +493,11 @@ class Cover_complex { * */ template <class InputRange> - void set_function_from_range(InputRange const& f) { - for (int i = 0; i < n; i++) func.emplace(i, f[i]); + void set_function_from_range(InputRange const& function) { + for (int i = 0; i < n; i++) func.emplace(i, function[i]); functional_cover = true; } - - - - - - - - - - - - - - - - - - - - - // ******************************************************************************************************************* // Covers. // ******************************************************************************************************************* @@ -552,12 +520,14 @@ class Cover_complex { return 0; } - double reso = 0; IndexMap index = boost::get(boost::vertex_index, one_skeleton); + double reso = 0; + IndexMap index = boost::get(boost::vertex_index, one_skeleton); if (type == "GIC") { boost::graph_traits<Graph>::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) - reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] - func[index[boost::target(*ei, one_skeleton)]])); + reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] - + func[index[boost::target(*ei, one_skeleton)]])); if (verbose) std::cout << "resolution = " << reso << std::endl; resolution_double = reso; } @@ -565,7 +535,9 @@ class Cover_complex { if (type == "Nerve") { boost::graph_traits<Graph>::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) - reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] - func[index[boost::target(*ei, one_skeleton)]]) / gain); + reso = std::max(reso, std::abs(func[index[boost::source(*ei, one_skeleton)]] - + func[index[boost::target(*ei, one_skeleton)]]) / + gain); if (verbose) std::cout << "resolution = " << reso << std::endl; resolution_double = reso; } @@ -608,14 +580,17 @@ class Cover_complex { } // Read function values and compute min and max - double minf = std::numeric_limits<float>::max(); double maxf = std::numeric_limits<float>::lowest(); + double minf = std::numeric_limits<float>::max(); + double maxf = std::numeric_limits<float>::lowest(); for (int i = 0; i < n; i++) { - minf = std::min(minf, func[i]); maxf = std::max(maxf, func[i]); + minf = std::min(minf, func[i]); + maxf = std::max(maxf, func[i]); } if (verbose) std::cout << "Min function value = " << minf << " and Max function value = " << maxf << std::endl; // Compute cover of im(f) - std::vector<std::pair<double, double> > intervals; int res; + std::vector<std::pair<double, double> > intervals; + int res; if (resolution_double == -1) { // Case we use an integer for the number of intervals. double incr = (maxf - minf) / resolution_int; @@ -637,7 +612,8 @@ class Cover_complex { res = intervals.size(); if (verbose) { for (int i = 0; i < res; i++) - std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" << std::endl; + std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" + << std::endl; } } else { if (resolution_int == -1) { // Case we use a double for the length of the intervals. @@ -654,7 +630,8 @@ class Cover_complex { res = intervals.size(); if (verbose) { for (int i = 0; i < res; i++) - std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" << std::endl; + std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" + << std::endl; } } else { // Case we use an integer and a double for the length of the intervals. double x = minf; @@ -670,82 +647,100 @@ class Cover_complex { res = intervals.size(); if (verbose) { for (int i = 0; i < res; i++) - std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" << std::endl; + std::cout << "Interval " << i << " = [" << intervals[i].first << ", " << intervals[i].second << "]" + << std::endl; } } } // Sort points according to function values - std::vector<int> points(n); for (int i = 0; i < n; i++) points[i] = i; + std::vector<int> points(n); + for (int i = 0; i < n; i++) points[i] = i; std::sort(points.begin(), points.end(), Less(this->func)); - int id = 0; int pos = 0; IndexMap index = boost::get(boost::vertex_index, one_skeleton); //int maxc = -1; - std::map<int, std::vector<int> > preimages; std::map<int, double> funcstd; - - if(verbose) std::cout << "Computing preimages..." << std::endl; - for (int i = 0; i < res; i++){ + int id = 0; + int pos = 0; + IndexMap index = boost::get(boost::vertex_index, one_skeleton); // int maxc = -1; + std::map<int, std::vector<int> > preimages; + std::map<int, double> funcstd; + if (verbose) std::cout << "Computing preimages..." << std::endl; + for (int i = 0; i < res; i++) { // Find points in the preimage - std::pair<double, double> inter1 = intervals[i]; int tmp = pos; double u, v; + std::pair<double, double> inter1 = intervals[i]; + int tmp = pos; + double u, v; if (i != res - 1) { - if (i != 0) { std::pair<double, double> inter3 = intervals[i - 1]; - while (func[points[tmp]] < inter3.second && tmp != n){preimages[i].push_back(points[tmp]); tmp++;} + while (func[points[tmp]] < inter3.second && tmp != n) { + preimages[i].push_back(points[tmp]); + tmp++; + } u = inter3.second; - } - else u = inter1.first; + } else + u = inter1.first; std::pair<double, double> inter2 = intervals[i + 1]; - while (func[points[tmp]] < inter2.first && tmp != n){preimages[i].push_back(points[tmp]); tmp++;} + while (func[points[tmp]] < inter2.first && tmp != n) { + preimages[i].push_back(points[tmp]); + tmp++; + } v = inter2.first; pos = tmp; - while (func[points[tmp]] < inter1.second && tmp != n){preimages[i].push_back(points[tmp]); tmp++;} + while (func[points[tmp]] < inter1.second && tmp != n) { + preimages[i].push_back(points[tmp]); + tmp++; + } } else { - std::pair<double, double> inter3 = intervals[i - 1]; - while (func[points[tmp]] < inter3.second && tmp != n){preimages[i].push_back(points[tmp]); tmp++;} - while (tmp != n){preimages[i].push_back(points[tmp]); tmp++;} - u = inter3.second; v = inter1.second; - + while (func[points[tmp]] < inter3.second && tmp != n) { + preimages[i].push_back(points[tmp]); + tmp++; + } + while (tmp != n) { + preimages[i].push_back(points[tmp]); + tmp++; + } + u = inter3.second; + v = inter1.second; } - funcstd[i] = 0.5*(u+v); - + funcstd[i] = 0.5 * (u + v); } - if(verbose) std::cout << "Computing connected components..." << std::endl; + if (verbose) std::cout << "Computing connected components..." << std::endl; // #pragma omp parallel for - for (int i = 0; i < res; i++){ - + for (int i = 0; i < res; i++) { // Compute connected components - Graph G = one_skeleton.create_subgraph(); int num = preimages[i].size(); std::vector<int> component(num); - for(int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G); - boost::connected_components(G, &component[0]); int max = 0; + Graph G = one_skeleton.create_subgraph(); + int num = preimages[i].size(); + std::vector<int> component(num); + for (int j = 0; j < num; j++) boost::add_vertex(index[vertices[preimages[i][j]]], G); + boost::connected_components(G, &component[0]); + int max = 0; // For each point in preimage - for(int j = 0; j < num; j++){ - + for (int j = 0; j < num; j++) { // Update number of components in preimage - if(component[j] > max) max = component[j]; + if (component[j] > max) max = component[j]; // Identify component with Cantor polynomial N^2 -> N - int identifier = (std::pow(i + component[j], 2) + 3*i + component[j])/2; + int identifier = (std::pow(i + component[j], 2) + 3 * i + component[j]) / 2; // Update covers - cover [preimages[i][j]] .push_back(identifier); - cover_back [identifier] .push_back(preimages[i][j]); - cover_fct [identifier] = i; - cover_std [identifier] = funcstd[i]; - cover_color [identifier] .second += func_color[preimages[i][j]]; - cover_color [identifier] .first += 1; + cover[preimages[i][j]].push_back(identifier); + cover_back[identifier].push_back(preimages[i][j]); + cover_fct[identifier] = i; + cover_std[identifier] = funcstd[i]; + cover_color[identifier].second += func_color[preimages[i][j]]; + cover_color[identifier].first += 1; } // Maximal dimension is total number of connected components id += max + 1; - } maximal_dim = id - 1; @@ -760,21 +755,25 @@ class Cover_complex { * @param[in] cover_file_name name of the input cover file. * */ - void set_cover_from_file(const std::string & cover_file_name) { - int i = 0; int cov; std::vector<int> cov_elts, cov_number; - std::ifstream input(cover_file_name); std::string line; + void set_cover_from_file(const std::string& cover_file_name) { + int i = 0; + int cov; + std::vector<int> cov_elts, cov_number; + std::ifstream input(cover_file_name); + std::string line; while (std::getline(input, line)) { cov_elts.clear(); std::stringstream stream(line); while (stream >> cov) { cov_elts.push_back(cov); cov_number.push_back(cov); - cover_fct [cov] = cov; - cover_color [cov] .second += func_color[i]; - cover_color [cov] .first++; - cover_back [cov] .push_back(i); + cover_fct[cov] = cov; + cover_color[cov].second += func_color[i]; + cover_color[cov].first++; + cover_back[cov].push_back(i); } - cover[i] = cov_elts; i++; + cover[i] = cov_elts; + i++; } std::sort(cov_number.begin(), cov_number.end()); @@ -794,37 +793,44 @@ class Cover_complex { * */ template <typename Distance> - void set_cover_from_Voronoi(Distance distance, int m = 100){ - - voronoi_subsamples.resize(m); SampleWithoutReplacement(n, m, voronoi_subsamples); - if (distances.size() == 0) compute_pairwise_distances(distance); set_graph_weights(); - WeightMap weight = boost::get(boost::edge_weight, one_skeleton); IndexMap index = boost::get(boost::vertex_index, one_skeleton); - std::vector<double> mindist(n); for (int j = 0; j < n; j++) mindist[j] = std::numeric_limits<double>::max(); + void set_cover_from_Voronoi(Distance distance, int m = 100) { + voronoi_subsamples.resize(m); + SampleWithoutReplacement(n, m, voronoi_subsamples); + if (distances.size() == 0) compute_pairwise_distances(distance); + set_graph_weights(); + WeightMap weight = boost::get(boost::edge_weight, one_skeleton); + IndexMap index = boost::get(boost::vertex_index, one_skeleton); + std::vector<double> mindist(n); + for (int j = 0; j < n; j++) mindist[j] = std::numeric_limits<double>::max(); // Compute the geodesic distances to subsamples with Dijkstra // #pragma omp parallel for for (int i = 0; i < m; i++) { - if (verbose) std::cout << "Computing geodesic distances to seed " << i << "..." << std::endl; - int seed = voronoi_subsamples[i]; std::vector<double> dmap(n); - boost::dijkstra_shortest_paths(one_skeleton, vertices[seed], boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index))); + int seed = voronoi_subsamples[i]; + std::vector<double> dmap(n); + boost::dijkstra_shortest_paths( + one_skeleton, vertices[seed], + boost::weight_map(weight).distance_map(boost::make_iterator_property_map(dmap.begin(), index))); for (int j = 0; j < n; j++) if (mindist[j] > dmap[j]) { mindist[j] = dmap[j]; - if (cover[j].size() == 0) cover[j].push_back(i); else cover[j][0] = i; + if (cover[j].size() == 0) + cover[j].push_back(i); + else + cover[j][0] = i; } } for (int i = 0; i < n; i++) { - cover_back [cover[i][0]] .push_back(i); - cover_color [cover[i][0]] .second += func_color[i]; - cover_color [cover[i][0]] .first++; + cover_back[cover[i][0]].push_back(i); + cover_color[cover[i][0]].second += func_color[i]; + cover_color[cover[i][0]].first++; } for (int i = 0; i < m; i++) cover_color[i].second /= cover_color[i].first; maximal_dim = m - 1; cover_name = "Voronoi"; - } public: // return subset of data corresponding to a node @@ -834,19 +840,7 @@ class Cover_complex { * @result cover_back(c) vector of IDs of data points. * */ - const std::vector<int> & subpopulation(int c) { return cover_back[name2idinv[c]]; } - - - - - - - - - - - - + const std::vector<int>& subpopulation(int c) { return cover_back[name2idinv[c]]; } // ******************************************************************************************************************* // Visualization. @@ -859,14 +853,15 @@ class Cover_complex { * @param[in] color_file_name name of the input color file. * */ - void set_color_from_file(const std::string & color_file_name) { + void set_color_from_file(const std::string& color_file_name) { int i = 0; std::ifstream input(color_file_name); std::string line; double f; while (std::getline(input, line)) { std::stringstream stream(line); - stream >> f; func_color.emplace(i, f); + stream >> f; + func_color.emplace(i, f); i++; } color_name = color_file_name; @@ -890,8 +885,8 @@ class Cover_complex { * @param[in] color input vector of values. * */ - void set_color_from_vector(std::vector<double> c) { - for (unsigned int i = 0; i < c.size(); i++) func_color[i] = c[i]; + void set_color_from_vector(std::vector<double> color) { + for (unsigned int i = 0; i < color.size(); i++) func_color[i] = color[i]; } public: // Create a .dot file that can be compiled with neato to produce a .pdf file. @@ -900,22 +895,31 @@ class Cover_complex { * of its 1-skeleton in a .pdf file. */ void plot_DOT() { + char mapp[100]; + sprintf(mapp, "%s_sc.dot", point_cloud_name.c_str()); + std::ofstream graphic(mapp); - char mapp[100]; sprintf(mapp, "%s_sc.dot",point_cloud_name.c_str()); std::ofstream graphic(mapp); - - double maxv = std::numeric_limits<double>::lowest(); double minv = std::numeric_limits<double>::max(); + double maxv = std::numeric_limits<double>::lowest(); + double minv = std::numeric_limits<double>::max(); for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) { - maxv = std::max(maxv, iit->second.second); minv = std::min(minv, iit->second.second); + maxv = std::max(maxv, iit->second.second); + minv = std::min(minv, iit->second.second); } - int k = 0; std::vector<int> nodes; nodes.clear(); + int k = 0; + std::vector<int> nodes; + nodes.clear(); - graphic << "graph GIC {" << std::endl; int id = 0; + graphic << "graph GIC {" << std::endl; + int id = 0; for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) { if (iit->second.first > mask) { - nodes.push_back(iit->first); name2id[iit->first] = id; name2idinv[id] = iit->first; id++; - graphic << name2id[iit->first] << "[shape=circle fontcolor=black color=black label=\"" << name2id[iit->first] << ":" - << iit->second.first << "\" style=filled fillcolor=\"" + nodes.push_back(iit->first); + name2id[iit->first] = id; + name2idinv[id] = iit->first; + id++; + graphic << name2id[iit->first] << "[shape=circle fontcolor=black color=black label=\"" << name2id[iit->first] + << ":" << iit->second.first << "\" style=filled fillcolor=\"" << (1 - (maxv - iit->second.second) / (maxv - minv)) * 0.6 << ", 1, 1\"]" << std::endl; k++; } @@ -925,7 +929,8 @@ class Cover_complex { for (int i = 0; i < num_simplices; i++) if (simplices[i].size() == 2) { if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) { - graphic << " " << name2id[simplices[i][0]] << " -- " << name2id[simplices[i][1]] << " [weight=15];" << std::endl; + graphic << " " << name2id[simplices[i][0]] << " -- " << name2id[simplices[i][1]] << " [weight=15];" + << std::endl; ke++; } } @@ -939,9 +944,11 @@ class Cover_complex { * KeplerMapper. */ void write_info() { - - int num_simplices = simplices.size(); int num_edges = 0; - char mapp[100]; sprintf(mapp, "%s_sc.txt",point_cloud_name.c_str()); std::ofstream graphic(mapp); + int num_simplices = simplices.size(); + int num_edges = 0; + char mapp[100]; + sprintf(mapp, "%s_sc.txt", point_cloud_name.c_str()); + std::ofstream graphic(mapp); for (int i = 0; i < num_simplices; i++) if (simplices[i].size() == 2) @@ -954,16 +961,20 @@ class Cover_complex { graphic << cover_color.size() << " " << num_edges << std::endl; int id = 0; - for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++){ - graphic << id << " " << iit->second.second << " " << iit->second.first << std::endl; name2id[iit->first] = id; name2idinv[id] = iit->first; id++;} + for (std::map<int, std::pair<int, double> >::iterator iit = cover_color.begin(); iit != cover_color.end(); iit++) { + graphic << id << " " << iit->second.second << " " << iit->second.first << std::endl; + name2id[iit->first] = id; + name2idinv[id] = iit->first; + id++; + } for (int i = 0; i < num_simplices; i++) if (simplices[i].size() == 2) if (cover_color[simplices[i][0]].first > mask && cover_color[simplices[i][1]].first > mask) graphic << name2id[simplices[i][0]] << " " << name2id[simplices[i][1]] << std::endl; graphic.close(); - std::cout << ".txt generated. It can be visualized with e.g. python KeplerMapperVisuFromTxtFile.py and firefox." << std::endl; - + std::cout << ".txt generated. It can be visualized with e.g. python KeplerMapperVisuFromTxtFile.py and firefox." + << std::endl; } public: // Create a .off file that can be visualized (e.g. with Geomview). @@ -972,13 +983,17 @@ class Cover_complex { * the remaining coordinates of the points embedded in 3D are set to 0. */ void plot_OFF() { - assert(cover_name == "Voronoi"); - int m = voronoi_subsamples.size(); int numedges = 0; int numfaces = 0; std::vector<std::vector<int> > edges, faces; + int m = voronoi_subsamples.size(); + int numedges = 0; + int numfaces = 0; + std::vector<std::vector<int> > edges, faces; int numsimplices = simplices.size(); - char gic[100]; sprintf(gic, "%s_sc.off",point_cloud_name.c_str()); std::ofstream graphic(gic); + char gic[100]; + sprintf(gic, "%s_sc.off", point_cloud_name.c_str()); + std::ofstream graphic(gic); graphic << "OFF" << std::endl; for (int i = 0; i < numsimplices; i++) { @@ -1008,27 +1023,6 @@ class Cover_complex { std::cout << ".off generated. It can be visualized with e.g. geomview." << std::endl; } - - - - - - - - - - - - - - - - - - - - - // ******************************************************************************************************************* // Extended Persistence Diagrams. // ******************************************************************************************************************* @@ -1037,56 +1031,77 @@ class Cover_complex { /** \brief Computes the extended persistence diagram of the complex. * */ - void compute_PD(){ - + void compute_PD() { Simplex_tree st; // Compute max and min - double maxf = std::numeric_limits<double>::lowest(); double minf = std::numeric_limits<double>::max(); - for(std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++){ - maxf = std::max(maxf, it->second); minf = std::min(minf, it->second); + double maxf = std::numeric_limits<double>::lowest(); + double minf = std::numeric_limits<double>::max(); + for (std::map<int, double>::iterator it = cover_std.begin(); it != cover_std.end(); it++) { + maxf = std::max(maxf, it->second); + minf = std::min(minf, it->second); } - - for(auto const & simplex : simplices){ + + for (auto const& simplex : simplices) { // Add simplices st.insert_simplex_and_subfaces(simplex); // Add cone on simplices - std::vector<int> splx = simplex; splx.push_back(-2); st.insert_simplex_and_subfaces(splx); + std::vector<int> splx = simplex; + splx.push_back(-2); + st.insert_simplex_and_subfaces(splx); } // Build filtration - for(auto simplex : st.complex_simplex_range()){ - double filta = std::numeric_limits<double>::lowest(); double filts = filta; bool ascending = true; - for(auto vertex : st.simplex_vertex_range(simplex)){ - if(vertex == -2){ascending = false; continue;} - filta = std::max( -2 + (cover_std[vertex] - minf)/(maxf - minf), filta ); - filts = std::max( 2 - (cover_std[vertex] - minf)/(maxf - minf), filts ); + for (auto simplex : st.complex_simplex_range()) { + double filta = std::numeric_limits<double>::lowest(); + double filts = filta; + bool ascending = true; + for (auto vertex : st.simplex_vertex_range(simplex)) { + if (vertex == -2) { + ascending = false; + continue; + } + filta = std::max(-2 + (cover_std[vertex] - minf) / (maxf - minf), filta); + filts = std::max(2 - (cover_std[vertex] - minf) / (maxf - minf), filts); } - if(ascending) st.assign_filtration(simplex, filta); else st.assign_filtration(simplex, filts); + if (ascending) + st.assign_filtration(simplex, filta); + else + st.assign_filtration(simplex, filts); } - std::vector<int> magic = {-2}; st.assign_filtration(st.find(magic), -3); + std::vector<int> magic = {-2}; + st.assign_filtration(st.find(magic), -3); // Compute PD - st.initialize_filtration(); Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Gudhi::persistent_cohomology::Field_Zp> pcoh(st); - pcoh.init_coefficients(2); pcoh.compute_persistent_cohomology(); + st.initialize_filtration(); + Gudhi::persistent_cohomology::Persistent_cohomology<Simplex_tree, Gudhi::persistent_cohomology::Field_Zp> pcoh(st); + pcoh.init_coefficients(2); + pcoh.compute_persistent_cohomology(); // Output PD int max_dim = st.dimension(); - for(int i = 0; i < max_dim; i++){ - std::vector<std::pair<double, double> > bars = pcoh.intervals_in_dimension(i); int num_bars = bars.size(); std::cout << num_bars << " interval(s) in dimension " << i << ":" << std::endl; - for(int j = 0; j < num_bars; j++){ - double birth = bars[j].first; double death = bars[j].second; - if(i == 0 && std::isinf(death)) continue; - if(birth < 0) birth = minf + (birth + 2)*(maxf - minf); else birth = minf + (2 - birth)*(maxf - minf); - if(death < 0) death = minf + (death + 2)*(maxf - minf); else death = minf + (2 - death)*(maxf - minf); - PD.push_back(std::pair<double,double>(birth, death)); - if(verbose) std::cout << " [" << birth << ", " << death << "]" << std::endl; + for (int i = 0; i < max_dim; i++) { + std::vector<std::pair<double, double> > bars = pcoh.intervals_in_dimension(i); + int num_bars = bars.size(); + std::cout << num_bars << " interval(s) in dimension " << i << ":" << std::endl; + for (int j = 0; j < num_bars; j++) { + double birth = bars[j].first; + double death = bars[j].second; + if (i == 0 && std::isinf(death)) continue; + if (birth < 0) + birth = minf + (birth + 2) * (maxf - minf); + else + birth = minf + (2 - birth) * (maxf - minf); + if (death < 0) + death = minf + (death + 2) * (maxf - minf); + else + death = minf + (2 - death) * (maxf - minf); + PD.push_back(std::pair<double, double>(birth, death)); + if (verbose) std::cout << " [" << birth << ", " << death << "]" << std::endl; } } - } - public: /** \brief Computes bootstrapped distances distribution. * @@ -1094,34 +1109,38 @@ class Cover_complex { * */ template <typename SimplicialComplex> - void compute_distribution(int N = 100){ - - if(distribution.size() >= N) std::cout << "Already done!" << std::endl; - else{ - for(int i = 0; i < N-distribution.size(); i++){ - - Cover_complex Cboot; Cboot.n = this->n; std::vector<int> boot(this->n); - for(int j = 0; j < this->n; j++){ - double u = GetUniform(); int id = std::floor(u*(this->n)); boot[j] = id; - Cboot.point_cloud[j] = this->point_cloud[id]; Cboot.func.emplace(j,this->func[id]); + void compute_distribution(int N = 100) { + if (distribution.size() >= N) + std::cout << "Already done!" << std::endl; + else { + for (int i = 0; i < N - distribution.size(); i++) { + Cover_complex Cboot; + Cboot.n = this->n; + std::vector<int> boot(this->n); + for (int j = 0; j < this->n; j++) { + double u = GetUniform(); + int id = std::floor(u * (this->n)); + boot[j] = id; + Cboot.point_cloud[j] = this->point_cloud[id]; + Cboot.func.emplace(j, this->func[id]); } - for(int j = 0; j < n; j++){ + for (int j = 0; j < n; j++) { std::vector<double> dist(n); - for(int k = 0; k < n; k++) - dist[k] = distances[boot[j]][boot[k]]; + for (int k = 0; k < n; k++) dist[k] = distances[boot[j]][boot[k]]; Cboot.distances.push_back(dist); } Cboot.set_graph_from_automatic_rips(Gudhi::Euclidean_distance()); - Cboot.set_automatic_resolution(); Cboot.set_gain(); Cboot.set_cover_from_function(); - Cboot.find_simplices(); Cboot.compute_PD(); - - distribution.push_back(Gudhi::persistence_diagram::bottleneck_distance(this->PD,Cboot.PD)); + Cboot.set_automatic_resolution(); + Cboot.set_gain(); + Cboot.set_cover_from_function(); + Cboot.find_simplices(); + Cboot.compute_PD(); + distribution.push_back(Gudhi::persistence_diagram::bottleneck_distance(this->PD, Cboot.PD)); } std::sort(distribution.begin(), distribution.end()); - } } @@ -1131,9 +1150,9 @@ class Cover_complex { * @param[in] alpha Confidence level. * */ - double compute_distance_from_confidence_level(double alpha){ + double compute_distance_from_confidence_level(double alpha) { int N = distribution.size(); - return distribution[std::floor(alpha*N)]; + return distribution[std::floor(alpha * N)]; } public: @@ -1142,9 +1161,10 @@ class Cover_complex { * @param[in] d Bottleneck distance. * */ - double compute_confidence_level_from_distance(double d){ + double compute_confidence_level_from_distance(double d) { int N = distribution.size(); - for(int i = 0; i < N; i++) if(distribution[i] > d) return i*1.0/N; + for (int i = 0; i < N; i++) + if (distribution[i] > d) return i * 1.0 / N; } public: @@ -1152,27 +1172,13 @@ class Cover_complex { * distance preserving the points in the persistence diagram of the output simplicial complex. * */ - double compute_p_value(){ + double compute_p_value() { double distancemin = -std::numeric_limits<double>::lowest(); - int N = PD.size(); for(int i = 0; i < N; i++) distancemin = std::min(distancemin, 0.5*(PD[i].second - PD[i].first)); - return 1-compute_confidence_level_from_distance(distancemin); + int N = PD.size(); + for (int i = 0; i < N; i++) distancemin = std::min(distancemin, 0.5 * (PD[i].second - PD[i].first)); + return 1 - compute_confidence_level_from_distance(distancemin); } - - - - - - - - - - - - - - - // ******************************************************************************************************************* // Computation of simplices. // ******************************************************************************************************************* @@ -1184,11 +1190,12 @@ class Cover_complex { * */ template <typename SimplicialComplex> - void create_complex(SimplicialComplex& complex){ + void create_complex(SimplicialComplex& complex) { unsigned int dimension = 0; for (auto const& simplex : simplices) { - int numvert = simplex.size(); double filt = std::numeric_limits<double>::lowest(); - for(int i = 0; i < numvert; i++) filt = std::max(cover_color[simplex[i]].second, filt); + int numvert = simplex.size(); + double filt = std::numeric_limits<double>::lowest(); + for (int i = 0; i < numvert; i++) filt = std::max(cover_color[simplex[i]].second, filt); complex.insert_simplex_and_subfaces(simplex, filt); if (dimension < simplex.size() - 1) dimension = simplex.size() - 1; } @@ -1212,7 +1219,6 @@ class Cover_complex { } if (type == "GIC") { - IndexMap index = boost::get(boost::vertex_index, one_skeleton); if (functional_cover) { @@ -1220,40 +1226,47 @@ class Cover_complex { // corresponding edges in the GIC if the images of the endpoints belong to consecutive intervals. if (gain >= 0.5) - throw std::invalid_argument("the output of this function is correct ONLY if the cover is minimal, i.e. the gain is less than 0.5."); + throw std::invalid_argument( + "the output of this function is correct ONLY if the cover is minimal, i.e. the gain is less than 0.5."); // Loop on all edges. boost::graph_traits<Graph>::edge_iterator ei, ei_end; - for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei){ + for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) { int nums = cover[index[boost::source(*ei, one_skeleton)]].size(); - for(int i = 0; i < nums; i++){ + for (int i = 0; i < nums; i++) { int vs = cover[index[boost::source(*ei, one_skeleton)]][i]; int numt = cover[index[boost::target(*ei, one_skeleton)]].size(); - for(int j = 0; j < numt; j++){ + for (int j = 0; j < numt; j++) { int vt = cover[index[boost::target(*ei, one_skeleton)]][j]; - if(cover_fct[vs] == cover_fct[vt] + 1 || cover_fct[vt] == cover_fct[vs] + 1){ - std::vector<int> edge(2); edge[0] = std::min(vs,vt); edge[1] = std::max(vs,vt); simplices.push_back(edge); goto afterLoop; + if (cover_fct[vs] == cover_fct[vt] + 1 || cover_fct[vt] == cover_fct[vs] + 1) { + std::vector<int> edge(2); + edge[0] = std::min(vs, vt); + edge[1] = std::max(vs, vt); + simplices.push_back(edge); + goto afterLoop; } } } - afterLoop: ; + afterLoop:; } std::sort(simplices.begin(), simplices.end()); std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end()); simplices.resize(std::distance(simplices.begin(), it)); } else { - // Find edges to keep - Simplex_tree st; boost::graph_traits<Graph>::edge_iterator ei, ei_end; + Simplex_tree st; + boost::graph_traits<Graph>::edge_iterator ei, ei_end; for (boost::tie(ei, ei_end) = boost::edges(one_skeleton); ei != ei_end; ++ei) - if( !( cover[index[boost::target(*ei, one_skeleton)]].size() == 1 && - cover[index[boost::target(*ei, one_skeleton)]] == cover[index[boost::source(*ei, one_skeleton)]]) ){ - std::vector<int> edge(2); edge[0] = index[boost::source(*ei, one_skeleton)]; edge[1] = index[boost::target(*ei, one_skeleton)]; + if (!(cover[index[boost::target(*ei, one_skeleton)]].size() == 1 && + cover[index[boost::target(*ei, one_skeleton)]] == cover[index[boost::source(*ei, one_skeleton)]])) { + std::vector<int> edge(2); + edge[0] = index[boost::source(*ei, one_skeleton)]; + edge[1] = index[boost::target(*ei, one_skeleton)]; st.insert_simplex_and_subfaces(edge); } - //st.insert_graph(one_skeleton); + // st.insert_graph(one_skeleton); // Build the Simplex Tree corresponding to the graph st.expansion(maximal_dim); @@ -1278,7 +1291,6 @@ class Cover_complex { std::sort(simplices.begin(), simplices.end()); std::vector<std::vector<int> >::iterator it = std::unique(simplices.begin(), simplices.end()); simplices.resize(std::distance(simplices.begin(), it)); - } } } @@ -1289,203 +1301,3 @@ class Cover_complex { } // namespace Gudhi #endif // GIC_H_ - - - - - - - - - - - - - - - - - -/*Old code. - - private: - void fill_adjacency_matrix_from_st() { - std::std::vector<int> empty; - for (int i = 0; i < n; i++) adjacency_matrix[i] = empty; - for (auto simplex : st.complex_simplex_range()) { - if (st.dimension(simplex) == 1) { - std::std::vector<int> vertices; - for (auto vertex : st.simplex_vertex_range(simplex)) vertices.push_back(vertex); - adjacency_matrix[vertices[0]].push_back(vertices[1]); - adjacency_matrix[vertices[1]].push_back(vertices[0]); - } - } - } - -std::std::vector<int> simplex_to_remove; -int simplex_id = 0; -for (auto simplex : st.complex_simplex_range()) { - if (st.dimension(simplex) == 1) { - std::std::vector<std::std::vector<int> > comp; - for (auto vertex : st.simplex_vertex_range(simplex)) comp.push_back(cover[vertex]); - if (comp[0].size() == 1 && comp[0] == comp[1]) simplex_to_remove.push_back(simplex_id); - } - simplex_id++; -} - -// Remove edges -if (simplex_to_remove.size() > 1) { - int current_id = 1; - auto simplex = st.complex_simplex_range().begin(); - int num_rem = 0; - for (int i = 0; i < simplex_id - 1; i++) { - int j = i + 1; - auto simplex_tmp = simplex; - simplex_tmp++; - if (j == simplex_to_remove[current_id]) { - st.remove_maximal_simplex(*simplex_tmp); - current_id++; - num_rem++; - } else { - simplex++; - } - } - simplex = st.complex_simplex_range().begin(); - for (int i = 0; i < simplex_to_remove[0]; i++) simplex++; - st.remove_maximal_simplex(*simplex); -} - - -if(cover[index[source(*ei, one_skeleton)]].size() == 1){ - vs = cover[index[source(*ei, one_skeleton)]][0]; - vm = cover_fct[vs]; -} -else{ - vs0 = cover[index[source(*ei, one_skeleton)]][0]; - vs1 = cover[index[source(*ei, one_skeleton)]][1]; - vm = min(cover_fct[vs0], cover_fct[vs1]); - if(vm == cover_fct[vs0]) vs = vs0; else vs = vs1; -} - -if(cover[index[target(*ei, one_skeleton)]].size() == 1){ - vt = cover[index[target(*ei, one_skeleton)]][0]; - vM = cover_fct[vt]; -} -else{ - vt0 = cover[index[target(*ei, one_skeleton)]][0]; - vt1 = cover[index[target(*ei, one_skeleton)]][1]; - vM = max(cover_fct[vt0], cover_fct[vt1]); - if(vM == cover_fct[vt0]) vt = vt0; else vt = vt1; -} - -if(vM == vm + 1){ - //if(max(cover_fct[cover[index[target(*ei, one_skeleton)]][0]], cover_fct[cover[index[target(*ei, one_skeleton)]][1]])== min(cover_fct[index[source(*ei, one_skeleton)]][0], cover_fct[index[source(*ei, one_skeleton)]][1]) + 1){ - std::vector<int> edge(2); edge[0] = vs; edge[1] = vt; - simplices.push_back(edge); -} - - -for (std::map<int, std::vector<int> >::iterator it = cover.begin(); it != cover.end(); it++) { -int vid = it->first; -std::vector<int> neighbors = adjacency_matrix[vid]; -int num_neighb = neighbors.size(); - -// Find cover of current point (vid). -if (cover[vid].size() == 2) v1 = std::min(cover[vid][0], cover[vid][1]); -else v1 = cover[vid][0]; -std::vector<int> node(1); node[0] = v1; -simplices.push_back(node); - -// Loop on neighbors. -for (int i = 0; i < num_neighb; i++) { - int neighb = neighbors[i]; - - // Find cover of neighbor (neighb). - if (cover[neighb].size() == 2) v2 = std::max(cover[neighb][0], cover[neighb][1]); - else v2 = cover[neighb][0]; - - // If neighbor is in next interval, add edge. - if (cover_fct[v2] == cover_fct[v1] + 1) { - std::vector<int> edge(2); edge[0] = v1; edge[1] = v2; - simplices.push_back(edge); break; - } -} -} - - - std::std::vector<double> dist(n); - std::std::vector<int> process(n); - for (int j = 0; j < n; j++) { - dist[j] = std::numeric_limits<double>::max(); - process[j] = j; - } - dist[seed] = 0; - int curr_size = process.size(); - int min_point, min_index; - double min_dist; - std::std::vector<int> neighbors; - int num_neighbors; - - while (curr_size > 0) { - min_dist = std::numeric_limits<double>::max(); - min_index = -1; - min_point = -1; - for (int j = 0; j < curr_size; j++) { - if (dist[process[j]] < min_dist) { - min_point = process[j]; - min_dist = dist[process[j]]; - min_index = j; - } - } - assert(min_index != -1); - process.erase(process.begin() + min_index); - assert(min_point != -1); - neighbors = adjacency_matrix[min_point]; - num_neighbors = neighbors.size(); - for (int j = 0; j < num_neighbors; j++) { - double d = dist[min_point] + distances[min_point][neighbors[j]]; - dist[neighbors[j]] = std::min(dist[neighbors[j]], d); - } - curr_size = process.size(); - } - - - // Compute the connected components with DFS - std::std::map<int, bool> visit; - if (verbose) std::std::cout << "Preimage of interval " << i << std::std::endl; - for (std::std::map<int, std::std::vector<int> >::iterator it = prop.begin(); it != prop.end(); it++) - visit[it->first] = false; - if (!(prop.empty())) { - for (std::std::map<int, std::std::vector<int> >::iterator it = prop.begin(); it != prop.end(); it++) { - if (!(visit[it->first])) { - std::std::vector<int> cc; - cc.clear(); - dfs(prop, it->first, cc, visit); - int cci = cc.size(); - if (verbose) std::std::cout << "one CC with " << cci << " points, "; - double average_col = 0; - for (int j = 0; j < cci; j++) { - cover[cc[j]].push_back(id); - cover_back[id].push_back(cc[j]); - average_col += func_color[cc[j]] / cci; - } - cover_fct[id] = i; - cover_std[id] = std::std::pair<int, double>(cci, 0.5*(u+v)); - cover_color[id] = std::std::pair<int, double>(cci, average_col); - id++; - } - } - } - - - // DFS - private: - void dfs(std::std::map<int, std::std::vector<int> >& G, int p, std::std::vector<int>& cc, std::std::map<int, bool>& visit) { - cc.push_back(p); - visit[p] = true; - int neighb = G[p].size(); - for (int i = 0; i < neighb; i++) - if (visit.find(G[p][i]) != visit.end()) - if (!(visit[G[p][i]])) dfs(G, G[p][i], cc, visit); - } -*/ |