/* This file is part of the Gudhi Library. The Gudhi library * (Geometric Understanding in Higher Dimensions) is a generic C++ * library for computational topology. * * Author: Mathieu Carriere * * Copyright (C) 2017 INRIA * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GIC_H_ #define GIC_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include // for numeric_limits #include // for pair<> #include // for greater<> #include #include #include // for std::max #include // for std::uint32_t using Simplex_tree = Gudhi::Simplex_tree<>; using Filtration_value = Simplex_tree::Filtration_value; using Rips_complex = Gudhi::rips_complex::Rips_complex; using Point = std::vector; std::map func; namespace Gudhi { namespace graph_induced_complex { /** * \class Graph_induced_complex * \brief Graph induced complex data structure. * * \ingroup graph_induced_complex * * \details * * */ class Graph_induced_complex { private: typedef int Cover_t; private: std::vector > simplices; private: std::map > cover; private: int maximal_dim; private: Simplex_tree<> st; std::map > adjacency_matrix; // Simplex comparator private: bool simplex_comp(const std::vector& s1, const std::vector& s2){ if(s1.size() == s2.size()){ return s1[0] < s2[0]; } else return s1.size() < s2.size(); } // Point comparator private: static bool functional_comp(const int& a, const int& b){ if(func[a] == func[b]) return a < b; else return func[a] < func[b]; } // DFS private: void dfs(std::map >& G, const int& p, std::vector& cc, std::map& 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); } // ******************************************************************************************************************* // Graphs. // ******************************************************************************************************************* public: // Set graph from file. void set_graph_from_file(const std::string& graph_file_name){ int neighb; int vid; std::ifstream input(graph_file_name); std::string line; std::vector edge(2); while(std::getline(input,line)){ std::stringstream stream(line); stream >> vid; edge[0] = vid; while(stream >> neighb){edge[1] = neighb; st.insert_simplex_and_subfaces(edge);} } } public: // Set graph from Rips complex. void set_graph_from_rips(const double& threshold, const std::string& off_file_name){ Points_off_reader off_reader(off_file_name); Rips_complex rips_complex_from_points(off_reader.get_point_cloud(), threshold, Euclidean_distance()); rips_complex_from_points.create_complex(st, 1); } // ******************************************************************************************************************* // Functions. // ******************************************************************************************************************* public: // Set function from file. void set_function_from_file(const std::string& func_file_name){ int vertex_id = 0; std::ifstream input(func_file_name); std::string line; double f; while(std::getline(input,line)){ std::stringstream stream(line); stream >> f; func.insert(std::pair(vertex_id, f)); vertex_id++; } } public: // Set function from vector. void set_function_from_vector(const std::vector& function){ for(int i = 0; i < function.size(); i++) func.insert(std::pair(i, function[i])); } // ******************************************************************************************************************* // Covers. // ******************************************************************************************************************* public: // Set cover from file. void set_cover_from_file(const std::string& cover_file_name){ int vertex_id = 0; Cover_t cov; std::vector 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.insert(std::pair >(vertex_id, cov_elts)); vertex_id++; } std::vector::iterator it; std::sort(cov_number.begin(),cov_number.end()); it = std::unique(cov_number.begin(),cov_number.end()); cov_number.resize(std::distance(cov_number.begin(),it)); maximal_dim = cov_number.size(); } public: // Set cover with preimages of function. void set_cover_from_function(const double& resolution, const double& gain, const bool& token){ // Read function values and compute min and max std::map::iterator it; std::vector range; double maxf, minf; minf = std::numeric_limits::max(); maxf = std::numeric_limits::min(); for(it = func.begin(); it != func.end(); it++){range.push_back(it->second); minf = std::min(minf, it->second); maxf = std::max(maxf, it->second);} int num_pts = func.size(); // Compute cover of im(f) std::vector > intervals; int res; if(!token){ double incr = (maxf-minf)/resolution; double x = minf; double alpha = (incr*gain)/(2-2*gain); double y = minf + incr + alpha; std::pair interm(x,y); intervals.push_back(interm); for(int i = 1; i < resolution-1; i++){ x = minf + i*incr - alpha; y = minf + (i+1)*incr + alpha; std::pair inter(x,y); intervals.push_back(inter); } x = minf + (resolution-1)*incr - alpha; y = maxf; std::pair interM(x,y); intervals.push_back(interM); res = intervals.size(); } else{ double x = minf; double y = x + resolution; while(y <= maxf && maxf - (y-gain*resolution) >= resolution){ std::pair inter(x,y); intervals.push_back(inter); x = y - gain*resolution; y = x + resolution; } std::pair interM(x,maxf); intervals.push_back(interM); res = intervals.size(); } // Sort points according to function values std::vector points(num_pts); for(int i = 0; i < num_pts; i++) points[i] = i; std::sort(points.begin(),points.end(),functional_comp); // Build adjacency matrix std::vector empty; for(int i = 0; i < num_pts; i++) adjacency_matrix.insert(std::pair >(points[i],empty)); for (auto simplex : st.complex_simplex_range()) { if(st.dimension(simplex) == 1){ std::vector 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]); } } int id = 0; int pos = 0; for(int i = 0; i < res; i++){ // Find points in the preimage std::map > prop; prop.clear(); std::pair inter1 = intervals[i]; int tmp = pos; if(i != res-1){ if(i != 0){ std::pair inter3 = intervals[i-1]; while(func[points[tmp]] < inter3.second && tmp != num_pts){ prop.insert(std::pair >(points[tmp],adjacency_matrix[points[tmp]])); tmp++; } } std::pair inter2 = intervals[i+1]; while(func[points[tmp]] < inter2.first && tmp != num_pts){ prop.insert(std::pair >(points[tmp],adjacency_matrix[points[tmp]])); tmp++; } pos = tmp; while(func[points[tmp]] < inter1.second && tmp != num_pts){ prop.insert(std::pair >(points[tmp],adjacency_matrix[points[tmp]])); tmp++; } } else{ std::pair inter3 = intervals[i-1]; while(func[points[tmp]] < inter3.second && tmp != num_pts){ prop.insert(std::pair >(points[tmp],adjacency_matrix[points[tmp]])); tmp++; } while(tmp != num_pts){ prop.insert(std::pair >(points[tmp],adjacency_matrix[points[tmp]])); tmp++; } } // Compute the connected components with DFS std::map visit; for(std::map >::iterator it = prop.begin(); it != prop.end(); it++) visit.insert(std::pair(it->first, false)); if (!(prop.empty())){ for(std::map >::iterator it = prop.begin(); it != prop.end(); it++){ if ( !(visit[it->first]) ){ std::vector cc; cc.clear(); dfs(prop,it->first,cc,visit); int cci = cc.size(); for(int i = 0; i < cci; i++) cover[cc[i]].push_back(id); id++; } } } } maximal_dim = id; } // ******************************************************************************************************************* // ******************************************************************************************************************* public: template void create_complex(SimplicialComplexForGIC & complex) { size_t sz = simplices.size(); int dimension = 0; for(int i = 0; i < sz; i++){ complex.insert_simplex_and_subfaces(simplices[i]); if(dimension < simplices[i].size()-1) dimension = simplices[i].size()-1; } complex.set_dimension(dimension); } public: void find_all_simplices(const std::vector > & cover_elts\ //int token, std::vector & simplex_tmp ){ int num_nodes = cover_elts.size(); // Old method. /*if(token == num_nodes-1){ int num_clus = cover_elts[token].size(); for(int i = 0; i < num_clus; i++){ std::vector simplex = simplex_tmp; simplex.push_back(cover_elts[token][i]); std::vector::iterator it; std::sort(simplex.begin(),simplex.end()); it = std::unique(simplex.begin(),simplex.end()); simplex.resize(std::distance(simplex.begin(),it)); simplices.push_back(simplex); } } else{ int num_clus = cover_elts[token].size(); for(int i = 0; i < num_clus; i++){ std::vector simplex = simplex_tmp; simplex.push_back(cover_elts[token][i]); find_all_simplices(cover_elts, token+1, simplex); } }*/ std::vector simplex; for(int i = 0; i < num_nodes; i++) for(int j = 0; j < cover_elts[i].size(); j++) simplex.push_back(cover_elts[i][j]); std::sort(simplex.begin(),simplex.end()); it = std::unique(simplex.begin(),simplex.end()); simplex.resize(std::distance(simplex.begin(),it)); simplices.push_back(simplex); } public: void find_Nerve_simplices(){ simplices.clear(); for(std::map >::iterator it = cover.begin(); it!=cover.end(); it++){ simplices.push_back(it->second); } std::vector >::iterator it; std::sort(simplices.begin(),simplices.end()); it = std::unique(simplices.begin(),simplices.end()); simplices.resize(std::distance(simplices.begin(),it)); } public: void find_GIC_simplices() { // Find IDs of edges to remove std::vector simplex_to_remove; int simplex_id = 0; for (auto simplex : st.complex_simplex_range()) { if(st.dimension(simplex) == 1){ std::vector > comp; for(auto vertex : st.simplex_vertex_range(simplex)) comp.push_back(cover[vertex]); if(comp[0].size() == 1 && comp[1].size() == 1 && comp[0] == comp[1]) simplex_to_remove.push_back(simplex_id); } simplex_id++; } // Remove edges 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); // Build the Simplex Tree corresponding to the graph st.expansion(maximal_dim); // Find simplices of GIC simplices.clear(); for (auto simplex : st.complex_simplex_range()) { if(!st.has_children(simplex)){ std::vector > cover_elts; std::vector sim; for (auto vertex : st.simplex_vertex_range(simplex)) cover_elts.push_back(cover[vertex]); find_all_simplices(cover_elts,0,sim); } } std::vector >::iterator it; std::sort(simplices.begin(),simplices.end()); it = std::unique(simplices.begin(),simplices.end()); simplices.resize(std::distance(simplices.begin(),it)); } public: void find_GIC_simplices_with_functional_minimal_cover(const double& resolution, const double& gain){ for(std::map >::iterator it = cover.begin(); it != cover.end(); it++){ int vid = it->first; std::vector neighbors = adjacency_matrix[vid]; int num_neighb = neighbors.size(); for(int i = 0; i < num_neighb; i++){ int neighb = neighbors[i]; int v1, v2; if(func[vid] > func[neighb]){ if( func[vid]-func[neighb] <= resolution*(2-gain) ){ if(cover[vid].size() == 2) v1 = std::min(cover[vid][0],cover[vid][1]); else v1 = cover[vid][0]; if(cover[neighb].size() == 2) v2 = std::max(cover[neighb][0],cover[neighb][1]); else v2 = cover[neighb][0]; std::vector edge(2); edge[0] = v1; edge[1] = v2; if(v1 > v2) simplices.push_back(edge); } } else{ if( func[neighb]-func[vid] <= resolution*(2-gain) ){ if(cover[vid].size() == 2) v1 = std::max(cover[vid][0],cover[vid][1]); else v1 = cover[vid][0]; if(cover[neighb].size() == 2) v2 = std::min(cover[neighb][0],cover[neighb][1]); else v2 = cover[neighb][0]; std::vector edge(2); edge[0] = v1; edge[1] = v2; if(v2 > v1) simplices.push_back(edge); } } } } std::vector >::iterator it; std::sort(simplices.begin(),simplices.end()); it = std::unique(simplices.begin(),simplices.end()); simplices.resize(std::distance(simplices.begin(),it)); } }; } // namespace graph_induced_complex } // namespace Gudhi #endif // GIC_H_