From ca63b38beafa9f5bb0b674682764e26097380134 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 16 Mar 2020 23:06:09 +0100 Subject: Collapse first version from Siddharth --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 963 +++++++++++++++++++++ src/Collapse/include/gudhi/PointSetGen.h | 273 ++++++ src/Collapse/include/gudhi/Rips_edge_list.h | 184 ++++ .../include/gudhi/TowerAssembler_FlagComplex.h | 184 ++++ 4 files changed, 1604 insertions(+) create mode 100644 src/Collapse/include/gudhi/FlagComplexSpMatrix.h create mode 100644 src/Collapse/include/gudhi/PointSetGen.h create mode 100644 src/Collapse/include/gudhi/Rips_edge_list.h create mode 100644 src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h new file mode 100644 index 00000000..d3e58d4f --- /dev/null +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -0,0 +1,963 @@ +/* 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(s): Siddharth Pritam + * + * Copyright (C) 2018 INRIA Sophia Antipolis (France) + * + * 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 . + +*/ +#pragma once + +#include +#include +// #include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +typedef std::size_t Vertex; +using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables +using EdgeFilt = std::pair; +using edge_list = std::vector; + +using MapVertexToIndex = std::unordered_map; +using Map = std::unordered_map; + +using sparseRowMatrix = Eigen::SparseMatrix ; +using rowInnerIterator = sparseRowMatrix::InnerIterator; + +using intVector = std::vector; +using doubleVector = std::vector; +using vertexVector = std::vector; +using boolVector = std::vector; + +using doubleQueue = std::queue; +using edgeQueue = std::queue; + +using EdgeFiltQueue = std::queue; +using EdgeFiltVector = std::vector; + +typedef std::vector< std::tuple< double, Vertex, Vertex > > Filtered_sorted_edge_list; +typedef std::unordered_map > u_edge_map; +typedef std::unordered_map > u_edge_to_idx_map; + + +//! Class SparseMsMatrix +/*! + The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() Algorithm. +*/ +class FlagComplexSpMatrix +{ + private: + + std::unordered_map rowToVertex; + + // Vertices strored as an unordered_set + std::unordered_set vertices; + //! Stores the 1-simplices(edges) of the original Simplicial Complex. + edge_list oneSimplices; + + //Unordered set of removed edges. (to enforce removal from the matrix) + std::unordered_set> u_set_removed_redges; + + //Unordered set of dominated edges. (to inforce removal from the matrix) + std::unordered_set> u_set_dominated_redges; + + + //Map from egde to its index + u_edge_to_idx_map edge_to_index_map; + //Boolean vector to indicate if the index is critical or not. + boolVector critical_edge_indicator; // critical indicator + + //Boolean vector to indicate if the index is critical or not. + boolVector dominated_edge_indicator; // domination indicator + + //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. + /*! + \code + MapVertexToIndex = std::unordered_map + \endcode + So, if the original simplex tree had vertices 0,1,4,5
+ rowToVertex would store :
+ \verbatim + Values = | 0 | 1 | 4 | 5 | + Indices = 0 1 2 3 + \endverbatim + And vertexToRow would be a map like the following :
+ \verbatim + 0 -> 0 + 1 -> 1 + 4 -> 2 + 5 -> 3 + \endverbatim + */ + MapVertexToIndex vertexToRow; + + //! Stores the number of vertices in the original Simplicial Complex. + /*! + This stores the count of vertices (which is also the number of rows in the Matrix). + */ + std::size_t rows; + + std::size_t numOneSimplices; + + std::size_t numDomEdge; + + //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. + /*! + \code + sparseRowMatrix = Eigen::SparseMatrix ; + \endcode + ; + */ + + sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. + sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access to elements when traversing the matrix row-wise. + + + + //! Stores true for dominated rows and false for undominated rows. + /*! + Initialised to a vector of length equal to the value of the variable rows with all false values. + Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. + */ + boolVector vertDomnIndicator; //(domination indicator) + + + boolVector activeIndicator; // active indicator + boolVector contractionIndicator; //(contraction indicator) + + //! Stores the indices of the rows to-be checked for domination in the current iteration. + /*! + Initialised with all rows for the first iteration. + Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. + */ + //doubleQueue rowIterator; + + doubleQueue rowIterator; + + //! Stores the indices-pair of the edges to-be checked for domination in the current iteration. + /*! + Initialised with all egdes for the first iteration. + Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. // To be clarified. + */ + //doubleQueue rowIterator; + + // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltQueue filteredEgdeIter; + + // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltVector fEgdeVector; + + // List of non-dominated edges, the indices of the edges are the vertex lables!!. + Filtered_sorted_edge_list criticalCoreEdges; + // Stores the indices from the sorted filtered edge vector. + // std::set recurCriticalCoreIndcs; + + + //! Stores true if the current row is inserted in the queue rowIterator otherwise its value is false. + /*! + Initialised to a boolean vector of length equal to the value of the variable rows with all true values. + Subsequent removal/addition of a row from rowIterator is reflected by concerned entries changing to false/true in this vector. + */ + boolVector rowInsertIndicator; //(current iteration row insertion indicator) + + + //! Map that stores the current status of the edges after the vertex-collapse has been performed. . + /*! + \code + u_edge_map = std::unordered_map + \endcode + The values an edge can take are true, false; + true -> Inserted in filteredEgdeIter; + false -> Not inserted in filteredEgdeIter; + */ + u_edge_map edgeStatusMap; + + //! Map that stores the Reduction / Collapse of vertices. + /*! + \code + Map = std::unordered_map + \endcode + This is empty to begin with. As and when collapses are done (let's say from dominated vertex v to dominating vertex v') :
+ ReductionMap[v] = v' is entered into the map.
+ This does not store uncollapsed vertices. What it means is that say vertex x was never collapsed onto any other vertex. Then, this map WILL NOT have any entry like x -> x. + Basically, it will have no entry corresponding to vertex x at all. + */ + Map ReductionMap; + + bool vertexCollapsed; + bool edgeCollapsed; + //Variable to indicate if filtered-edge-collapse has to be performed. + bool filtEdgeCol; + int expansion_limit; + + void init() + { + rowToVertex.clear(); + vertexToRow.clear(); + oneSimplices.clear(); + ReductionMap.clear(); + + vertDomnIndicator.clear(); + rowInsertIndicator.clear(); + rowIterator.push(0); + rowIterator.pop(); + + filteredEgdeIter.push({{0,0},0}); + filteredEgdeIter.pop(); + fEgdeVector.clear(); + + rows = 0; + numDomEdge = 0; + + numOneSimplices = 0; + expansion_limit = 2; + + vertexCollapsed = false; + edgeCollapsed = false; + filtEdgeCol = false; + } + + //! Function for computing the sparse-matrix corresponding to the core of the complex. It also prepares the working list filteredEgdeIter for edge collapses + void after_vertex_collapse() + { + sparse_colpsd_adj_Matrix = new sparseRowMatrix(rows,rows); // Just for debugging purpose. + oneSimplices.clear(); + if(not filteredEgdeIter.empty()) + std::cout << "Working list for edge collapses are not empty before the edge-collapse." << std::endl; + + for(int rw = 0 ; rw < rows ; ++rw) + { + if(not vertDomnIndicator[rw]) //If the current column is not dominated + { + auto nbhrs_to_insert = closed_neighbours_row_index(rw); // returns row indices of the non-dominated vertices. + for(auto & v: nbhrs_to_insert) { + sparse_colpsd_adj_Matrix->insert(rw, v) = 1; // This creates the full matrix + if(rw < v) { + oneSimplices.push_back({rowToVertex[rw],rowToVertex[v]}); + filteredEgdeIter.push({{rw,v},1}) ; + // if(rw == v) + // std::cout << "Pushed the edge {" << rw << ", " << v << "} " << std::endl; + edgeStatusMap[{rw,v}] = true; + } + } + } + } + // std::cout << "Total number of non-zero elements before domination check are: " << sparse_colpsd_adj_Matrix->nonZeros() << std::endl; + // std::cout << "Total number of edges for domination check are: " << filteredEgdeIter.size() << std::endl; + // std::cout << *sparse_colpsd_adj_Matrix << std::endl; + return ; + } + + //! Function to fully compact a particular vertex of the ReductionMap. + /*! + It takes as argument the iterator corresponding to a particular vertex pair (key-value) stored in the ReductionMap.
+ It then checks if the second element of this particular vertex pair is present as a first element of some other key-value pair in the map. + If no, then the first element of the vertex pair in consideration is fully compact. + If yes, then recursively call fully_compact_this_vertex() on the second element of the original pair in consideration and assign its resultant image as the image of the first element of the original pair in consideration as well. + */ + void fully_compact_this_vertex(Map::iterator iter) + { + Map::iterator found = ReductionMap.find(iter->second); + if ( found == ReductionMap.end() ) + return; + + fully_compact_this_vertex(found); + iter->second = ReductionMap[iter->second]; + } + + //! Function to fully compact the Reduction Map. + /*! + While doing strong collapses, we store only the immediate collapse of a vertex. Which means that in one round, vertex x may collapse to vertex y. + And in some later round it may be possible that vertex y collapses to z. In which case our map stores :
+ x -> y and also y -> z. But it really should store : + x -> z and y -> z. This function achieves the same.
+ It basically calls fully_compact_this_vertex() for each entry in the map. + */ + void fully_compact() + { + Map::iterator it = ReductionMap.begin(); + while(it != ReductionMap.end()) + { + fully_compact_this_vertex(it); + it++; + } + } + + void sparse_strong_vertex_collapse() + { + complete_vertex_domination_check(rowIterator, rowInsertIndicator, vertDomnIndicator); // Complete check for rows in rowIterator, rowInsertIndicator is a list of boolean indicator if a vertex is already inserted in the working row_queue (rowIterator) + if( not rowIterator.empty()) + sparse_strong_vertex_collapse(); + else + return ; + } + + void complete_vertex_domination_check (doubleQueue& iterator, boolVector& insertIndicator, boolVector& domnIndicator) + { + double k; + doubleVector nonZeroInnerIdcs; + while(not iterator.empty()) // "iterator" contains list(FIFO) of rows to be considered for domination check + { + k = iterator.front(); + iterator.pop(); + insertIndicator[k] = false; + if( not domnIndicator[k]) // Check if is already dominated + { + nonZeroInnerIdcs = closed_neighbours_row_index(k); + for (doubleVector::iterator it = nonZeroInnerIdcs.begin(); it!=nonZeroInnerIdcs.end(); it++) + { + int checkDom = vertex_domination_check(k, *it); // "true" for row domination comparison + if( checkDom == 1) // row k is dominated by *it, k <= *it; + { + setZero(k, *it); + break ; + } + else if(checkDom == -1) // row *it is dominated by k, *it <= k; + setZero(*it, k); + } + } + } + } + + bool check_edge_domination(Edge e) // Edge e is the actual edge (u,v). Not the row ids in the matrixs + { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_e = std::make_pair(rw_u,rw_v); + // std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; + auto commonNeighbours = closed_common_neighbours_row_index(rw_e); + // std::cout << "And its common neighbours are." << std::endl; + // for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + // std::cout << rowToVertex[*it] << ", " ; + // } + //std::cout<< std::endl; + if(commonNeighbours.size() > 2) { + if (commonNeighbours.size() == 3) + return true; + else + for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + auto rw_c = *it; // Typecasting + if(rw_c != rw_u and rw_c != rw_v) { + auto neighbours_c = closed_neighbours_row_index(rw_c); + if(std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), commonNeighbours.end())) // If neighbours_c contains the common neighbours. + return true; + } + } + } + return false; + } + + bool check_domination_indicator(Edge e) // The edge should be sorted by the indices and indices are original + { + return dominated_edge_indicator[edge_to_index_map[e]]; + } + + std::set three_clique_indices(std::size_t crit) { + std::set edge_indices; + + EdgeFilt fe = fEgdeVector.at(crit); + Edge e = std::get<0>(fe); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + + // std::cout << "The current critical edge to re-check criticality with filt value is : {" << u << "," << v << "}; "<< std::get<1>(fe) << std::endl; + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_critical_edge = std::make_pair(rw_u,rw_v); + + doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); + + if(commonNeighbours.size() > 2) { + for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + auto rw_c = *it; + if(rw_c != rw_u and rw_c != rw_v) { + auto e_with_new_nbhr_v = std::minmax(u,rowToVertex[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v,rowToVertex[rw_c]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); + } + } + } + return edge_indices; + + } + + void set_edge_critical(std::size_t indx, double filt) + { + // std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; + std::set effectedIndcs = three_clique_indices(indx); + if(effectedIndcs.size() > 0){ + for(auto idx = indx-1; idx > 0 ; idx--) { + EdgeFilt fec = fEgdeVector.at(idx); + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + if ( not critical_edge_indicator.at(idx) ) { // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() + if( effectedIndcs.find(idx) != effectedIndcs.end()) { // If idx is affected + if(not check_edge_domination(e)) { + // std::cout << "The curent index is became critical " << idx << std::endl; + critical_edge_indicator.at(idx) = true; + criticalCoreEdges.push_back({filt,u,v}); + std::set inner_effected_indcs = three_clique_indices(idx); + for(auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++ ) + { + if(*inr_idx < idx) + effectedIndcs.emplace(*inr_idx); + } + inner_effected_indcs.clear(); + // std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << std::get<1>(e) << "}; " << filt << std::endl; + } + else + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u],vertexToRow[v])); + } + else // Idx is not affected hence dominated. + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u],vertexToRow[v])); + + } + } + + } + effectedIndcs.clear(); + u_set_dominated_redges.clear(); + + } + + void critical_core_edges() + { + std::size_t totEdges = fEgdeVector.size(); + + std::size_t endIdx = 0; + + u_set_removed_redges.clear(); + u_set_dominated_redges.clear(); + critical_edge_indicator.clear(); + + while( endIdx < totEdges) + { + EdgeFilt fec = fEgdeVector.at(endIdx); + + insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)),std::get<1>(fec)); // Inserts the edge in the sparse matrix to update the graph (G_i) + // cfiltVal = std::get<1>(fEgdeVector.at(endIdx)); + // std::cout << "The current processing index is " << endIdx << std::endl; + + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + edge_to_index_map.emplace(std::minmax(u,v), endIdx); + critical_edge_indicator.push_back(false); + dominated_edge_indicator.push_back(false); + + if ( not check_edge_domination(e) ) + { + critical_edge_indicator.at(endIdx) = true; + dominated_edge_indicator.at(endIdx) = false; + criticalCoreEdges.push_back({std::get<1>(fec),u,v}); + if(endIdx > 1) + set_edge_critical(endIdx, std::get<1>(fec)); + + } + else + dominated_edge_indicator.at(endIdx) = true; + endIdx++; + } + + std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; + std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; +} + + + int vertex_domination_check( double i, double j) // True for row comparison, false for column comparison + { + if(i != j) + { + doubleVector Listi = closed_neighbours_row_index(i); + doubleVector Listj = closed_neighbours_row_index(j); + if(Listj.size() <= Listi.size()) + { + if(std::includes(Listi.begin(), Listi.end(), Listj.begin(), Listj.end())) // Listj is a subset of Listi + return -1; + } + + else + if(std::includes(Listj.begin(), Listj.end(), Listi.begin(), Listi.end())) // Listi is a subset of Listj + return 1; + } + return 0; + } + + doubleVector closed_neighbours_row_index(double indx) // Returns list of non-zero columns of the particular indx. + { + doubleVector nonZeroIndices; + Vertex u = indx; + Vertex v; + // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; + if(not vertDomnIndicator[indx]) { + for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { // Iterate over the non-zero columns + v = it.index(); + if(not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { // If the vertex v is not dominated and the edge {u,v} is still in the matrix + nonZeroIndices.push_back(it.index()); // inner index, here it is equal to it.columns() + // std::cout << rowToVertex[it.index()] << ", " ; + } + } + // std::cout << std::endl; + } + return nonZeroIndices; + } + + doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. + { + doubleVector common; + doubleVector nonZeroIndices_u; + doubleVector nonZeroIndices_v; + double u = std::get<0>(e) ; + double v = std::get<1>(e) ; + + nonZeroIndices_u = closed_neighbours_row_index(u); + nonZeroIndices_v = closed_neighbours_row_index(v); + std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), nonZeroIndices_v.end(), std::inserter(common, common.begin())); + + return common; + } + + void setZero(double dominated, double dominating) + { + for(auto & v: closed_neighbours_row_index(dominated)) + if(not rowInsertIndicator[v]) // Checking if the row is already inserted + { + rowIterator.push(v); + rowInsertIndicator[v] = true; + } + vertDomnIndicator[dominated] = true; + ReductionMap[rowToVertex[dominated]] = rowToVertex[dominating]; + + vertexToRow.erase(rowToVertex[dominated]); + vertices.erase(rowToVertex[dominated]); + rowToVertex.erase(dominated); + } + + vertexVector closed_neighbours_vertex_index(double rowIndx) // Returns list of non-zero "vertices" of the particular colIndx. the difference is in the return type + { + vertexVector colmns ; + for(auto & v: closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns + colmns.push_back(rowToVertex[v]); + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + vertexVector vertex_closed_active_neighbours(double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx which are currently active. the difference is in the return type. + { + vertexVector colmns ; + for(auto & v: closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns + if(not contractionIndicator[v]) // Check if the row corresponds to a contracted vertex + colmns.push_back(rowToVertex[v]); + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + vertexVector closed_all_neighbours_row_index(double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx whether dominated or not. the difference is in the return type. + { + vertexVector colmns ; + for (rowInnerIterator itCol(sparseRowAdjMatrix,rowIndx); itCol; ++itCol) // Iterate over the non-zero columns + colmns.push_back(rowToVertex[itCol.index()]); // inner index, here it is equal to it.row() + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + void swap_rows(const Vertex & v, const Vertex & w) { // swap the rows of v and w. Both should be members of the skeleton + if(membership(v) && membership(w)){ + auto rw_v = vertexToRow[v]; + auto rw_w = vertexToRow[w]; + vertexToRow[v] = rw_w; + vertexToRow[w] = rw_v; + rowToVertex[rw_v] = w; + rowToVertex[rw_w] = v; + } + } + +public: + + //! Default Constructor + /*! + Only initialises all Data Members of the class to empty/Null values as appropriate. + One WILL have to create the matrix using the Constructor that has an object of the Simplex_tree class as argument. + */ + + FlagComplexSpMatrix() + { + init(); + } + + FlagComplexSpMatrix(std::size_t expRows) + { + init(); + sparseRowAdjMatrix = sparseRowMatrix(expansion_limit*expRows, expansion_limit*expRows); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + } + + //! Main Constructor + /*! + Argument is an instance of Filtered_sorted_edge_list.
+ This is THE function that initialises all data members to appropriate values.
+ rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. + vertDomnIndicator, rowInsertIndicator ,rowIterator are initialised by init() function which is called at the begining of this.
+ */ + //Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); + FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list &edge_t) { + init(); + + filtEdgeCol = false; + sparseRowAdjMatrix = sparseRowMatrix(expansion_limit*num_vertices, expansion_limit*num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + + for(size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { + std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; + insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); + } + sparseRowAdjMatrix.makeCompressed(); + + // std::cout << sparseRowAdjMatrix << std::endl; + } + FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list & edge_t, const bool fEdgeCol) { + if(fEdgeCol) + { + init(); + filtEdgeCol = true; + sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + + for(size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { + // std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; + // insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); + fEgdeVector.push_back({{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))},std::get<0>(edge_t.at(bgn_idx))}); + } + + // sparseRowAdjMatrix.makeCompressed(); + } + else + FlagComplexSpMatrix(num_vertices, edge_t); + + // std::cout << sparseRowAdjMatrix << std::endl; + } + + //! Destructor. + /*! + Frees up memory locations on the heap. + */ + ~FlagComplexSpMatrix() + { + } + + //! Function for performing strong collapse. + /*! + calls sparse_strong_vertex_collapse(), and + Then, it compacts the ReductionMap by calling the function fully_compact(). + */ + double strong_vertex_collapse() { + auto begin_collapse = std::chrono::high_resolution_clock::now(); + sparse_strong_vertex_collapse(); + vertexCollapsed = true; + auto end_collapse = std::chrono::high_resolution_clock::now(); + + auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); + // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; + + // Now we complete the Reduction Map + fully_compact(); + //Post processing... + after_vertex_collapse(); + return collapseTime; + } + + // Performs edge collapse in of a given sparse-matrix(graph) without considering the filtration value. + // double strong_edge_collapse() { + // auto begin_collapse = std::chrono::high_resolution_clock::now(); + // critical_core_edges(); + // vertexCollapsed = false; + // edgeCollapsed = true; + // auto end_collapse = std::chrono::high_resolution_clock::now(); + + // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); + // // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; + // //Post processing... + // after_edge_collapse(); + // return collapseTime; + // } + + + // Performs edge collapse in a decreasing sequence of the filtration value. + Filtered_sorted_edge_list filtered_edge_collapse(double steps) { + auto begin_collapse = std::chrono::high_resolution_clock::now(); + critical_core_edges(); + vertexCollapsed = false; + edgeCollapsed = true; + auto end_collapse = std::chrono::high_resolution_clock::now(); + + auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); + std::cout << "Time of filtered edge Collapse : " << collapseTime << " ms\n" << std::endl; + //Post processing... + // after_edge_collapse(); + // std::cout << sparseRowAdjMatrix << std::endl; + // for(auto idx = criticalCoreEdges.begin(); idx != criticalCoreEdges.end(); idx++ ) + // { + // std::cout << + // } + return criticalCoreEdges; + } + + // double strong_vertex_edge_collapse() { + // auto begin_collapse = std::chrono::high_resolution_clock::now(); + // strong_vertex_collapse(); + // strong_edge_collapse(); + // // strong_vertex_collapse(); + // auto end_collapse = std::chrono::high_resolution_clock::now(); + + // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); + // return collapseTime; + // } + + bool membership(const Vertex & v) { + auto rw = vertexToRow.find(v); + if(rw != vertexToRow.end()) + return true; + else + return false; + } + + bool membership(const Edge & e) { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + if(membership(u) && membership(v)) { + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + if(rw_u <= rw_v) + for( auto x : closed_neighbours_row_index(rw_v)){ // Taking advantage of sorted lists. + if(rw_u == x) + return true; + else if(rw_u < x) + return false; + } + else + for( auto x : closed_neighbours_row_index(rw_u)){ // Taking advantage of sorted lists. + if(rw_v == x) + return true; + else if(rw_v < x) + return false; + } + } + return false; + + } + void insert_vertex(const Vertex & vertex, double filt_val) + { + auto rw = vertexToRow.find(vertex); + if(rw == vertexToRow.end()) { + sparseRowAdjMatrix.insert(rows,rows) = filt_val; // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + vertDomnIndicator.push_back(false); + rowInsertIndicator.push_back(true); + contractionIndicator.push_back(false); + rowIterator.push(rows); + vertexToRow.insert(std::make_pair(vertex, rows)); + rowToVertex.insert(std::make_pair(rows, vertex)); + vertices.emplace(vertex); + rows++; + } + } + + void insert_new_edges(const Vertex & u, const Vertex & v, double filt_val) // The edge must not be added before, it should be a new edge. + { + insert_vertex(u, filt_val); + if( u != v) { + insert_vertex(v, filt_val); + // std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; + + auto rw_u = vertexToRow.find(u); + auto rw_v = vertexToRow.find(v); + // std::cout << "Inserting the edge " << u <<", " << v << std::endl; + sparseRowAdjMatrix.insert(rw_u->second,rw_v->second) = filt_val; + sparseRowAdjMatrix.insert(rw_v->second,rw_u->second) = filt_val; + oneSimplices.emplace_back(u, v); + numOneSimplices++; + } + // else + // std::cout << "Already a member simplex, skipping..." << std::endl; + + } + + + + std::size_t num_vertices() const { + return vertices.size(); + } + + //! Function for returning the ReductionMap. + /*! + This is the (stl's unordered) map that stores all the collapses of vertices.
+ It is simply returned. + */ + + Map reduction_map() const { + return ReductionMap; + } + std::unordered_set vertex_set() const { + return vertices; + } + sparseRowMatrix collapsed_matrix() const { + return *sparse_colpsd_adj_Matrix; + } + + sparseRowMatrix uncollapsed_matrix() const { + return sparseRowAdjMatrix; + } + + edge_list all_edges() const { + return oneSimplices; + } + + vertexVector active_neighbors(const Vertex & v) { + vertexVector nb; + auto rw_v = vertexToRow.find(v); + if(rw_v != vertexToRow.end()) + nb = vertex_closed_active_neighbours(rw_v->second); + return nb; + } + + vertexVector neighbors(const Vertex & v) { + vertexVector nb; + auto rw_v = vertexToRow.find(v); + if(rw_v != vertexToRow.end()) + nb = closed_neighbours_vertex_index(rw_v->second); + + return nb; + } + + vertexVector active_relative_neighbors(const Vertex & v, const Vertex & w){ + std::vector diff; + if(membership(v) && membership(w)){ + auto nbhrs_v = active_neighbors(v); + auto nbhrs_w = active_neighbors(w); + std::set_difference(nbhrs_v.begin(), nbhrs_v.end(), nbhrs_w.begin(), nbhrs_w.end(), std::inserter(diff, diff.begin())); + } + return diff; + } + + + void contraction(const Vertex & del, const Vertex & keep){ + if(del != keep){ + bool del_mem = membership (del); + bool keep_mem = membership(keep); + if( del_mem && keep_mem) + { + doubleVector del_indcs, keep_indcs, diff; + auto row_del = vertexToRow[del]; + auto row_keep = vertexToRow[keep]; + del_indcs = closed_neighbours_row_index(row_del); + keep_indcs = closed_neighbours_row_index(row_keep); + std::set_difference(del_indcs.begin(), del_indcs.end(), keep_indcs.begin(), keep_indcs.end(), std::inserter(diff, diff.begin())); + for (auto & v : diff) { + if( v != row_del){ + sparseRowAdjMatrix.insert(row_keep,v) = 1; + sparseRowAdjMatrix.insert(v, row_keep) = 1; + } + } + vertexToRow.erase(del); + vertices.erase(del); + rowToVertex.erase(row_del); + //setZero(row_del->second, row_keep->second); + } + else if(del_mem && not keep_mem) + { + vertexToRow.insert(std::make_pair(keep, vertexToRow.find(del)->second)); + rowToVertex[vertexToRow.find(del)->second] = keep; + vertices.emplace(keep); + vertices.erase(del); + vertexToRow.erase(del); + + } + else + { + std::cerr << "The first vertex entered in the method contraction() doesn't exist in the skeleton." <second] = true; + } + if(membership(v) && !membership(w)){ + relable(v,w); + } + } + void active_edge_insertion(const Vertex & v, const Vertex & w, double filt_val){ + insert_new_edges(v,w, filt_val); + //update_active_indicator(v,w); + } + + void print_sparse_skeleton(){ + std::cout << sparseRowAdjMatrix << std::endl; + } + +}; \ No newline at end of file diff --git a/src/Collapse/include/gudhi/PointSetGen.h b/src/Collapse/include/gudhi/PointSetGen.h new file mode 100644 index 00000000..af78b63b --- /dev/null +++ b/src/Collapse/include/gudhi/PointSetGen.h @@ -0,0 +1,273 @@ +#include +#include + +#include +#include +#include + +#include + +using Point = CGAL::Epick_d< CGAL::Dynamic_dimension_tag>::Point_d; +using Vector_of_points = std::vector; + +const double PI = 3.141592653589793238463; +#define _USE_MATH_DEFINES + +class PointSetGen { + private: + double unirand(){return (double) rand()/(double) RAND_MAX;} + public: + void program_options(int argc, char * const argv[] + , std::size_t & number_of_points + , double & begin_thresold + , double & steps + , double & end_thresold + , int & repetetions + , char & manifold + , int & dimension + , int & dim_max + , std::string & in_file_name + , std::string & out_file_name + ) { + namespace po = boost::program_options; + + po::options_description visible("Allowed options", 100); + visible.add_options() + ("help,h", "produce help message") + ("number,n", po::value(&number_of_points)->default_value(0), + "Number of generated point_vector.") + + ("begin_thresold,b", po::value(&begin_thresold)->default_value(0), + "Initial threshold for rips complex.") + ("steps,s", po::value(&steps)->default_value(0.1), + "Steps of the threshold") + ("end_thresold,e", po::value(&end_thresold)->default_value(1), + "Final threshold for rips complex.") + + ("repetetions,r", po::value(&repetetions)->default_value(1), + "Num of repetetions of the experiments.") + ("manifold,m", po::value(&manifold)->default_value('s'), + "Type of manifold") + + ("dimensions,D", po::value(&dimension)->default_value(2), + "Dimension of the manifold.") + + ("dim_max,k ", po::value(&dim_max)->default_value(2), + "Maximum allowed dimension of the Rips complex.") + + ("input_file_name,i", po::value(&in_file_name), + "The input file.") + ("out_file_name,o", po::value(&out_file_name), + "The output file."); + + po::options_description all; + all.add(visible); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv). + options(all).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << std::endl; + std::cout << "Computes rips complexes of different threshold values, from 'begin_thresold' to 'end_thresold', with priodic steps of 'steps' from a n random uniform point_vector on a selected manifold, . \n"; + std::cout << "Strongly collapses all the rips complexes and output the results in out_file. \n"; + std::cout << "The experiments are repeted 'repete' num of times for each threshold value. \n"; + std::cout << "type -m for manifold options, 's' for uni sphere, 'b' for unit ball, 'f' for file. \n"; + std::cout << "type -i 'filename' for Input file option for exported point sample. \n"; + std::cout << std::endl << std::endl; + + std::cout << "Usage: " << argv[0] << " [options]" << std::endl << std::endl; + std::cout << visible << std::endl; + std::abort(); + } + } + + + void generate_points_sphere(Vector_of_points& W, int nbP, int dim, double radius) { + CGAL::Random_points_on_sphere_d rp(dim+1, radius); + for (int i = 0; i < nbP; i++) + W.push_back(*rp++); + } + // void generate_fibonaci_grid_sphere(Vector_of_points& W, int nbP, int dim, double radius) + // { + + // } + + void generate_grid_2sphere(Vector_of_points& W, int nbP, int r ) + { + std::vector coords; + int Ncount = 0; + double p,v; //the angles phi and psi + int M_p; + + double a = (4*PI*pow(r,2))/nbP; + double d = sqrt(a); + + int M_v = PI/d; + + double d_v = PI/M_v; + double d_p = a/d_v; + + for( int m = 0; m < M_v ; m++) { + v = (PI*(m + 0.5))/M_v; + M_p = ((2*PI*sin(v))/d_p); + for(int n = 0; n < M_p ; n++) { + p = (2*PI*n)/M_p; + coords = {r*sin(v)*cos(p), r*sin(v)*sin(p), r*cos(v)}; + W.push_back(Point(coords)); + Ncount += 1; + } + } + } + + + /* + Generates point sets on spheres wedged at origin, sphere can have different radii from with steps of + Number of points on the sphere can also be different from for the smallest sphere and then multiplied by + */ + void generate_points_wedged_sphere(Vector_of_points& W, int init_nbP, int dim, double init_radius, int multiplier_step, int nbSpheres) { + double radius = init_radius; + int nbP = init_nbP; + std::vector translation; + for(int d = 0; d< dim; d++) { + translation.push_back(0); + } + for(int s = 0; s < nbSpheres; s++) { + CGAL::Random_points_on_sphere_d rp(dim+1, radius); + for (int i = 0; i < nbP; i++) { + W.push_back(add_point(*rp++, translation, dim)); + } + nbP = nbP*multiplier_step; + radius = radius*multiplier_step; + translation.at(dim-1) = (radius - init_radius); + } + } + + void generate_points_concentric_sphere(Vector_of_points& W, int init_nbP, int dim, int init_radius, int multiplier_step, int nbSpheres) { + double radius = init_radius; + int nbP = init_nbP; + + for(int s = 0; s < nbSpheres; s++) { + CGAL::Random_points_on_sphere_d rp(dim+1, radius); + for (int i = 0; i < nbP; i++) { + W.push_back(*rp++); + } + nbP = nbP*(pow(multiplier_step,2)); + radius = radius*multiplier_step; + } + + } + void generate_points_2annulus(Vector_of_points& W, int nbP, double r_min, double r_max) { + double rho, theta; + double x, y; + std::vector coords; + double r_min_sq = pow(r_min,2); + double r_max_sq = pow(r_max,2); + + srand(time(NULL)); + for (int i=0; i coords; + double r_min_cube = pow(r_min,3); + double r_max_cube = pow(r_max,3); + + srand(time(NULL)); + for (int i=0; i rp(dim, radius); + for (int i = 0; i < nbP; i++) + W.push_back(*rp++); + } + + void generate_points_cube(Vector_of_points& W, int nbP, int dim) { + CGAL::Random_points_in_cube_d rp(dim, 6); + for (int i = 0; i < nbP; i++) + W.push_back(*rp++); + } + + void add_point_vectors(Vector_of_points& V, Vector_of_points& U, int nbP, int dim) { // Adds two point vectors of the same size (nbP), by Modifying the first one, V = V+W. + for (int i = 0; i < nbP; i++) + { + V[i] = add_point(V[i], U[i], dim); + } + } + + //returns x = x+y; + Point add_point(const Point & x, const Point & y, int dim) { + std::vector coords; + for(int i =0; i< dim; i++) + coords.push_back(x[i]+y[i]); + return Point(coords); + } + void print_point(const Point & x) { + std::cout<< "("; + for(auto & p : x){ + std::cout<< p << ", " ; + } + std::cout<< ")" << std::endl; + } + void output_points(Vector_of_points & W, std::string outFile) { + std::ofstream myfile (outFile, std::ios::app); + if (myfile.is_open()) { + myfile << "OFF" << " " << W.size() << " " << W.at(0).size() << std::endl; + for(auto & v : W){ + for(auto & x : v){ + myfile<< x << " " ; + } + myfile << std::endl; + } + myfile << "# Tower updated for the additional subcomplex.\n"; + myfile.close(); + } + else { + std::cerr << "Unable to open file"; + exit(-1) ; + } + } + + Point noise_point(double noise_param, int dim, double radius) { + std::vector noise; + for(int d = 0; d< dim; d++){ + if(d % 2) + noise.push_back(-noise_param*radius); + else + noise.push_back(noise_param*radius); + } + return Point(noise); + } + //add noise to the points in W. + void add_noise(Vector_of_points& W, int nbP, int dim, double radius, double noise_param) { + Point noise = noise_point(noise_param, dim, radius); + for(Vector_of_points::iterator it = W.begin(); it != W.end(); it++ ) { + *it = add_point(*it,noise,dim); + } + } + + PointSetGen(){} + ~PointSetGen(){} +}; \ No newline at end of file diff --git a/src/Collapse/include/gudhi/Rips_edge_list.h b/src/Collapse/include/gudhi/Rips_edge_list.h new file mode 100644 index 00000000..b7c4dcff --- /dev/null +++ b/src/Collapse/include/gudhi/Rips_edge_list.h @@ -0,0 +1,184 @@ +/* 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(s): Clément Maria, Pawel Dlotko, Vincent Rouvreau Siddharth Pritam + * + * Copyright (C) 2016 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 RIPS_edge_list_H_ +#define RIPS_edge_list_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include // for numeric_limits +#include // for pair<> + + +namespace Gudhi { + +namespace rips_edge_list { + +/** + * \class Rips_complex + * \brief Rips complex data structure. + * + * \ingroup rips_complex + * + * \details + * The data structure is a one skeleton graph, or Rips graph, containing edges when the edge length is less or equal + * to a given threshold. Edge length is computed from a user given point cloud with a given distance function, or a + * distance matrix. + * + * \tparam Filtration_value is the type used to store the filtration values of the simplicial complex. + */ +template +class Rips_edge_list { + public: + /** + * \brief Type of the one skeleton graph stored inside the Rips complex structure. + */ + // typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS + // , boost::property < vertex_filtration_t, Filtration_value > + // , boost::property < edge_filtration_t, Filtration_value >> OneSkeletonGraph; + + private: + typedef int Vertex_handle; + + public: + /** \brief Rips_complex constructor from a list of points. + * + * @param[in] points Range of points. + * @param[in] threshold Rips value. + * @param[in] distance distance function that returns a `Filtration_value` from 2 given points. + * + * \tparam ForwardPointRange must be a range for which `std::begin` and `std::end` return input iterators on a + * point. + * + * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where + * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. + */ + template + Rips_edge_list(const ForwardPointRange& points, Filtration_value threshold, Distance distance) { + compute_proximity_graph(points, threshold, distance); + } + + /** \brief Rips_complex constructor from a distance matrix. + * + * @param[in] distance_matrix Range of distances. + * @param[in] threshold Rips value. + * + * \tparam DistanceMatrix must have a `size()` method and on which `distance_matrix[i][j]` returns + * the distance between points \f$i\f$ and \f$j\f$ as long as \f$ 0 \leqslant i < j \leqslant + * distance\_matrix.size().\f$ + */ + template + Rips_edge_list(const DistanceMatrix& distance_matrix, Filtration_value threshold) { + compute_proximity_graph(boost::irange((size_t)0, distance_matrix.size()), threshold, + [&](size_t i, size_t j){return distance_matrix[j][i];}); + } + + /** \brief Initializes the egde list (one skeleton) complex from the Rips graph + * + * \tparam EdgeListForRips must meet `EdgeListForRips` concept. + * + * @param[in] edges EdgeListForRips to be created. + * @param[in] dim_max graph expansion for Rips until this given maximal dimension. + * @exception std::invalid_argument In debug mode, if `edges.num_vertices()` does not return 0. + * + */ + template + void create_edges(EdgeListForRips& edge_list) { + GUDHI_CHECK(edges.num_vertices() == 0, + std::invalid_argument("Rips_complex::create_complex - edge list is not empty")); + + // sort the tuple (filteration_valuem, (v1,v2){edge}) + //By default the sort is done on the first element, so here it's filteration value. + std::sort(edges.begin(),edges.end()); + for(size_t i = 0; i < edges.size(); i++ ) + edge_list.emplace_back(edges.at(i)); + + } + + private: + /** \brief Computes the proximity graph of the points. + * + * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the + * distance function between points u and v is smaller than threshold. + * + * \tparam ForwardPointRange furnishes `.begin()` and `.end()` + * methods. + * + * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where + * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. + */ + template< typename ForwardPointRange, typename Distance > + void compute_proximity_graph(const ForwardPointRange& points, Filtration_value threshold, + Distance distance) { + edges.clear(); + // Compute the proximity graph of the points. + // If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the + // distance function between points u and v is smaller than threshold. + // -------------------------------------------------------------------------------------------- + // Creates the vector of edges and its filtration values (returned by distance function) + Vertex_handle idx_u = 0; + for (auto it_u = std::begin(points); it_u != std::end(points); ++it_u, ++idx_u) { + Vertex_handle idx_v = idx_u + 1; + for (auto it_v = it_u + 1; it_v != std::end(points); ++it_v, ++idx_v) { + Filtration_value fil = distance(*it_u, *it_v); + if (fil <= threshold) { + edges.emplace_back(fil, idx_u, idx_v); + } + } + } + + // -------------------------------------------------------------------------------------------- + // Creates the proximity graph from edges and sets the property with the filtration value. + // Number of points is labeled from 0 to idx_u-1 + // -------------------------------------------------------------------------------------------- + // Do not use : rips_skeleton_graph_ = OneSkeletonGraph(...) -> deep copy of the graph (boost graph is not + // move-enabled) + // rips_skeleton_graph_.~OneSkeletonGraph(); + // new(&rips_skeleton_graph_)OneSkeletonGraph(edges.begin(), edges.end(), edges_fil.begin(), idx_u); + + // auto vertex_prop = boost::get(vertex_filtration_t(), rips_skeleton_graph_); + + // using vertex_iterator = typename boost::graph_traits::vertex_iterator; + // vertex_iterator vi, vi_end; + // for (std::tie(vi, vi_end) = boost::vertices(rips_skeleton_graph_); + // vi != vi_end; ++vi) { + // boost::put(vertex_prop, *vi, 0.); + // } + } + + private: + // OneSkeletonGraph rips_skeleton_graph_; + std::vector< std::tuple < Filtration_value, Vertex_handle, Vertex_handle > > edges; + // std::vector< Filtration_value > edges_fil; +}; + +} // namespace rips_complex + +} // namespace Gudhi + +#endif // RIPS_COMPLEX_H_ diff --git a/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h b/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h new file mode 100644 index 00000000..01d86642 --- /dev/null +++ b/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h @@ -0,0 +1,184 @@ +#pragma once +#include +#include + +#include +#include +#include +#include +#include +#include + + +typedef std::size_t Vertex; +using Edge = std::pair; +using edge_list = std::vector; +using Simplex = std::vector; + +using vectorVertex = std::vector; +using vert_unSet = std::unordered_set; +using Map = std::unordered_map; +using Distance_matrix = std::vector>; +// using infinity = std::numeric_limits::max(); +// assumptions : (1) K1 and K2 have the same vertex set +// (2) The set of simplices of K1 is a subset of set of simplices of K2 +// K1 -> K2 [Original Simplicial Complexes] +// | | +// | | +// K1c -> K2c [Strongly Collapsed Flag Complexes] + +class TowerAssembler_FlagComplex +{ + private: + Map renamedVertices; + Map representative_map; + std::size_t current_rename_counter; + Distance_matrix * distance_mat; + size_t total_vertices; + + // Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); + FlagComplexSpMatrix * flag_Filtration; + typedef std::vector< std::tuple< double, Vertex, Vertex > > Filtered_sorted_edge_list; + + + public: + + TowerAssembler_FlagComplex(std::size_t numVert) + { + for (std::size_t i = 0; i <= numVert; ++i){ + renamedVertices[i] = i; + } + total_vertices = 0; + current_rename_counter = numVert+1; + + flag_Filtration = new FlagComplexSpMatrix((numVert*log2(numVert)) +1); + distance_mat = new Distance_matrix(); + // distance_mat->push_back({0}); + } + + ~TowerAssembler_FlagComplex(){}; + double build_tower_for_two_cmplxs(FlagComplexSpMatrix mat_1, const FlagComplexSpMatrix & mat_2, Map redmap_2, double filtration_value, std::string outFile) // mat_1 and mat_2 are simplex_trees of K1c and K2c (the collapsed ones), redmap_2 is the map of K2 -> K2c + { + auto begin_print = std::chrono::high_resolution_clock::now(); + std::ofstream myfile (outFile, std::ios::app); + if (myfile.is_open()) + { + for (auto & v : mat_1.vertex_set()) { + auto collapsed_to = redmap_2.find(v); // If v collapsed to something? + if(collapsed_to != redmap_2.end()) { // Collapse happened, because there is a vertex in the map + if(mat_1.membership(collapsed_to->second)) { // Collapsed to an existing vertex in mat_1. + + // myfile << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; + std::cout << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; + flag_Filtration->active_strong_expansion(renamedVertices.at(v), renamedVertices.at(collapsed_to->second), filtration_value); + renamedVertices.at(v) = current_rename_counter; + current_rename_counter++; + } + else { + // myfile << filtration_value << " i " << renamedVertices.at(collapsed_to->second) << std::endl; + // myfile << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; + flag_Filtration->active_strong_expansion(renamedVertices.at(v), renamedVertices.at(collapsed_to->second),filtration_value); + std::cout << filtration_value << " i " << renamedVertices.at(collapsed_to->second) << std::endl; + std::cout << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; + renamedVertices.at(v) = current_rename_counter; + current_rename_counter++; + } + // If the vertex "collapsed_to->second" is not a member of mat_1, the contraction function will simply add and then collapse + mat_1.contraction(v, collapsed_to->second); + // std::cout << " Contraction Done " << std::endl; + + } + } + + //The core K1c (mat_1) has gone through the transformation(re-labeling)/collapse and it is now a subcomplex of K2c, the remaining simplices need to be included + // Writing the inclusion of all remaining simplices... + // std::cout << "Begining the inclusion of edges " << std::endl; + for( const Edge & e : mat_2.all_edges()) { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + // std::cout << "Going to insert the edge :" << renamedVertices.at(u) << ", " << renamedVertices.at(v) << std::endl; + // std::cout << "Going to insert the vertex :" << u << std::endl; + if(!mat_1.membership(u)) { + flag_Filtration->insert_vertex(renamedVertices.at(u),filtration_value); + // std::cout << "Inserted the vertex :" << renamedVertices.at(u) << " in the new distance matrix"<< std::endl; + // myfile << filtration_value << " i"; + // myfile << " " << renamedVertices.at(u); + // myfile << std::endl; + mat_1.insert_vertex(u,1); + // std::cout << "Inserted the vertex :" << renamedVertices.at(u) << " in the old skeleton matrix"<< std::endl; + + + } + + // std::cout << "Going to insert the vertex :" << v << std::endl ; + if(!mat_1.membership(v)) { + // std::cout << "Begining the insertion the vertex :" << renamedVertices.at(v) << " in the new distance matrix"<< std::endl; + + flag_Filtration->insert_vertex(renamedVertices.at(v),filtration_value); + // std::cout << "Inserted the vertex :" << renamedVertices.at(v) << " in the new distance matrix"<< std::endl; + + // myfile << filtration_value << " i"; + // myfile << " " << renamedVertices.at(v); + // myfile << std::endl; + mat_1.insert_vertex(v,1); + // std::cout << "Inserted the vertex :" << v << " in the old skeleton matrix"<< std::endl; + + } + // std::cout << "Going to insert the edge :" << u << ", " << v << std::endl; + if(!mat_1.membership(e)){ + flag_Filtration->insert_new_edges(renamedVertices.at(u),renamedVertices.at(v), filtration_value); + // std::cout << "Inserted the edge :" << renamedVertices.at(u) << ","<< renamedVertices.at(v) << " in the new distance matrix"<< std::endl; + + // myfile << filtration_value << " i"; + // myfile << " " << renamedVertices.at(u) << ", " << renamedVertices.at(v); + // myfile << std::endl; + // std::cout << "Going to insert the edge :" << u << ","<< v << " in the old skeleton"<< std::endl; + mat_1.insert_new_edges(u,v,1); + // std::cout << "Inserted the edge :" << u << ","<< v << " in the old skeleton"<< std::endl; + } + // std::cout << " Insertion Done " << std::endl; + } + + // myfile << "# Tower updated for the additional subcomplex.\n"; + myfile.close(); + } + else { + std::cerr << "Unable to open file"; + exit(-1) ; + } + + auto end_print = std::chrono::high_resolution_clock::now(); + auto printTime = std::chrono::duration(end_print- begin_print).count(); + // std::cout << " Time to print the tower : " << printTime << " ms\n" << std::endl; + return printTime; + } + Distance_matrix distance_matrix() + { + size_t non_zero_rw = flag_Filtration->num_vertices(); + double inf = std::numeric_limits::max(); + sparseRowMatrix mat = flag_Filtration->uncollapsed_matrix(); + doubleVector distances ; + for(size_t indx = 0; indx < non_zero_rw; indx++){ + rowInnerIterator it(mat, indx); + for(size_t j = 0; j <= indx; j++) { // Iterate over the non-zero columns + //std::cout << "j = " << j << " - it.index = " << it.index() << " - indx = " << indx << std::endl; + if(it.index() == j && j != indx){ + distances.push_back(it.value()); // inner index, here it is equal to it.columns() + ++it; + } + else if( j == indx) + distances.push_back(0); + else + distances.push_back(inf); + + } + distance_mat->push_back(distances); + distances.clear(); + } + return *distance_mat; + } + void print_sparse_matrix(){ + flag_Filtration->print_sparse_skeleton(); + } + +}; -- cgit v1.2.3 From ac06d17b3eb9fb45160dd5f1d17a527d54e075ca Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 18 Mar 2020 21:53:08 +0100 Subject: Remove tower assembler as not used by edge collapse --- src/Collapse/example/rips_persistence_with_sc.cpp | 81 --------- .../include/gudhi/TowerAssembler_FlagComplex.h | 184 --------------------- 2 files changed, 265 deletions(-) delete mode 100644 src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index 5336b202..65b886f7 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -46,83 +45,7 @@ public: } }; -class strong_filtered_vertex_collapse -{ -public: - template - strong_filtered_vertex_collapse(std::size_t number_of_points, Filtered_sorted_edge_list & edge_t, double steps, Distance_matrix & sparse_distances) - { - auto the_collapse_begin = std::chrono::high_resolution_clock::now(); - //An additional vector to perform binary search to find the index of given threshold - std::vector * edge_filt = new std::vector(); - edge_filt->clear(); - for(auto edIt = edge_t.begin(); edIt != edge_t.end(); edIt++) { - edge_filt->push_back(std::get<0>(*edIt)); - } - double begin_thresold = edge_filt->at(0); - double end_threshold = edge_filt->at(edge_filt->size()-1); - double totAssembleTime = 0.0; - Filtered_sorted_edge_list * sub_skeleton = new Filtered_sorted_edge_list(); - TowerAssembler_FlagComplex twr_assembler(number_of_points) ; - - std::cout<< "Begin and end thresholds (filteration values) are , " << begin_thresold <<", " << end_threshold << "." <size() > 0) { - - if(steps > 0) - extract_sub_one_skeleton(threshold, *sub_skeleton, edge_t, *edge_filt); - else - extract_one_new_edge(*sub_skeleton, edge_t, *edge_filt); - - - mat_coll = new FlagComplexSpMatrix(number_of_points, *sub_skeleton); - // mat_coll->strong_vertex_edge_collapse(); - mat_coll->strong_vertex_collapse(); - // std::cout<< " Total number of current edges are " << sub_skeleton->size() << std::endl; - - redmap = new Map(); - *redmap = mat_coll->reduction_map(); - - // std::cout << "Subcomplex #" << i << " of threshold "<< threshold << " Collapsed" << std::endl; - totAssembleTime += twr_assembler.build_tower_for_two_cmplxs(*mat_prev_coll, *mat_coll, *redmap, threshold, "./PersistenceOutput/CollapsedTowerRips.txt"); - // std::cout << "Tower updated for subcomplex #" << i << std::endl; - - delete mat_prev_coll; - mat_prev_coll = new FlagComplexSpMatrix(); - mat_prev_coll = mat_coll; - mat_coll = new FlagComplexSpMatrix(); - i++; - delete redmap; - if(steps > 0) { - threshold = threshold+steps; - if(threshold > end_threshold) - threshold = end_threshold; - } - else { - if(edge_filt->size() > 0) - threshold = edge_filt->at(0); - } - } - std::cout << "Tower updated for subcomplex #" << i << std::endl; - auto the_collapse = std::chrono::high_resolution_clock::now(); - sparse_distances = twr_assembler.distance_matrix(); - std::cout << "Collapse And assembly time : " << std::chrono::duration(the_collapse- the_collapse_begin).count() << " ms\n" << std::endl; - } - -}; class filt_edge_to_dist_matrix { public: @@ -320,10 +243,6 @@ int main(int argc, char * const argv[]) { exit(-1) ; } - - // std::cout<< "Vertex strong-collapse begins" << std::endl; - // strong_filtered_vertex_collapse(number_of_points, *edge_t, steps, *sparse_distances); - auto end_full_cmplx = std::chrono::high_resolution_clock::now(); currentCreationTime = std::chrono::duration(end_full_cmplx - begin_full_cmplx).count(); maxCreationTime = currentCreationTime; diff --git a/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h b/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h deleted file mode 100644 index 01d86642..00000000 --- a/src/Collapse/include/gudhi/TowerAssembler_FlagComplex.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once -#include -#include - -#include -#include -#include -#include -#include -#include - - -typedef std::size_t Vertex; -using Edge = std::pair; -using edge_list = std::vector; -using Simplex = std::vector; - -using vectorVertex = std::vector; -using vert_unSet = std::unordered_set; -using Map = std::unordered_map; -using Distance_matrix = std::vector>; -// using infinity = std::numeric_limits::max(); -// assumptions : (1) K1 and K2 have the same vertex set -// (2) The set of simplices of K1 is a subset of set of simplices of K2 -// K1 -> K2 [Original Simplicial Complexes] -// | | -// | | -// K1c -> K2c [Strongly Collapsed Flag Complexes] - -class TowerAssembler_FlagComplex -{ - private: - Map renamedVertices; - Map representative_map; - std::size_t current_rename_counter; - Distance_matrix * distance_mat; - size_t total_vertices; - - // Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); - FlagComplexSpMatrix * flag_Filtration; - typedef std::vector< std::tuple< double, Vertex, Vertex > > Filtered_sorted_edge_list; - - - public: - - TowerAssembler_FlagComplex(std::size_t numVert) - { - for (std::size_t i = 0; i <= numVert; ++i){ - renamedVertices[i] = i; - } - total_vertices = 0; - current_rename_counter = numVert+1; - - flag_Filtration = new FlagComplexSpMatrix((numVert*log2(numVert)) +1); - distance_mat = new Distance_matrix(); - // distance_mat->push_back({0}); - } - - ~TowerAssembler_FlagComplex(){}; - double build_tower_for_two_cmplxs(FlagComplexSpMatrix mat_1, const FlagComplexSpMatrix & mat_2, Map redmap_2, double filtration_value, std::string outFile) // mat_1 and mat_2 are simplex_trees of K1c and K2c (the collapsed ones), redmap_2 is the map of K2 -> K2c - { - auto begin_print = std::chrono::high_resolution_clock::now(); - std::ofstream myfile (outFile, std::ios::app); - if (myfile.is_open()) - { - for (auto & v : mat_1.vertex_set()) { - auto collapsed_to = redmap_2.find(v); // If v collapsed to something? - if(collapsed_to != redmap_2.end()) { // Collapse happened, because there is a vertex in the map - if(mat_1.membership(collapsed_to->second)) { // Collapsed to an existing vertex in mat_1. - - // myfile << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; - std::cout << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; - flag_Filtration->active_strong_expansion(renamedVertices.at(v), renamedVertices.at(collapsed_to->second), filtration_value); - renamedVertices.at(v) = current_rename_counter; - current_rename_counter++; - } - else { - // myfile << filtration_value << " i " << renamedVertices.at(collapsed_to->second) << std::endl; - // myfile << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; - flag_Filtration->active_strong_expansion(renamedVertices.at(v), renamedVertices.at(collapsed_to->second),filtration_value); - std::cout << filtration_value << " i " << renamedVertices.at(collapsed_to->second) << std::endl; - std::cout << filtration_value << " c " << renamedVertices.at(v) << " " << renamedVertices.at(collapsed_to->second) << std::endl; - renamedVertices.at(v) = current_rename_counter; - current_rename_counter++; - } - // If the vertex "collapsed_to->second" is not a member of mat_1, the contraction function will simply add and then collapse - mat_1.contraction(v, collapsed_to->second); - // std::cout << " Contraction Done " << std::endl; - - } - } - - //The core K1c (mat_1) has gone through the transformation(re-labeling)/collapse and it is now a subcomplex of K2c, the remaining simplices need to be included - // Writing the inclusion of all remaining simplices... - // std::cout << "Begining the inclusion of edges " << std::endl; - for( const Edge & e : mat_2.all_edges()) { - auto u = std::get<0>(e); - auto v = std::get<1>(e); - // std::cout << "Going to insert the edge :" << renamedVertices.at(u) << ", " << renamedVertices.at(v) << std::endl; - // std::cout << "Going to insert the vertex :" << u << std::endl; - if(!mat_1.membership(u)) { - flag_Filtration->insert_vertex(renamedVertices.at(u),filtration_value); - // std::cout << "Inserted the vertex :" << renamedVertices.at(u) << " in the new distance matrix"<< std::endl; - // myfile << filtration_value << " i"; - // myfile << " " << renamedVertices.at(u); - // myfile << std::endl; - mat_1.insert_vertex(u,1); - // std::cout << "Inserted the vertex :" << renamedVertices.at(u) << " in the old skeleton matrix"<< std::endl; - - - } - - // std::cout << "Going to insert the vertex :" << v << std::endl ; - if(!mat_1.membership(v)) { - // std::cout << "Begining the insertion the vertex :" << renamedVertices.at(v) << " in the new distance matrix"<< std::endl; - - flag_Filtration->insert_vertex(renamedVertices.at(v),filtration_value); - // std::cout << "Inserted the vertex :" << renamedVertices.at(v) << " in the new distance matrix"<< std::endl; - - // myfile << filtration_value << " i"; - // myfile << " " << renamedVertices.at(v); - // myfile << std::endl; - mat_1.insert_vertex(v,1); - // std::cout << "Inserted the vertex :" << v << " in the old skeleton matrix"<< std::endl; - - } - // std::cout << "Going to insert the edge :" << u << ", " << v << std::endl; - if(!mat_1.membership(e)){ - flag_Filtration->insert_new_edges(renamedVertices.at(u),renamedVertices.at(v), filtration_value); - // std::cout << "Inserted the edge :" << renamedVertices.at(u) << ","<< renamedVertices.at(v) << " in the new distance matrix"<< std::endl; - - // myfile << filtration_value << " i"; - // myfile << " " << renamedVertices.at(u) << ", " << renamedVertices.at(v); - // myfile << std::endl; - // std::cout << "Going to insert the edge :" << u << ","<< v << " in the old skeleton"<< std::endl; - mat_1.insert_new_edges(u,v,1); - // std::cout << "Inserted the edge :" << u << ","<< v << " in the old skeleton"<< std::endl; - } - // std::cout << " Insertion Done " << std::endl; - } - - // myfile << "# Tower updated for the additional subcomplex.\n"; - myfile.close(); - } - else { - std::cerr << "Unable to open file"; - exit(-1) ; - } - - auto end_print = std::chrono::high_resolution_clock::now(); - auto printTime = std::chrono::duration(end_print- begin_print).count(); - // std::cout << " Time to print the tower : " << printTime << " ms\n" << std::endl; - return printTime; - } - Distance_matrix distance_matrix() - { - size_t non_zero_rw = flag_Filtration->num_vertices(); - double inf = std::numeric_limits::max(); - sparseRowMatrix mat = flag_Filtration->uncollapsed_matrix(); - doubleVector distances ; - for(size_t indx = 0; indx < non_zero_rw; indx++){ - rowInnerIterator it(mat, indx); - for(size_t j = 0; j <= indx; j++) { // Iterate over the non-zero columns - //std::cout << "j = " << j << " - it.index = " << it.index() << " - indx = " << indx << std::endl; - if(it.index() == j && j != indx){ - distances.push_back(it.value()); // inner index, here it is equal to it.columns() - ++it; - } - else if( j == indx) - distances.push_back(0); - else - distances.push_back(inf); - - } - distance_mat->push_back(distances); - distances.clear(); - } - return *distance_mat; - } - void print_sparse_matrix(){ - flag_Filtration->print_sparse_skeleton(); - } - -}; -- cgit v1.2.3 From 00709233ad05a22597295ab819df2ee6394ad0b2 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 18 Mar 2020 22:39:58 +0100 Subject: Remove some strong collapse useless parameters and variables for edge collapse --- src/Collapse/example/rips_persistence_with_sc.cpp | 67 +++-------------------- src/Collapse/include/gudhi/PointSetGen.h | 6 +- 2 files changed, 8 insertions(+), 65 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index 65b886f7..ed978daa 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -87,7 +88,6 @@ int main(int argc, char * const argv[]) { typedef std::vector< std::tuple > Filtered_sorted_edge_list; int dimension; - double begin_thresold; double end_threshold; double steps; int repetetions = 1; @@ -98,16 +98,14 @@ int main(int argc, char * const argv[]) { std::string manifold_full = "sphere"; - double radius = 1; double r_min = 0.6; - double r_max = 1; int dim_max = 2; - point_generator.program_options(argc, argv, number_of_points, begin_thresold, steps, end_threshold, repetetions, manifold, dimension, dim_max, in_file_name, out_file_name); + point_generator.program_options(argc, argv, number_of_points, steps, end_threshold, repetetions, manifold, dimension, dim_max, in_file_name, out_file_name); std::cout << "The current input values to run the program is: "<< std::endl; - std::cout << "number_of_points, begin_thresold, steps, end_threshold, repetetions, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; - std::cout << number_of_points << ", " << begin_thresold << ", " << steps << ", " << end_threshold << ", " << repetetions << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; + std::cout << "number_of_points, steps, end_threshold, repetetions, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; + std::cout << number_of_points << ", " << steps << ", " << end_threshold << ", " << repetetions << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; if(manifold == 'f' || manifold =='F') { Gudhi::Points_off_reader off_reader(in_file_name); @@ -123,60 +121,25 @@ int main(int argc, char * const argv[]) { } Map map_empty; - - std::string origFile ("./PersistenceOutput/original_tower_rips" ); - std::string collFile ("./PersistenceOutput/collapsed_tower_rips") ; - std::string filediag_bfr ("./PersistenceOutput/uncollapsed_persistence_diags") ; std::string filediag_aft ("./PersistenceOutput/collapsed_persistence_diags") ; std::string origPoints ("./PersistenceOutput/pointsamaple.off"); // std::string otherStats ("./PersistenceOutput/maximal_simplx_cnt"); // otherStats = otherStats+"_"+ out_file_name+ ".txt"; - filediag_bfr = filediag_bfr+"_"+ out_file_name+ ".txt"; filediag_aft = filediag_aft+"_"+ out_file_name+ ".txt"; double currentCreationTime = 0.0; - double maxCreationTime = 0.0; - point_vector = new Vector_of_points(); Distance_matrix distances; Distance_matrix *sparse_distances = new Distance_matrix(); - if(manifold == 's' || manifold == 'S'){ - // point_generator.generate_points_sphere(*point_vector, number_of_points, dimension, radius); - point_generator.generate_grid_2sphere(*point_vector, number_of_points, radius); - origFile = origFile+"_sphere_"+out_file_name+".txt"; - collFile = collFile+"_sphere_"+out_file_name+".txt"; - std::cout << number_of_points << " points successfully chosen randomly from "<< dimension <<"-sphere of radius " << radius << std::endl; - } - else if(manifold == 'b' || manifold == 'B'){ - point_generator.generate_points_ball(*point_vector, number_of_points, dimension, radius); - origFile = origFile+"_ball_"+out_file_name+".txt"; - collFile = collFile+"_ball_"+out_file_name+".txt"; - std::cout << number_of_points << " points successfully chosen randomly from "<< dimension <<"-ball of radius " << radius << std::endl; - - } - else if( (manifold == 'a' || manifold == 'A')&& dimension == 2){ - point_generator.generate_points_2annulus(*point_vector, number_of_points, r_min, r_max); - origFile = origFile+"_annulus_"+out_file_name+".txt"; - collFile = collFile+"_annulus_"+out_file_name+".txt"; - std::cout << number_of_points << " points successfully chosen randomly from "<< 2 <<"-annulus of radii (" << r_min << ',' << r_max << ") " << std::endl; - } - else if( (manifold == 'a' || manifold == 'A') && dimension == 3){ - point_generator.generate_points_spherical_shell(*point_vector, number_of_points, r_min, r_max); - origFile = origFile+"_annulus_"+out_file_name+".txt"; - collFile = collFile+"_annulus_"+out_file_name+".txt"; - std::cout << number_of_points << " points successfully chosen randomly from spherical shell of radii (" << r_min << ',' << r_max << ") " << std::endl; - } - - else if(manifold == 'f' || manifold =='f') { + if(manifold == 'f' || manifold =='f') { // Subsampling from all points for each iterations Gudhi::subsampling::pick_n_random_points(file_all_points, number_of_points, std::back_inserter(*point_vector)); - origFile = origFile+"_"+ out_file_name+ ".txt"; - collFile = collFile+"_"+ out_file_name+ ".txt"; + number_of_points = point_vector->size(); std::cout << number_of_points << " points succesfully chosen randomly of dimension "<< dimension << " ." << std::endl; } else if (manifold == 'm'){ @@ -184,16 +147,12 @@ int main(int argc, char * const argv[]) { distances = Gudhi::read_lower_triangular_matrix_from_csv_file(csv_file_name); number_of_points = distances.size(); std::cout << "Read the distance matrix succesfully, of size: " << number_of_points << std::endl; - origFile = origFile+"_"+ out_file_name+ ".txt"; - collFile = collFile+"_"+ out_file_name+ ".txt"; } else { std::cerr << "Wrong parameters for input manifold..." <size(); std::cout << "Point Set Generated." <(end_full_cmplx - begin_full_cmplx).count(); - maxCreationTime = currentCreationTime; - // Rips_complex rips_complex_before_collapse(distances, end_threshold); Rips_complex rips_complex_after_collapse(*sparse_distances, end_threshold); @@ -276,16 +233,6 @@ int main(int argc, char * const argv[]) { // pcoh_bfr.compute_persistent_cohomology(steps); pcoh_aft.compute_persistent_cohomology(steps); - // Output the diagram in filediag - // if (filediag_bfr.empty()) { - // pcoh_bfr.output_diagram(); - // } - // else { - // std::ofstream out(filediag_bfr); - // pcoh_bfr.output_diagram(out); - // out.close(); - // } - if (filediag_aft.empty()) { pcoh_aft.output_diagram(); } @@ -302,4 +249,4 @@ int main(int argc, char * const argv[]) { return 0; } - \ No newline at end of file + diff --git a/src/Collapse/include/gudhi/PointSetGen.h b/src/Collapse/include/gudhi/PointSetGen.h index af78b63b..a7d6956d 100644 --- a/src/Collapse/include/gudhi/PointSetGen.h +++ b/src/Collapse/include/gudhi/PointSetGen.h @@ -19,7 +19,6 @@ class PointSetGen { public: void program_options(int argc, char * const argv[] , std::size_t & number_of_points - , double & begin_thresold , double & steps , double & end_thresold , int & repetetions @@ -36,9 +35,6 @@ class PointSetGen { ("help,h", "produce help message") ("number,n", po::value(&number_of_points)->default_value(0), "Number of generated point_vector.") - - ("begin_thresold,b", po::value(&begin_thresold)->default_value(0), - "Initial threshold for rips complex.") ("steps,s", po::value(&steps)->default_value(0.1), "Steps of the threshold") ("end_thresold,e", po::value(&end_thresold)->default_value(1), @@ -70,7 +66,7 @@ class PointSetGen { if (vm.count("help")) { std::cout << std::endl; - std::cout << "Computes rips complexes of different threshold values, from 'begin_thresold' to 'end_thresold', with priodic steps of 'steps' from a n random uniform point_vector on a selected manifold, . \n"; + std::cout << "Computes rips complexes of different threshold values, to 'end_thresold', with priodic steps of 'steps' from a n random uniform point_vector on a selected manifold, . \n"; std::cout << "Strongly collapses all the rips complexes and output the results in out_file. \n"; std::cout << "The experiments are repeted 'repete' num of times for each threshold value. \n"; std::cout << "type -m for manifold options, 's' for uni sphere, 'b' for unit ball, 'f' for file. \n"; -- cgit v1.2.3 From 3a2f852e87514edff2d6c91c0ced2f6c53b541a1 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 18 Mar 2020 23:43:17 +0100 Subject: [skip ci] some cleanups --- src/Collapse/example/rips_persistence_with_sc.cpp | 88 ++-------- src/Collapse/include/gudhi/PointSetGen.h | 193 ---------------------- 2 files changed, 13 insertions(+), 268 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index ed978daa..70f7abbb 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -18,34 +18,7 @@ using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Distance_matrix = std::vector>; -class extract_sub_one_skeleton -{ -public: - template - extract_sub_one_skeleton(double threshold, Filtered_sorted_edge_list & current_edge_t, Filtered_sorted_edge_list & edge_t, Fil_vector & edge_filt ) { - - auto end_it = std::upper_bound(edge_filt.begin(), edge_filt.end(), threshold); // find_index(edge_t, threshold, 0, end_idx); - size_t end_idx = std::distance(edge_filt.begin(), end_it); - for( size_t idx = 0; idx < end_idx ; idx++) { - current_edge_t.push_back(*edge_t.begin()); - edge_filt.erase(edge_filt.begin()); - edge_t.erase(edge_t.begin()); - } - - } -}; -class extract_one_new_edge -{ -public: - template - extract_one_new_edge(Filtered_sorted_edge_list & current_edge_t, Filtered_sorted_edge_list & edge_t, Fil_vector & edge_filt ) { - current_edge_t.push_back(*edge_t.begin()); - edge_filt.erase(edge_filt.begin()); - edge_t.erase(edge_t.begin()); - - } -}; class filt_edge_to_dist_matrix { @@ -94,53 +67,42 @@ int main(int argc, char * const argv[]) { char manifold; Vector_of_points * point_vector; - Vector_of_points file_all_points; std::string manifold_full = "sphere"; double r_min = 0.6; int dim_max = 2; - point_generator.program_options(argc, argv, number_of_points, steps, end_threshold, repetetions, manifold, dimension, dim_max, in_file_name, out_file_name); + point_generator.program_options(argc, argv, steps, end_threshold, repetetions, manifold, dimension, dim_max, in_file_name, out_file_name); std::cout << "The current input values to run the program is: "<< std::endl; - std::cout << "number_of_points, steps, end_threshold, repetetions, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; - std::cout << number_of_points << ", " << steps << ", " << end_threshold << ", " << repetetions << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; + std::cout << "steps, end_threshold, repetetions, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; + std::cout << steps << ", " << end_threshold << ", " << repetetions << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; - if(manifold == 'f' || manifold =='F') { - Gudhi::Points_off_reader off_reader(in_file_name); - if (!off_reader.is_valid()) { - std::cerr << "Unable to read file " << in_file_name << "\n"; - exit(-1); // ----- >> - } - - file_all_points = Vector_of_points(off_reader.get_point_cloud()); - dimension = file_all_points[0].dimension() ; - std::cout << "Successfully read " << file_all_points.size() << " point_vector.\n"; - std::cout << "Ambient dimension is " << dimension << ".\n"; - } - Map map_empty; std::string filediag_aft ("./PersistenceOutput/collapsed_persistence_diags") ; - std::string origPoints ("./PersistenceOutput/pointsamaple.off"); - // std::string otherStats ("./PersistenceOutput/maximal_simplx_cnt"); - // otherStats = otherStats+"_"+ out_file_name+ ".txt"; filediag_aft = filediag_aft+"_"+ out_file_name+ ".txt"; double currentCreationTime = 0.0; - point_vector = new Vector_of_points(); Distance_matrix distances; Distance_matrix *sparse_distances = new Distance_matrix(); if(manifold == 'f' || manifold =='f') { - // Subsampling from all points for each iterations - Gudhi::subsampling::pick_n_random_points(file_all_points, number_of_points, std::back_inserter(*point_vector)); + Gudhi::Points_off_reader off_reader(in_file_name); + if (!off_reader.is_valid()) { + std::cerr << "Unable to read file " << in_file_name << "\n"; + exit(-1); // ----- >> + } + + point_vector = new Vector_of_points(off_reader.get_point_cloud().begin(), off_reader.get_point_cloud().end()); + dimension = point_vector->at(0).dimension() ; number_of_points = point_vector->size(); - std::cout << number_of_points << " points succesfully chosen randomly of dimension "<< dimension << " ." << std::endl; + std::cout << "Successfully read " << number_of_points << " point_vector.\n"; + std::cout << "Ambient dimension is " << dimension << ".\n"; } else if (manifold == 'm'){ std::string csv_file_name(in_file_name); @@ -155,10 +117,6 @@ int main(int argc, char * const argv[]) { std::cout << "Point Set Generated." <at(i)); - // point_generator.output_points(*point_vector, origPoints); - Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); std::cout << "Computing the one-skeleton for threshold: " << end_threshold << std::endl; @@ -167,22 +125,12 @@ int main(int argc, char * const argv[]) { Rips_edge_list Rips_edge_list_from_file(distances, end_threshold); Rips_edge_list_from_file.create_edges(*edge_t); std::cout<< "Sorted edge list computed" << std::endl; - - //Creating the Rips Complex - //Rips_complex rips_complex_from_file(distances, end_threshold); - //rips_complex_from_file.create_complex(*subComplex, dim_max); - //std::cout<< "Rips complex computed" << std::endl; } else{ //Point cloud input //Creating the edge list Rips_edge_list Rips_edge_list_from_points(*point_vector, end_threshold, Gudhi::Euclidean_distance()); Rips_edge_list_from_points.create_edges(*edge_t); std::cout<< "Sorted edge list computed" << std::endl; std::cout << "Total number of edges before collapse are: " << edge_t->size() << std::endl; - - // Creating the Rips Complex - // Rips_complex rips_complex_after_collapse(*point_vector, end_threshold, Gudhi::Euclidean_distance()); - // rips_complex_from_points.create_complex(*subComplex, dim_max); - // std::cout<< "Rips complex computed" << std::endl; } //Now we will perform filtered edge collapse to sparsify the edge list edge_t. @@ -207,28 +155,18 @@ int main(int argc, char * const argv[]) { // Rips_complex rips_complex_before_collapse(distances, end_threshold); Rips_complex rips_complex_after_collapse(*sparse_distances, end_threshold); - // Rips_complex rips_complex_after_collapse(*point_vector, end_threshold, Gudhi::Euclidean_distance()); - // Construct the Rips complex in a Simplex Tree Simplex_tree simplex_tree_aft; - // Simplex_tree simplex_tree_bfr; - // rips_complex_before_collapse.create_complex(simplex_tree_bfr, dim_max); rips_complex_after_collapse.create_complex(simplex_tree_aft, dim_max); - // std::cout << "The complex contains " << simplex_tree_bfr.num_simplices() << " simplices before collapse. \n"; - // std::cout << " and has dimension " << simplex_tree_bfr.dimension() << " \n"; - std::cout << "The complex contains " << simplex_tree_aft.num_simplices() << " simplices after collapse. \n"; std::cout << " and has dimension " << simplex_tree_aft.dimension() << " \n"; // Sort the simplices in the order of the filtration - // simplex_tree_bfr.initialize_filtration(); simplex_tree_aft.initialize_filtration(); // Compute the persistence diagram of the complex - // Persistent_cohomology pcoh_bfr(simplex_tree_bfr); Persistent_cohomology pcoh_aft(simplex_tree_aft); // initializes the coefficient field for homology - // pcoh_bfr.init_coefficients(2); pcoh_aft.init_coefficients(2); // pcoh_bfr.compute_persistent_cohomology(steps); diff --git a/src/Collapse/include/gudhi/PointSetGen.h b/src/Collapse/include/gudhi/PointSetGen.h index a7d6956d..be83090b 100644 --- a/src/Collapse/include/gudhi/PointSetGen.h +++ b/src/Collapse/include/gudhi/PointSetGen.h @@ -14,11 +14,8 @@ const double PI = 3.141592653589793238463; #define _USE_MATH_DEFINES class PointSetGen { - private: - double unirand(){return (double) rand()/(double) RAND_MAX;} public: void program_options(int argc, char * const argv[] - , std::size_t & number_of_points , double & steps , double & end_thresold , int & repetetions @@ -33,8 +30,6 @@ class PointSetGen { po::options_description visible("Allowed options", 100); visible.add_options() ("help,h", "produce help message") - ("number,n", po::value(&number_of_points)->default_value(0), - "Number of generated point_vector.") ("steps,s", po::value(&steps)->default_value(0.1), "Steps of the threshold") ("end_thresold,e", po::value(&end_thresold)->default_value(1), @@ -78,192 +73,4 @@ class PointSetGen { std::abort(); } } - - - void generate_points_sphere(Vector_of_points& W, int nbP, int dim, double radius) { - CGAL::Random_points_on_sphere_d rp(dim+1, radius); - for (int i = 0; i < nbP; i++) - W.push_back(*rp++); - } - // void generate_fibonaci_grid_sphere(Vector_of_points& W, int nbP, int dim, double radius) - // { - - // } - - void generate_grid_2sphere(Vector_of_points& W, int nbP, int r ) - { - std::vector coords; - int Ncount = 0; - double p,v; //the angles phi and psi - int M_p; - - double a = (4*PI*pow(r,2))/nbP; - double d = sqrt(a); - - int M_v = PI/d; - - double d_v = PI/M_v; - double d_p = a/d_v; - - for( int m = 0; m < M_v ; m++) { - v = (PI*(m + 0.5))/M_v; - M_p = ((2*PI*sin(v))/d_p); - for(int n = 0; n < M_p ; n++) { - p = (2*PI*n)/M_p; - coords = {r*sin(v)*cos(p), r*sin(v)*sin(p), r*cos(v)}; - W.push_back(Point(coords)); - Ncount += 1; - } - } - } - - - /* - Generates point sets on spheres wedged at origin, sphere can have different radii from with steps of - Number of points on the sphere can also be different from for the smallest sphere and then multiplied by - */ - void generate_points_wedged_sphere(Vector_of_points& W, int init_nbP, int dim, double init_radius, int multiplier_step, int nbSpheres) { - double radius = init_radius; - int nbP = init_nbP; - std::vector translation; - for(int d = 0; d< dim; d++) { - translation.push_back(0); - } - for(int s = 0; s < nbSpheres; s++) { - CGAL::Random_points_on_sphere_d rp(dim+1, radius); - for (int i = 0; i < nbP; i++) { - W.push_back(add_point(*rp++, translation, dim)); - } - nbP = nbP*multiplier_step; - radius = radius*multiplier_step; - translation.at(dim-1) = (radius - init_radius); - } - } - - void generate_points_concentric_sphere(Vector_of_points& W, int init_nbP, int dim, int init_radius, int multiplier_step, int nbSpheres) { - double radius = init_radius; - int nbP = init_nbP; - - for(int s = 0; s < nbSpheres; s++) { - CGAL::Random_points_on_sphere_d rp(dim+1, radius); - for (int i = 0; i < nbP; i++) { - W.push_back(*rp++); - } - nbP = nbP*(pow(multiplier_step,2)); - radius = radius*multiplier_step; - } - - } - void generate_points_2annulus(Vector_of_points& W, int nbP, double r_min, double r_max) { - double rho, theta; - double x, y; - std::vector coords; - double r_min_sq = pow(r_min,2); - double r_max_sq = pow(r_max,2); - - srand(time(NULL)); - for (int i=0; i coords; - double r_min_cube = pow(r_min,3); - double r_max_cube = pow(r_max,3); - - srand(time(NULL)); - for (int i=0; i rp(dim, radius); - for (int i = 0; i < nbP; i++) - W.push_back(*rp++); - } - - void generate_points_cube(Vector_of_points& W, int nbP, int dim) { - CGAL::Random_points_in_cube_d rp(dim, 6); - for (int i = 0; i < nbP; i++) - W.push_back(*rp++); - } - - void add_point_vectors(Vector_of_points& V, Vector_of_points& U, int nbP, int dim) { // Adds two point vectors of the same size (nbP), by Modifying the first one, V = V+W. - for (int i = 0; i < nbP; i++) - { - V[i] = add_point(V[i], U[i], dim); - } - } - - //returns x = x+y; - Point add_point(const Point & x, const Point & y, int dim) { - std::vector coords; - for(int i =0; i< dim; i++) - coords.push_back(x[i]+y[i]); - return Point(coords); - } - void print_point(const Point & x) { - std::cout<< "("; - for(auto & p : x){ - std::cout<< p << ", " ; - } - std::cout<< ")" << std::endl; - } - void output_points(Vector_of_points & W, std::string outFile) { - std::ofstream myfile (outFile, std::ios::app); - if (myfile.is_open()) { - myfile << "OFF" << " " << W.size() << " " << W.at(0).size() << std::endl; - for(auto & v : W){ - for(auto & x : v){ - myfile<< x << " " ; - } - myfile << std::endl; - } - myfile << "# Tower updated for the additional subcomplex.\n"; - myfile.close(); - } - else { - std::cerr << "Unable to open file"; - exit(-1) ; - } - } - - Point noise_point(double noise_param, int dim, double radius) { - std::vector noise; - for(int d = 0; d< dim; d++){ - if(d % 2) - noise.push_back(-noise_param*radius); - else - noise.push_back(noise_param*radius); - } - return Point(noise); - } - //add noise to the points in W. - void add_noise(Vector_of_points& W, int nbP, int dim, double radius, double noise_param) { - Point noise = noise_point(noise_param, dim, radius); - for(Vector_of_points::iterator it = W.begin(); it != W.end(); it++ ) { - *it = add_point(*it,noise,dim); - } - } - - PointSetGen(){} - ~PointSetGen(){} }; \ No newline at end of file -- cgit v1.2.3 From c8ae4d46d42340140d8687994f322d288e47a3bb Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 18 Mar 2020 23:57:39 +0100 Subject: some cleanups --- src/Collapse/example/rips_persistence_with_sc.cpp | 14 +++----------- src/Collapse/include/gudhi/PointSetGen.h | 7 ------- 2 files changed, 3 insertions(+), 18 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index 70f7abbb..a462dcea 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -63,21 +63,17 @@ int main(int argc, char * const argv[]) { int dimension; double end_threshold; double steps; - int repetetions = 1; char manifold; Vector_of_points * point_vector; - - std::string manifold_full = "sphere"; - double r_min = 0.6; int dim_max = 2; - point_generator.program_options(argc, argv, steps, end_threshold, repetetions, manifold, dimension, dim_max, in_file_name, out_file_name); + point_generator.program_options(argc, argv, steps, end_threshold, manifold, dimension, dim_max, in_file_name, out_file_name); std::cout << "The current input values to run the program is: "<< std::endl; - std::cout << "steps, end_threshold, repetetions, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; - std::cout << steps << ", " << end_threshold << ", " << repetetions << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; + std::cout << "steps, end_threshold, manifold, dimension, max_complex_dimension, in_file_name, out_file_name" << std::endl; + std::cout << steps << ", " << end_threshold << ", " << manifold << ", " << dimension << ", " << dim_max << ", " << in_file_name << ", " << out_file_name << std::endl; Map map_empty; @@ -120,7 +116,6 @@ int main(int argc, char * const argv[]) { Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); std::cout << "Computing the one-skeleton for threshold: " << end_threshold << std::endl; - auto begin_full_cmplx = std::chrono::high_resolution_clock::now(); if(manifold == 'm') { //Input is a distance 'm'atrix //Creating the edge list Rips_edge_list Rips_edge_list_from_file(distances, end_threshold); Rips_edge_list_from_file.create_edges(*edge_t); @@ -149,9 +144,6 @@ int main(int argc, char * const argv[]) { std::cerr << "Total number of egdes are zero." <(end_full_cmplx - begin_full_cmplx).count(); // Rips_complex rips_complex_before_collapse(distances, end_threshold); Rips_complex rips_complex_after_collapse(*sparse_distances, end_threshold); diff --git a/src/Collapse/include/gudhi/PointSetGen.h b/src/Collapse/include/gudhi/PointSetGen.h index be83090b..45e9fbba 100644 --- a/src/Collapse/include/gudhi/PointSetGen.h +++ b/src/Collapse/include/gudhi/PointSetGen.h @@ -10,15 +10,11 @@ using Point = CGAL::Epick_d< CGAL::Dynamic_dimension_tag>::Point_d; using Vector_of_points = std::vector; -const double PI = 3.141592653589793238463; -#define _USE_MATH_DEFINES - class PointSetGen { public: void program_options(int argc, char * const argv[] , double & steps , double & end_thresold - , int & repetetions , char & manifold , int & dimension , int & dim_max @@ -34,9 +30,6 @@ class PointSetGen { "Steps of the threshold") ("end_thresold,e", po::value(&end_thresold)->default_value(1), "Final threshold for rips complex.") - - ("repetetions,r", po::value(&repetetions)->default_value(1), - "Num of repetetions of the experiments.") ("manifold,m", po::value(&manifold)->default_value('s'), "Type of manifold") -- cgit v1.2.3 From 1142403db4ba255e0f5c9f8082a158780df51148 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 19 Mar 2020 07:47:18 +0100 Subject: some cleanups --- src/Collapse/example/rips_persistence_with_sc.cpp | 5 +-- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 45 +---------------------- 2 files changed, 4 insertions(+), 46 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index a462dcea..f16588cf 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -9,7 +9,6 @@ // Types definition using Vector_of_points = std::vector; -using Vector_of_SM_pointers = std::vector; using Simplex_tree = Gudhi::Simplex_tree; using Filtration_value = double; @@ -130,12 +129,12 @@ int main(int argc, char * const argv[]) { //Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout<< "Filtered edge collapse begins" << std::endl; - FlagComplexSpMatrix * mat_filt_edge_coll = new FlagComplexSpMatrix(number_of_points,*edge_t,true); + FlagComplexSpMatrix * mat_filt_edge_coll = new FlagComplexSpMatrix(number_of_points,*edge_t); std::cout<< "Matrix instansiated" << std::endl; if(edge_t->size() >0){ delete edge_t; edge_t = new Filtered_sorted_edge_list(); - *edge_t = mat_filt_edge_coll->filtered_edge_collapse(0); + *edge_t = mat_filt_edge_coll->filtered_edge_collapse(); filt_edge_to_dist_matrix(*sparse_distances, *edge_t, number_of_points); std::cout << "Total number of vertices after collapse in the sparse matrix are: " << mat_filt_edge_coll->num_vertices() << std::endl; } diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index d3e58d4f..7d6d6d22 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -217,7 +217,6 @@ class FlagComplexSpMatrix bool vertexCollapsed; bool edgeCollapsed; //Variable to indicate if filtered-edge-collapse has to be performed. - bool filtEdgeCol; int expansion_limit; void init() @@ -244,7 +243,6 @@ class FlagComplexSpMatrix vertexCollapsed = false; edgeCollapsed = false; - filtEdgeCol = false; } //! Function for computing the sparse-matrix corresponding to the core of the complex. It also prepares the working list filteredEgdeIter for edge collapses @@ -633,26 +631,8 @@ public: rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. vertDomnIndicator, rowInsertIndicator ,rowIterator are initialised by init() function which is called at the begining of this.
*/ - //Filtered_sorted_edge_list * edge_t = new Filtered_sorted_edge_list(); - FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list &edge_t) { - init(); - - filtEdgeCol = false; - sparseRowAdjMatrix = sparseRowMatrix(expansion_limit*num_vertices, expansion_limit*num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - - for(size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; - insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); - } - sparseRowAdjMatrix.makeCompressed(); - - // std::cout << sparseRowAdjMatrix << std::endl; - } - FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list & edge_t, const bool fEdgeCol) { - if(fEdgeCol) - { + FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list & edge_t) { init(); - filtEdgeCol = true; sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. for(size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { @@ -662,11 +642,6 @@ public: } // sparseRowAdjMatrix.makeCompressed(); - } - else - FlagComplexSpMatrix(num_vertices, edge_t); - - // std::cout << sparseRowAdjMatrix << std::endl; } //! Destructor. @@ -697,25 +672,9 @@ public: after_vertex_collapse(); return collapseTime; } - - // Performs edge collapse in of a given sparse-matrix(graph) without considering the filtration value. - // double strong_edge_collapse() { - // auto begin_collapse = std::chrono::high_resolution_clock::now(); - // critical_core_edges(); - // vertexCollapsed = false; - // edgeCollapsed = true; - // auto end_collapse = std::chrono::high_resolution_clock::now(); - - // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); - // // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; - // //Post processing... - // after_edge_collapse(); - // return collapseTime; - // } - // Performs edge collapse in a decreasing sequence of the filtration value. - Filtered_sorted_edge_list filtered_edge_collapse(double steps) { + Filtered_sorted_edge_list filtered_edge_collapse() { auto begin_collapse = std::chrono::high_resolution_clock::now(); critical_core_edges(); vertexCollapsed = false; -- cgit v1.2.3 From 4010a8da315d500e023d8a1f5b70a9eab3da629c Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 19 Mar 2020 08:05:30 +0100 Subject: some cleanups --- src/Collapse/example/rips_persistence_with_sc.cpp | 6 ++---- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 23 +++++------------------ 2 files changed, 7 insertions(+), 22 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/rips_persistence_with_sc.cpp b/src/Collapse/example/rips_persistence_with_sc.cpp index f16588cf..46ec8eca 100644 --- a/src/Collapse/example/rips_persistence_with_sc.cpp +++ b/src/Collapse/example/rips_persistence_with_sc.cpp @@ -29,7 +29,7 @@ public: doubleVector distances ; std::pair e; for(std::size_t indx = 0; indx < number_of_points; indx++) { - for (int j = 0; j <= indx; j++) { + for (std::size_t j = 0; j <= indx; j++) { if( j == indx) distances.push_back(0); @@ -80,13 +80,11 @@ int main(int argc, char * const argv[]) { filediag_aft = filediag_aft+"_"+ out_file_name+ ".txt"; - double currentCreationTime = 0.0; - Distance_matrix distances; Distance_matrix *sparse_distances = new Distance_matrix(); - if(manifold == 'f' || manifold =='f') { + if(manifold == 'f') { Gudhi::Points_off_reader off_reader(in_file_name); if (!off_reader.is_valid()) { std::cerr << "Unable to read file " << in_file_name << "\n"; diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index 7d6d6d22..a1174084 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -250,10 +250,10 @@ class FlagComplexSpMatrix { sparse_colpsd_adj_Matrix = new sparseRowMatrix(rows,rows); // Just for debugging purpose. oneSimplices.clear(); - if(not filteredEgdeIter.empty()) + if(not filteredEgdeIter.empty()) { std::cout << "Working list for edge collapses are not empty before the edge-collapse." << std::endl; - - for(int rw = 0 ; rw < rows ; ++rw) + } + for(std::size_t rw = 0 ; rw < rows ; ++rw) { if(not vertDomnIndicator[rw]) //If the current column is not dominated { @@ -468,8 +468,6 @@ class FlagComplexSpMatrix EdgeFilt fec = fEgdeVector.at(endIdx); insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)),std::get<1>(fec)); // Inserts the edge in the sparse matrix to update the graph (G_i) - // cfiltVal = std::get<1>(fEgdeVector.at(endIdx)); - // std::cout << "The current processing index is " << endIdx << std::endl; Edge e = std::get<0>(fec); Vertex u = std::get<0>(e); @@ -675,21 +673,9 @@ public: // Performs edge collapse in a decreasing sequence of the filtration value. Filtered_sorted_edge_list filtered_edge_collapse() { - auto begin_collapse = std::chrono::high_resolution_clock::now(); critical_core_edges(); vertexCollapsed = false; edgeCollapsed = true; - auto end_collapse = std::chrono::high_resolution_clock::now(); - - auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); - std::cout << "Time of filtered edge Collapse : " << collapseTime << " ms\n" << std::endl; - //Post processing... - // after_edge_collapse(); - // std::cout << sparseRowAdjMatrix << std::endl; - // for(auto idx = criticalCoreEdges.begin(); idx != criticalCoreEdges.end(); idx++ ) - // { - // std::cout << - // } return criticalCoreEdges; } @@ -805,8 +791,9 @@ public: vertexVector active_neighbors(const Vertex & v) { vertexVector nb; auto rw_v = vertexToRow.find(v); - if(rw_v != vertexToRow.end()) + if(rw_v != vertexToRow.end()) { nb = vertex_closed_active_neighbours(rw_v->second); + } return nb; } -- cgit v1.2.3 From 2e20a1eb3156f7ea10ac19eb400f78ac55a1cb80 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 19 Mar 2020 10:20:51 +0100 Subject: Remove PointSetGen --- src/Collapse/include/gudhi/PointSetGen.h | 69 -------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 src/Collapse/include/gudhi/PointSetGen.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/PointSetGen.h b/src/Collapse/include/gudhi/PointSetGen.h deleted file mode 100644 index 45e9fbba..00000000 --- a/src/Collapse/include/gudhi/PointSetGen.h +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -#include -#include -#include - -#include - -using Point = CGAL::Epick_d< CGAL::Dynamic_dimension_tag>::Point_d; -using Vector_of_points = std::vector; - -class PointSetGen { - public: - void program_options(int argc, char * const argv[] - , double & steps - , double & end_thresold - , char & manifold - , int & dimension - , int & dim_max - , std::string & in_file_name - , std::string & out_file_name - ) { - namespace po = boost::program_options; - - po::options_description visible("Allowed options", 100); - visible.add_options() - ("help,h", "produce help message") - ("steps,s", po::value(&steps)->default_value(0.1), - "Steps of the threshold") - ("end_thresold,e", po::value(&end_thresold)->default_value(1), - "Final threshold for rips complex.") - ("manifold,m", po::value(&manifold)->default_value('s'), - "Type of manifold") - - ("dimensions,D", po::value(&dimension)->default_value(2), - "Dimension of the manifold.") - - ("dim_max,k ", po::value(&dim_max)->default_value(2), - "Maximum allowed dimension of the Rips complex.") - - ("input_file_name,i", po::value(&in_file_name), - "The input file.") - ("out_file_name,o", po::value(&out_file_name), - "The output file."); - - po::options_description all; - all.add(visible); - - po::variables_map vm; - po::store(po::command_line_parser(argc, argv). - options(all).run(), vm); - po::notify(vm); - - if (vm.count("help")) { - std::cout << std::endl; - std::cout << "Computes rips complexes of different threshold values, to 'end_thresold', with priodic steps of 'steps' from a n random uniform point_vector on a selected manifold, . \n"; - std::cout << "Strongly collapses all the rips complexes and output the results in out_file. \n"; - std::cout << "The experiments are repeted 'repete' num of times for each threshold value. \n"; - std::cout << "type -m for manifold options, 's' for uni sphere, 'b' for unit ball, 'f' for file. \n"; - std::cout << "type -i 'filename' for Input file option for exported point sample. \n"; - std::cout << std::endl << std::endl; - - std::cout << "Usage: " << argv[0] << " [options]" << std::endl << std::endl; - std::cout << visible << std::endl; - std::abort(); - } - } -}; \ No newline at end of file -- cgit v1.2.3 From 726329e4df9eb085da353ae25a949cbc7f66f00f Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 24 Mar 2020 11:01:01 +0100 Subject: clang format and remove useless variables and types --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 1627 +++++++++++----------- 1 file changed, 785 insertions(+), 842 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index a1174084..ac02a46f 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -2,7 +2,7 @@ * (Geometric Understanding in Higher Dimensions) is a generic C++ * library for computational topology. * - * Author(s): Siddharth Pritam + * Author(s): Siddharth Pritam * * Copyright (C) 2018 INRIA Sophia Antipolis (France) * @@ -26,7 +26,6 @@ #include // #include - #include #include #include @@ -42,868 +41,812 @@ #include - typedef std::size_t Vertex; -using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables -using EdgeFilt = std::pair; -using edge_list = std::vector; +using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first + // element being the smaller i.e {2,3} not {3,2}. However this is at the level + // of row indices on actual vertex lables +using EdgeFilt = std::pair; +using edge_list = std::vector; -using MapVertexToIndex = std::unordered_map; -using Map = std::unordered_map; +using MapVertexToIndex = std::unordered_map; +using Map = std::unordered_map; -using sparseRowMatrix = Eigen::SparseMatrix ; -using rowInnerIterator = sparseRowMatrix::InnerIterator; +using sparseRowMatrix = Eigen::SparseMatrix; +using rowInnerIterator = sparseRowMatrix::InnerIterator; -using intVector = std::vector; -using doubleVector = std::vector; -using vertexVector = std::vector; -using boolVector = std::vector; +using doubleVector = std::vector; +using vertexVector = std::vector; +using boolVector = std::vector; -using doubleQueue = std::queue; -using edgeQueue = std::queue; +using doubleQueue = std::queue; -using EdgeFiltQueue = std::queue; -using EdgeFiltVector = std::vector; +using EdgeFiltQueue = std::queue; +using EdgeFiltVector = std::vector; -typedef std::vector< std::tuple< double, Vertex, Vertex > > Filtered_sorted_edge_list; -typedef std::unordered_map > u_edge_map; -typedef std::unordered_map > u_edge_to_idx_map; +typedef std::vector> Filtered_sorted_edge_list; +typedef std::unordered_map> u_edge_map; +typedef std::unordered_map> u_edge_to_idx_map; - -//! Class SparseMsMatrix +//! Class SparseMsMatrix /*! - The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() Algorithm. + The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() + Algorithm. */ -class FlagComplexSpMatrix -{ - private: - - std::unordered_map rowToVertex; +class FlagComplexSpMatrix { + private: + std::unordered_map rowToVertex; - // Vertices strored as an unordered_set - std::unordered_set vertices; + // Vertices strored as an unordered_set + std::unordered_set vertices; //! Stores the 1-simplices(edges) of the original Simplicial Complex. - edge_list oneSimplices; - - //Unordered set of removed edges. (to enforce removal from the matrix) - std::unordered_set> u_set_removed_redges; - - //Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_redges; - - - //Map from egde to its index - u_edge_to_idx_map edge_to_index_map; - //Boolean vector to indicate if the index is critical or not. - boolVector critical_edge_indicator; // critical indicator - - //Boolean vector to indicate if the index is critical or not. - boolVector dominated_edge_indicator; // domination indicator - - //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. - /*! - \code - MapVertexToIndex = std::unordered_map - \endcode - So, if the original simplex tree had vertices 0,1,4,5
- rowToVertex would store :
- \verbatim - Values = | 0 | 1 | 4 | 5 | - Indices = 0 1 2 3 - \endverbatim - And vertexToRow would be a map like the following :
- \verbatim - 0 -> 0 - 1 -> 1 - 4 -> 2 - 5 -> 3 - \endverbatim - */ - MapVertexToIndex vertexToRow; - - //! Stores the number of vertices in the original Simplicial Complex. - /*! - This stores the count of vertices (which is also the number of rows in the Matrix). - */ - std::size_t rows; - - std::size_t numOneSimplices; - - std::size_t numDomEdge; - - //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. - /*! - \code - sparseRowMatrix = Eigen::SparseMatrix ; - \endcode - ; - */ - - sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. - sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access to elements when traversing the matrix row-wise. - - - - //! Stores true for dominated rows and false for undominated rows. - /*! - Initialised to a vector of length equal to the value of the variable rows with all false values. - Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. - */ - boolVector vertDomnIndicator; //(domination indicator) - - - boolVector activeIndicator; // active indicator - boolVector contractionIndicator; //(contraction indicator) - - //! Stores the indices of the rows to-be checked for domination in the current iteration. - /*! - Initialised with all rows for the first iteration. - Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. - */ - //doubleQueue rowIterator; - - doubleQueue rowIterator; - - //! Stores the indices-pair of the edges to-be checked for domination in the current iteration. - /*! - Initialised with all egdes for the first iteration. - Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. // To be clarified. - */ - //doubleQueue rowIterator; - - // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltQueue filteredEgdeIter; - - // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltVector fEgdeVector; - - // List of non-dominated edges, the indices of the edges are the vertex lables!!. - Filtered_sorted_edge_list criticalCoreEdges; - // Stores the indices from the sorted filtered edge vector. - // std::set recurCriticalCoreIndcs; - - - //! Stores true if the current row is inserted in the queue rowIterator otherwise its value is false. - /*! - Initialised to a boolean vector of length equal to the value of the variable rows with all true values. - Subsequent removal/addition of a row from rowIterator is reflected by concerned entries changing to false/true in this vector. - */ - boolVector rowInsertIndicator; //(current iteration row insertion indicator) - - - //! Map that stores the current status of the edges after the vertex-collapse has been performed. . - /*! - \code - u_edge_map = std::unordered_map - \endcode - The values an edge can take are true, false; - true -> Inserted in filteredEgdeIter; - false -> Not inserted in filteredEgdeIter; - */ - u_edge_map edgeStatusMap; - - //! Map that stores the Reduction / Collapse of vertices. - /*! - \code - Map = std::unordered_map - \endcode - This is empty to begin with. As and when collapses are done (let's say from dominated vertex v to dominating vertex v') :
- ReductionMap[v] = v' is entered into the map.
- This does not store uncollapsed vertices. What it means is that say vertex x was never collapsed onto any other vertex. Then, this map WILL NOT have any entry like x -> x. - Basically, it will have no entry corresponding to vertex x at all. - */ - Map ReductionMap; - - bool vertexCollapsed; - bool edgeCollapsed; - //Variable to indicate if filtered-edge-collapse has to be performed. - int expansion_limit; - - void init() - { - rowToVertex.clear(); - vertexToRow.clear(); - oneSimplices.clear(); - ReductionMap.clear(); - - vertDomnIndicator.clear(); - rowInsertIndicator.clear(); - rowIterator.push(0); - rowIterator.pop(); - - filteredEgdeIter.push({{0,0},0}); - filteredEgdeIter.pop(); - fEgdeVector.clear(); - - rows = 0; - numDomEdge = 0; - - numOneSimplices = 0; - expansion_limit = 2; - - vertexCollapsed = false; - edgeCollapsed = false; - } - - //! Function for computing the sparse-matrix corresponding to the core of the complex. It also prepares the working list filteredEgdeIter for edge collapses - void after_vertex_collapse() - { - sparse_colpsd_adj_Matrix = new sparseRowMatrix(rows,rows); // Just for debugging purpose. - oneSimplices.clear(); - if(not filteredEgdeIter.empty()) { - std::cout << "Working list for edge collapses are not empty before the edge-collapse." << std::endl; - } - for(std::size_t rw = 0 ; rw < rows ; ++rw) - { - if(not vertDomnIndicator[rw]) //If the current column is not dominated - { - auto nbhrs_to_insert = closed_neighbours_row_index(rw); // returns row indices of the non-dominated vertices. - for(auto & v: nbhrs_to_insert) { - sparse_colpsd_adj_Matrix->insert(rw, v) = 1; // This creates the full matrix - if(rw < v) { - oneSimplices.push_back({rowToVertex[rw],rowToVertex[v]}); - filteredEgdeIter.push({{rw,v},1}) ; - // if(rw == v) - // std::cout << "Pushed the edge {" << rw << ", " << v << "} " << std::endl; - edgeStatusMap[{rw,v}] = true; - } - } - } - } - // std::cout << "Total number of non-zero elements before domination check are: " << sparse_colpsd_adj_Matrix->nonZeros() << std::endl; - // std::cout << "Total number of edges for domination check are: " << filteredEgdeIter.size() << std::endl; - // std::cout << *sparse_colpsd_adj_Matrix << std::endl; - return ; - } - - //! Function to fully compact a particular vertex of the ReductionMap. - /*! - It takes as argument the iterator corresponding to a particular vertex pair (key-value) stored in the ReductionMap.
- It then checks if the second element of this particular vertex pair is present as a first element of some other key-value pair in the map. - If no, then the first element of the vertex pair in consideration is fully compact. - If yes, then recursively call fully_compact_this_vertex() on the second element of the original pair in consideration and assign its resultant image as the image of the first element of the original pair in consideration as well. - */ - void fully_compact_this_vertex(Map::iterator iter) - { - Map::iterator found = ReductionMap.find(iter->second); - if ( found == ReductionMap.end() ) - return; - - fully_compact_this_vertex(found); - iter->second = ReductionMap[iter->second]; - } - - //! Function to fully compact the Reduction Map. - /*! - While doing strong collapses, we store only the immediate collapse of a vertex. Which means that in one round, vertex x may collapse to vertex y. - And in some later round it may be possible that vertex y collapses to z. In which case our map stores :
- x -> y and also y -> z. But it really should store : - x -> z and y -> z. This function achieves the same.
- It basically calls fully_compact_this_vertex() for each entry in the map. - */ - void fully_compact() - { - Map::iterator it = ReductionMap.begin(); - while(it != ReductionMap.end()) - { - fully_compact_this_vertex(it); - it++; - } - } - - void sparse_strong_vertex_collapse() - { - complete_vertex_domination_check(rowIterator, rowInsertIndicator, vertDomnIndicator); // Complete check for rows in rowIterator, rowInsertIndicator is a list of boolean indicator if a vertex is already inserted in the working row_queue (rowIterator) - if( not rowIterator.empty()) - sparse_strong_vertex_collapse(); - else - return ; - } - - void complete_vertex_domination_check (doubleQueue& iterator, boolVector& insertIndicator, boolVector& domnIndicator) - { - double k; - doubleVector nonZeroInnerIdcs; - while(not iterator.empty()) // "iterator" contains list(FIFO) of rows to be considered for domination check - { - k = iterator.front(); - iterator.pop(); - insertIndicator[k] = false; - if( not domnIndicator[k]) // Check if is already dominated - { - nonZeroInnerIdcs = closed_neighbours_row_index(k); - for (doubleVector::iterator it = nonZeroInnerIdcs.begin(); it!=nonZeroInnerIdcs.end(); it++) - { - int checkDom = vertex_domination_check(k, *it); // "true" for row domination comparison - if( checkDom == 1) // row k is dominated by *it, k <= *it; - { - setZero(k, *it); - break ; - } - else if(checkDom == -1) // row *it is dominated by k, *it <= k; - setZero(*it, k); - } - } - } - } - - bool check_edge_domination(Edge e) // Edge e is the actual edge (u,v). Not the row ids in the matrixs - { - auto u = std::get<0>(e); - auto v = std::get<1>(e); - - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - auto rw_e = std::make_pair(rw_u,rw_v); - // std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; - auto commonNeighbours = closed_common_neighbours_row_index(rw_e); - // std::cout << "And its common neighbours are." << std::endl; - // for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - // std::cout << rowToVertex[*it] << ", " ; - // } - //std::cout<< std::endl; - if(commonNeighbours.size() > 2) { - if (commonNeighbours.size() == 3) - return true; - else - for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - auto rw_c = *it; // Typecasting - if(rw_c != rw_u and rw_c != rw_v) { - auto neighbours_c = closed_neighbours_row_index(rw_c); - if(std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), commonNeighbours.end())) // If neighbours_c contains the common neighbours. - return true; - } - } - } - return false; - } - - bool check_domination_indicator(Edge e) // The edge should be sorted by the indices and indices are original - { - return dominated_edge_indicator[edge_to_index_map[e]]; - } - - std::set three_clique_indices(std::size_t crit) { - std::set edge_indices; - - EdgeFilt fe = fEgdeVector.at(crit); - Edge e = std::get<0>(fe); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - - // std::cout << "The current critical edge to re-check criticality with filt value is : {" << u << "," << v << "}; "<< std::get<1>(fe) << std::endl; - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - auto rw_critical_edge = std::make_pair(rw_u,rw_v); - - doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); - - if(commonNeighbours.size() > 2) { - for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - auto rw_c = *it; - if(rw_c != rw_u and rw_c != rw_v) { - auto e_with_new_nbhr_v = std::minmax(u,rowToVertex[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v,rowToVertex[rw_c]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); - } - } - } - return edge_indices; - - } - - void set_edge_critical(std::size_t indx, double filt) - { - // std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; - std::set effectedIndcs = three_clique_indices(indx); - if(effectedIndcs.size() > 0){ - for(auto idx = indx-1; idx > 0 ; idx--) { - EdgeFilt fec = fEgdeVector.at(idx); - Edge e = std::get<0>(fec); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - if ( not critical_edge_indicator.at(idx) ) { // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() - if( effectedIndcs.find(idx) != effectedIndcs.end()) { // If idx is affected - if(not check_edge_domination(e)) { - // std::cout << "The curent index is became critical " << idx << std::endl; - critical_edge_indicator.at(idx) = true; - criticalCoreEdges.push_back({filt,u,v}); - std::set inner_effected_indcs = three_clique_indices(idx); - for(auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++ ) - { - if(*inr_idx < idx) - effectedIndcs.emplace(*inr_idx); - } - inner_effected_indcs.clear(); - // std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << std::get<1>(e) << "}; " << filt << std::endl; - } - else - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u],vertexToRow[v])); - } - else // Idx is not affected hence dominated. - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u],vertexToRow[v])); - - } - } - - } - effectedIndcs.clear(); - u_set_dominated_redges.clear(); - - } - - void critical_core_edges() - { - std::size_t totEdges = fEgdeVector.size(); - - std::size_t endIdx = 0; - - u_set_removed_redges.clear(); - u_set_dominated_redges.clear(); - critical_edge_indicator.clear(); - - while( endIdx < totEdges) - { - EdgeFilt fec = fEgdeVector.at(endIdx); - - insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)),std::get<1>(fec)); // Inserts the edge in the sparse matrix to update the graph (G_i) - - Edge e = std::get<0>(fec); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - edge_to_index_map.emplace(std::minmax(u,v), endIdx); - critical_edge_indicator.push_back(false); - dominated_edge_indicator.push_back(false); - - if ( not check_edge_domination(e) ) - { - critical_edge_indicator.at(endIdx) = true; - dominated_edge_indicator.at(endIdx) = false; - criticalCoreEdges.push_back({std::get<1>(fec),u,v}); - if(endIdx > 1) - set_edge_critical(endIdx, std::get<1>(fec)); - - } - else - dominated_edge_indicator.at(endIdx) = true; - endIdx++; - } - - std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; - std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; -} - - - int vertex_domination_check( double i, double j) // True for row comparison, false for column comparison - { - if(i != j) - { - doubleVector Listi = closed_neighbours_row_index(i); - doubleVector Listj = closed_neighbours_row_index(j); - if(Listj.size() <= Listi.size()) - { - if(std::includes(Listi.begin(), Listi.end(), Listj.begin(), Listj.end())) // Listj is a subset of Listi - return -1; - } - - else - if(std::includes(Listj.begin(), Listj.end(), Listi.begin(), Listi.end())) // Listi is a subset of Listj - return 1; - } - return 0; - } - - doubleVector closed_neighbours_row_index(double indx) // Returns list of non-zero columns of the particular indx. - { - doubleVector nonZeroIndices; - Vertex u = indx; - Vertex v; - // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; - if(not vertDomnIndicator[indx]) { - for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { // Iterate over the non-zero columns - v = it.index(); - if(not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { // If the vertex v is not dominated and the edge {u,v} is still in the matrix - nonZeroIndices.push_back(it.index()); // inner index, here it is equal to it.columns() - // std::cout << rowToVertex[it.index()] << ", " ; - } - } - // std::cout << std::endl; - } - return nonZeroIndices; - } - - doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. - { - doubleVector common; - doubleVector nonZeroIndices_u; - doubleVector nonZeroIndices_v; - double u = std::get<0>(e) ; - double v = std::get<1>(e) ; - - nonZeroIndices_u = closed_neighbours_row_index(u); - nonZeroIndices_v = closed_neighbours_row_index(v); - std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), nonZeroIndices_v.end(), std::inserter(common, common.begin())); - - return common; - } - - void setZero(double dominated, double dominating) - { - for(auto & v: closed_neighbours_row_index(dominated)) - if(not rowInsertIndicator[v]) // Checking if the row is already inserted - { - rowIterator.push(v); - rowInsertIndicator[v] = true; - } - vertDomnIndicator[dominated] = true; - ReductionMap[rowToVertex[dominated]] = rowToVertex[dominating]; - - vertexToRow.erase(rowToVertex[dominated]); - vertices.erase(rowToVertex[dominated]); - rowToVertex.erase(dominated); - } - - vertexVector closed_neighbours_vertex_index(double rowIndx) // Returns list of non-zero "vertices" of the particular colIndx. the difference is in the return type - { - vertexVector colmns ; - for(auto & v: closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns - colmns.push_back(rowToVertex[v]); - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - vertexVector vertex_closed_active_neighbours(double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx which are currently active. the difference is in the return type. - { - vertexVector colmns ; - for(auto & v: closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns - if(not contractionIndicator[v]) // Check if the row corresponds to a contracted vertex - colmns.push_back(rowToVertex[v]); - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - vertexVector closed_all_neighbours_row_index(double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx whether dominated or not. the difference is in the return type. - { - vertexVector colmns ; - for (rowInnerIterator itCol(sparseRowAdjMatrix,rowIndx); itCol; ++itCol) // Iterate over the non-zero columns - colmns.push_back(rowToVertex[itCol.index()]); // inner index, here it is equal to it.row() - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - void swap_rows(const Vertex & v, const Vertex & w) { // swap the rows of v and w. Both should be members of the skeleton - if(membership(v) && membership(w)){ - auto rw_v = vertexToRow[v]; - auto rw_w = vertexToRow[w]; - vertexToRow[v] = rw_w; - vertexToRow[w] = rw_v; - rowToVertex[rw_v] = w; - rowToVertex[rw_w] = v; - } - } - -public: - - //! Default Constructor - /*! - Only initialises all Data Members of the class to empty/Null values as appropriate. - One WILL have to create the matrix using the Constructor that has an object of the Simplex_tree class as argument. - */ - - FlagComplexSpMatrix() - { - init(); - } - - FlagComplexSpMatrix(std::size_t expRows) - { - init(); - sparseRowAdjMatrix = sparseRowMatrix(expansion_limit*expRows, expansion_limit*expRows); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - } - - //! Main Constructor - /*! - Argument is an instance of Filtered_sorted_edge_list.
- This is THE function that initialises all data members to appropriate values.
- rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. - vertDomnIndicator, rowInsertIndicator ,rowIterator are initialised by init() function which is called at the begining of this.
- */ - FlagComplexSpMatrix(const size_t & num_vertices, const Filtered_sorted_edge_list & edge_t) { - init(); - sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - - for(size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - // std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; - // insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); - fEgdeVector.push_back({{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))},std::get<0>(edge_t.at(bgn_idx))}); - } - - // sparseRowAdjMatrix.makeCompressed(); - } - - //! Destructor. - /*! - Frees up memory locations on the heap. - */ - ~FlagComplexSpMatrix() - { - } - - //! Function for performing strong collapse. - /*! - calls sparse_strong_vertex_collapse(), and - Then, it compacts the ReductionMap by calling the function fully_compact(). - */ - double strong_vertex_collapse() { - auto begin_collapse = std::chrono::high_resolution_clock::now(); - sparse_strong_vertex_collapse(); - vertexCollapsed = true; - auto end_collapse = std::chrono::high_resolution_clock::now(); - - auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); - // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; - - // Now we complete the Reduction Map - fully_compact(); - //Post processing... - after_vertex_collapse(); - return collapseTime; - } - - // Performs edge collapse in a decreasing sequence of the filtration value. - Filtered_sorted_edge_list filtered_edge_collapse() { - critical_core_edges(); - vertexCollapsed = false; - edgeCollapsed = true; - return criticalCoreEdges; - } - - // double strong_vertex_edge_collapse() { - // auto begin_collapse = std::chrono::high_resolution_clock::now(); - // strong_vertex_collapse(); - // strong_edge_collapse(); - // // strong_vertex_collapse(); - // auto end_collapse = std::chrono::high_resolution_clock::now(); - - // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); - // return collapseTime; - // } - - bool membership(const Vertex & v) { - auto rw = vertexToRow.find(v); - if(rw != vertexToRow.end()) - return true; - else - return false; - } - - bool membership(const Edge & e) { - auto u = std::get<0>(e); - auto v = std::get<1>(e); - if(membership(u) && membership(v)) { - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - if(rw_u <= rw_v) - for( auto x : closed_neighbours_row_index(rw_v)){ // Taking advantage of sorted lists. - if(rw_u == x) - return true; - else if(rw_u < x) - return false; - } - else - for( auto x : closed_neighbours_row_index(rw_u)){ // Taking advantage of sorted lists. - if(rw_v == x) - return true; - else if(rw_v < x) - return false; - } - } - return false; - - } - void insert_vertex(const Vertex & vertex, double filt_val) - { - auto rw = vertexToRow.find(vertex); - if(rw == vertexToRow.end()) { - sparseRowAdjMatrix.insert(rows,rows) = filt_val; // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - vertDomnIndicator.push_back(false); - rowInsertIndicator.push_back(true); - contractionIndicator.push_back(false); - rowIterator.push(rows); - vertexToRow.insert(std::make_pair(vertex, rows)); - rowToVertex.insert(std::make_pair(rows, vertex)); - vertices.emplace(vertex); - rows++; - } - } - - void insert_new_edges(const Vertex & u, const Vertex & v, double filt_val) // The edge must not be added before, it should be a new edge. - { - insert_vertex(u, filt_val); - if( u != v) { - insert_vertex(v, filt_val); - // std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; - - auto rw_u = vertexToRow.find(u); - auto rw_v = vertexToRow.find(v); - // std::cout << "Inserting the edge " << u <<", " << v << std::endl; - sparseRowAdjMatrix.insert(rw_u->second,rw_v->second) = filt_val; - sparseRowAdjMatrix.insert(rw_v->second,rw_u->second) = filt_val; - oneSimplices.emplace_back(u, v); - numOneSimplices++; - } - // else - // std::cout << "Already a member simplex, skipping..." << std::endl; - - } - - - - std::size_t num_vertices() const { - return vertices.size(); - } - - //! Function for returning the ReductionMap. - /*! - This is the (stl's unordered) map that stores all the collapses of vertices.
- It is simply returned. - */ - - Map reduction_map() const { - return ReductionMap; - } - std::unordered_set vertex_set() const { - return vertices; + edge_list oneSimplices; + + // Unordered set of removed edges. (to enforce removal from the matrix) + std::unordered_set> u_set_removed_redges; + + // Unordered set of dominated edges. (to inforce removal from the matrix) + std::unordered_set> u_set_dominated_redges; + + // Map from egde to its index + u_edge_to_idx_map edge_to_index_map; + // Boolean vector to indicate if the index is critical or not. + boolVector critical_edge_indicator; // critical indicator + + // Boolean vector to indicate if the index is critical or not. + boolVector dominated_edge_indicator; // domination indicator + + //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. + /*! + \code + MapVertexToIndex = std::unordered_map + \endcode + So, if the original simplex tree had vertices 0,1,4,5
+ rowToVertex would store :
+ \verbatim + Values = | 0 | 1 | 4 | 5 | + Indices = 0 1 2 3 + \endverbatim + And vertexToRow would be a map like the following :
+ \verbatim + 0 -> 0 + 1 -> 1 + 4 -> 2 + 5 -> 3 + \endverbatim + */ + MapVertexToIndex vertexToRow; + + //! Stores the number of vertices in the original Simplicial Complex. + /*! + This stores the count of vertices (which is also the number of rows in the Matrix). + */ + std::size_t rows; + + std::size_t numOneSimplices; + + std::size_t numDomEdge; + + //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. + /*! + \code + sparseRowMatrix = Eigen::SparseMatrix ; + \endcode + ; + */ + + sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. + sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access + // to elements when traversing the matrix row-wise. + + //! Stores true for dominated rows and false for undominated rows. + /*! + Initialised to a vector of length equal to the value of the variable rows with all false values. + Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. + */ + boolVector vertDomnIndicator; //(domination indicator) + + boolVector contractionIndicator; //(contraction indicator) + + //! Stores the indices of the rows to-be checked for domination in the current iteration. + /*! + Initialised with all rows for the first iteration. + Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. + */ + // doubleQueue rowIterator; + + doubleQueue rowIterator; + + // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltQueue filteredEgdeIter; + + // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltVector fEgdeVector; + + // List of non-dominated edges, the indices of the edges are the vertex lables!!. + Filtered_sorted_edge_list criticalCoreEdges; + // Stores the indices from the sorted filtered edge vector. + // std::set recurCriticalCoreIndcs; + + //! Stores true if the current row is inserted in the queue rowIterator otherwise its value is + //! false. + /*! + Initialised to a boolean vector of length equal to the value of the variable rows with all true + values. Subsequent removal/addition of a row from rowIterator is reflected by concerned entries changing to + false/true in this vector. + */ + boolVector rowInsertIndicator; //(current iteration row insertion indicator) + + //! Map that stores the Reduction / Collapse of vertices. + /*! + \code + Map = std::unordered_map + \endcode + This is empty to begin with. As and when collapses are done (let's say from dominated vertex v to dominating + vertex v') :
ReductionMap[v] = v' is entered into the map.
This does not + store uncollapsed vertices. What it means is that say vertex x was never collapsed onto any other vertex. + Then, this map WILL NOT have any entry like x -> x. Basically, it will have no entry + corresponding to vertex x at all. + */ + Map ReductionMap; + + bool vertexCollapsed; + bool edgeCollapsed; + // Variable to indicate if filtered-edge-collapse has to be performed. + int expansion_limit; + + void init() { + rowToVertex.clear(); + vertexToRow.clear(); + oneSimplices.clear(); + ReductionMap.clear(); + + vertDomnIndicator.clear(); + rowInsertIndicator.clear(); + rowIterator.push(0); + rowIterator.pop(); + + filteredEgdeIter.push({{0, 0}, 0}); + filteredEgdeIter.pop(); + fEgdeVector.clear(); + + rows = 0; + numDomEdge = 0; + + numOneSimplices = 0; + expansion_limit = 2; + + vertexCollapsed = false; + edgeCollapsed = false; + } + + //! Function for computing the sparse-matrix corresponding to the core of the complex. It also prepares the working + //!list filteredEgdeIter for edge collapses + void after_vertex_collapse() { + sparse_colpsd_adj_Matrix = new sparseRowMatrix(rows, rows); // Just for debugging purpose. + oneSimplices.clear(); + if (not filteredEgdeIter.empty()) { + std::cout << "Working list for edge collapses are not empty before the edge-collapse." << std::endl; } - sparseRowMatrix collapsed_matrix() const { - return *sparse_colpsd_adj_Matrix; + for (std::size_t rw = 0; rw < rows; ++rw) { + if (not vertDomnIndicator[rw]) // If the current column is not dominated + { + auto nbhrs_to_insert = closed_neighbours_row_index(rw); // returns row indices of the non-dominated vertices. + for (auto& v : nbhrs_to_insert) { + sparse_colpsd_adj_Matrix->insert(rw, v) = 1; // This creates the full matrix + if (rw < v) { + oneSimplices.push_back({rowToVertex[rw], rowToVertex[v]}); + filteredEgdeIter.push({{rw, v}, 1}); + // if(rw == v) + // std::cout << "Pushed the edge {" << rw << ", " << v << "} " << std::endl; + } + } + } } - - sparseRowMatrix uncollapsed_matrix() const { - return sparseRowAdjMatrix; + // std::cout << "Total number of non-zero elements before domination check are: " << + // sparse_colpsd_adj_Matrix->nonZeros() << std::endl; std::cout << "Total number of edges for domination check are: + // " << filteredEgdeIter.size() << std::endl; + // std::cout << *sparse_colpsd_adj_Matrix << std::endl; + return; + } + + //! Function to fully compact a particular vertex of the ReductionMap. + /*! + It takes as argument the iterator corresponding to a particular vertex pair (key-value) stored in the ReductionMap. +
It then checks if the second element of this particular vertex pair is present as a first element of some other + key-value pair in the map. If no, then the first element of the vertex pair in consideration is fully compact. If + yes, then recursively call fully_compact_this_vertex() on the second element of the original pair in consideration + and assign its resultant image as the image of the first element of the original pair in consideration as well. + */ + void fully_compact_this_vertex(Map::iterator iter) { + Map::iterator found = ReductionMap.find(iter->second); + if (found == ReductionMap.end()) return; + + fully_compact_this_vertex(found); + iter->second = ReductionMap[iter->second]; + } + + //! Function to fully compact the Reduction Map. + /*! + While doing strong collapses, we store only the immediate collapse of a vertex. Which means that in one round, + vertex x may collapse to vertex y. And in some later round it may be possible that vertex y + collapses to z. In which case our map stores :
x -> y and also y -> z. But + it really should store : x -> z and y -> z. This function achieves the same.
It + basically calls fully_compact_this_vertex() for each entry in the map. + */ + void fully_compact() { + Map::iterator it = ReductionMap.begin(); + while (it != ReductionMap.end()) { + fully_compact_this_vertex(it); + it++; + } + } + + void sparse_strong_vertex_collapse() { + complete_vertex_domination_check( + rowIterator, rowInsertIndicator, + vertDomnIndicator); // Complete check for rows in rowIterator, rowInsertIndicator is a list of boolean + // indicator if a vertex is already inserted in the working row_queue (rowIterator) + if (not rowIterator.empty()) + sparse_strong_vertex_collapse(); + else + return; + } + + void complete_vertex_domination_check(doubleQueue& iterator, boolVector& insertIndicator, boolVector& domnIndicator) { + double k; + doubleVector nonZeroInnerIdcs; + while (not iterator.empty()) // "iterator" contains list(FIFO) of rows to be considered for domination check + { + k = iterator.front(); + iterator.pop(); + insertIndicator[k] = false; + if (not domnIndicator[k]) // Check if is already dominated + { + nonZeroInnerIdcs = closed_neighbours_row_index(k); + for (doubleVector::iterator it = nonZeroInnerIdcs.begin(); it != nonZeroInnerIdcs.end(); it++) { + int checkDom = vertex_domination_check(k, *it); // "true" for row domination comparison + if (checkDom == 1) // row k is dominated by *it, k <= *it; + { + setZero(k, *it); + break; + } else if (checkDom == -1) // row *it is dominated by k, *it <= k; + setZero(*it, k); + } + } + } + } + + bool check_edge_domination(Edge e) // Edge e is the actual edge (u,v). Not the row ids in the matrixs + { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_e = std::make_pair(rw_u, rw_v); + // std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; + auto commonNeighbours = closed_common_neighbours_row_index(rw_e); + // std::cout << "And its common neighbours are." << std::endl; + // for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + // std::cout << rowToVertex[*it] << ", " ; + // } + // std::cout<< std::endl; + if (commonNeighbours.size() > 2) { + if (commonNeighbours.size() == 3) + return true; + else + for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { + auto rw_c = *it; // Typecasting + if (rw_c != rw_u and rw_c != rw_v) { + auto neighbours_c = closed_neighbours_row_index(rw_c); + if (std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), + commonNeighbours.end())) // If neighbours_c contains the common neighbours. + return true; + } + } + } + return false; + } + + bool check_domination_indicator(Edge e) // The edge should be sorted by the indices and indices are original + { + return dominated_edge_indicator[edge_to_index_map[e]]; + } + + std::set three_clique_indices(std::size_t crit) { + std::set edge_indices; + + EdgeFilt fe = fEgdeVector.at(crit); + Edge e = std::get<0>(fe); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + + // std::cout << "The current critical edge to re-check criticality with filt value is : {" << u << "," << v << "}; + // "<< std::get<1>(fe) << std::endl; + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_critical_edge = std::make_pair(rw_u, rw_v); + + doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); + + if (commonNeighbours.size() > 2) { + for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { + auto rw_c = *it; + if (rw_c != rw_u and rw_c != rw_v) { + auto e_with_new_nbhr_v = std::minmax(u, rowToVertex[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v, rowToVertex[rw_c]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); + } + } } - - edge_list all_edges() const { - return oneSimplices; + return edge_indices; + } + + void set_edge_critical(std::size_t indx, double filt) { + // std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << + // std::endl; + std::set effectedIndcs = three_clique_indices(indx); + if (effectedIndcs.size() > 0) { + for (auto idx = indx - 1; idx > 0; idx--) { + EdgeFilt fec = fEgdeVector.at(idx); + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + if (not critical_edge_indicator.at( + idx)) { // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev + // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() + if (effectedIndcs.find(idx) != effectedIndcs.end()) { // If idx is affected + if (not check_edge_domination(e)) { + // std::cout << "The curent index is became critical " << idx << std::endl; + critical_edge_indicator.at(idx) = true; + criticalCoreEdges.push_back({filt, u, v}); + std::set inner_effected_indcs = three_clique_indices(idx); + for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { + if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); + } + inner_effected_indcs.clear(); + // std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << + // std::get<1>(e) << "}; " << filt << std::endl; + } else + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + } else // Idx is not affected hence dominated. + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + } + } } + effectedIndcs.clear(); + u_set_dominated_redges.clear(); + } - vertexVector active_neighbors(const Vertex & v) { - vertexVector nb; - auto rw_v = vertexToRow.find(v); - if(rw_v != vertexToRow.end()) { - nb = vertex_closed_active_neighbours(rw_v->second); - } - return nb; + void critical_core_edges() { + std::size_t totEdges = fEgdeVector.size(); + + std::size_t endIdx = 0; + + u_set_removed_redges.clear(); + u_set_dominated_redges.clear(); + critical_edge_indicator.clear(); + + while (endIdx < totEdges) { + EdgeFilt fec = fEgdeVector.at(endIdx); + + insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)), + std::get<1>(fec)); // Inserts the edge in the sparse matrix to update the graph (G_i) + + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + edge_to_index_map.emplace(std::minmax(u, v), endIdx); + critical_edge_indicator.push_back(false); + dominated_edge_indicator.push_back(false); + + if (not check_edge_domination(e)) { + critical_edge_indicator.at(endIdx) = true; + dominated_edge_indicator.at(endIdx) = false; + criticalCoreEdges.push_back({std::get<1>(fec), u, v}); + if (endIdx > 1) set_edge_critical(endIdx, std::get<1>(fec)); + + } else + dominated_edge_indicator.at(endIdx) = true; + endIdx++; } - vertexVector neighbors(const Vertex & v) { - vertexVector nb; - auto rw_v = vertexToRow.find(v); - if(rw_v != vertexToRow.end()) - nb = closed_neighbours_vertex_index(rw_v->second); - - return nb; + std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; + std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; + } + + int vertex_domination_check(double i, double j) // True for row comparison, false for column comparison + { + if (i != j) { + doubleVector Listi = closed_neighbours_row_index(i); + doubleVector Listj = closed_neighbours_row_index(j); + if (Listj.size() <= Listi.size()) { + if (std::includes(Listi.begin(), Listi.end(), Listj.begin(), Listj.end())) // Listj is a subset of Listi + return -1; + } + + else if (std::includes(Listj.begin(), Listj.end(), Listi.begin(), Listi.end())) // Listi is a subset of Listj + return 1; + } + return 0; + } + + doubleVector closed_neighbours_row_index(double indx) // Returns list of non-zero columns of the particular indx. + { + doubleVector nonZeroIndices; + Vertex u = indx; + Vertex v; + // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; + if (not vertDomnIndicator[indx]) { + for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { // Iterate over the non-zero columns + v = it.index(); + if (not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and + u_set_dominated_redges.find(std::minmax(u, v)) == + u_set_dominated_redges + .end()) { // If the vertex v is not dominated and the edge {u,v} is still in the matrix + nonZeroIndices.push_back(it.index()); // inner index, here it is equal to it.columns() + // std::cout << rowToVertex[it.index()] << ", " ; + } + } + // std::cout << std::endl; + } + return nonZeroIndices; + } + + doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. + { + doubleVector common; + doubleVector nonZeroIndices_u; + doubleVector nonZeroIndices_v; + double u = std::get<0>(e); + double v = std::get<1>(e); + + nonZeroIndices_u = closed_neighbours_row_index(u); + nonZeroIndices_v = closed_neighbours_row_index(v); + std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), + nonZeroIndices_v.end(), std::inserter(common, common.begin())); + + return common; + } + + void setZero(double dominated, double dominating) { + for (auto& v : closed_neighbours_row_index(dominated)) + if (not rowInsertIndicator[v]) // Checking if the row is already inserted + { + rowIterator.push(v); + rowInsertIndicator[v] = true; + } + vertDomnIndicator[dominated] = true; + ReductionMap[rowToVertex[dominated]] = rowToVertex[dominating]; + + vertexToRow.erase(rowToVertex[dominated]); + vertices.erase(rowToVertex[dominated]); + rowToVertex.erase(dominated); + } + + vertexVector closed_neighbours_vertex_index(double rowIndx) // Returns list of non-zero "vertices" of the particular + // colIndx. the difference is in the return type + { + vertexVector colmns; + for (auto& v : closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns + colmns.push_back(rowToVertex[v]); + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + vertexVector vertex_closed_active_neighbours( + double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx which are currently active. + // the difference is in the return type. + { + vertexVector colmns; + for (auto& v : closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns + if (not contractionIndicator[v]) // Check if the row corresponds to a contracted vertex + colmns.push_back(rowToVertex[v]); + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + vertexVector closed_all_neighbours_row_index( + double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx whether dominated or not. + // the difference is in the return type. + { + vertexVector colmns; + for (rowInnerIterator itCol(sparseRowAdjMatrix, rowIndx); itCol; ++itCol) // Iterate over the non-zero columns + colmns.push_back(rowToVertex[itCol.index()]); // inner index, here it is equal to it.row() + std::sort(colmns.begin(), colmns.end()); + return colmns; + } + + void swap_rows(const Vertex& v, + const Vertex& w) { // swap the rows of v and w. Both should be members of the skeleton + if (membership(v) && membership(w)) { + auto rw_v = vertexToRow[v]; + auto rw_w = vertexToRow[w]; + vertexToRow[v] = rw_w; + vertexToRow[w] = rw_v; + rowToVertex[rw_v] = w; + rowToVertex[rw_w] = v; + } + } + + public: + //! Default Constructor + /*! + Only initialises all Data Members of the class to empty/Null values as appropriate. + One WILL have to create the matrix using the Constructor that has an object of the Simplex_tree class as + argument. + */ + + FlagComplexSpMatrix() { init(); } + + FlagComplexSpMatrix(std::size_t expRows) { + init(); + sparseRowAdjMatrix = sparseRowMatrix( + expansion_limit * expRows, + expansion_limit * expRows); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + } + + //! Main Constructor + /*! + Argument is an instance of Filtered_sorted_edge_list.
+ This is THE function that initialises all data members to appropriate values.
+ rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. + vertDomnIndicator, rowInsertIndicator ,rowIterator are initialised by init() function which is + called at the begining of this.
+ */ + FlagComplexSpMatrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) { + init(); + sparseRowAdjMatrix = sparseRowMatrix( + num_vertices, num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + + for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { + // std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; + // insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); + fEgdeVector.push_back( + {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); } - vertexVector active_relative_neighbors(const Vertex & v, const Vertex & w){ - std::vector diff; - if(membership(v) && membership(w)){ - auto nbhrs_v = active_neighbors(v); - auto nbhrs_w = active_neighbors(w); - std::set_difference(nbhrs_v.begin(), nbhrs_v.end(), nbhrs_w.begin(), nbhrs_w.end(), std::inserter(diff, diff.begin())); - } - return diff; + // sparseRowAdjMatrix.makeCompressed(); + } + + //! Destructor. + /*! + Frees up memory locations on the heap. + */ + ~FlagComplexSpMatrix() {} + + //! Function for performing strong collapse. + /*! + calls sparse_strong_vertex_collapse(), and + Then, it compacts the ReductionMap by calling the function fully_compact(). + */ + double strong_vertex_collapse() { + auto begin_collapse = std::chrono::high_resolution_clock::now(); + sparse_strong_vertex_collapse(); + vertexCollapsed = true; + auto end_collapse = std::chrono::high_resolution_clock::now(); + + auto collapseTime = std::chrono::duration(end_collapse - begin_collapse).count(); + // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; + + // Now we complete the Reduction Map + fully_compact(); + // Post processing... + after_vertex_collapse(); + return collapseTime; + } + + // Performs edge collapse in a decreasing sequence of the filtration value. + Filtered_sorted_edge_list filtered_edge_collapse() { + critical_core_edges(); + vertexCollapsed = false; + edgeCollapsed = true; + return criticalCoreEdges; + } + + // double strong_vertex_edge_collapse() { + // auto begin_collapse = std::chrono::high_resolution_clock::now(); + // strong_vertex_collapse(); + // strong_edge_collapse(); + // // strong_vertex_collapse(); + // auto end_collapse = std::chrono::high_resolution_clock::now(); + + // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); + // return collapseTime; + // } + + bool membership(const Vertex& v) { + auto rw = vertexToRow.find(v); + if (rw != vertexToRow.end()) + return true; + else + return false; + } + + bool membership(const Edge& e) { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + if (membership(u) && membership(v)) { + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + if (rw_u <= rw_v) + for (auto x : closed_neighbours_row_index(rw_v)) { // Taking advantage of sorted lists. + if (rw_u == x) + return true; + else if (rw_u < x) + return false; + } + else + for (auto x : closed_neighbours_row_index(rw_u)) { // Taking advantage of sorted lists. + if (rw_v == x) + return true; + else if (rw_v < x) + return false; + } + } + return false; + } + void insert_vertex(const Vertex& vertex, double filt_val) { + auto rw = vertexToRow.find(vertex); + if (rw == vertexToRow.end()) { + sparseRowAdjMatrix.insert(rows, rows) = + filt_val; // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + vertDomnIndicator.push_back(false); + rowInsertIndicator.push_back(true); + contractionIndicator.push_back(false); + rowIterator.push(rows); + vertexToRow.insert(std::make_pair(vertex, rows)); + rowToVertex.insert(std::make_pair(rows, vertex)); + vertices.emplace(vertex); + rows++; + } + } + + void insert_new_edges(const Vertex& u, const Vertex& v, + double filt_val) // The edge must not be added before, it should be a new edge. + { + insert_vertex(u, filt_val); + if (u != v) { + insert_vertex(v, filt_val); + // std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; + + auto rw_u = vertexToRow.find(u); + auto rw_v = vertexToRow.find(v); + // std::cout << "Inserting the edge " << u <<", " << v << std::endl; + sparseRowAdjMatrix.insert(rw_u->second, rw_v->second) = filt_val; + sparseRowAdjMatrix.insert(rw_v->second, rw_u->second) = filt_val; + oneSimplices.emplace_back(u, v); + numOneSimplices++; } + // else + // std::cout << "Already a member simplex, skipping..." << std::endl; + } + + std::size_t num_vertices() const { return vertices.size(); } + + //! Function for returning the ReductionMap. + /*! + This is the (stl's unordered) map that stores all the collapses of vertices.
+ It is simply returned. + */ + + Map reduction_map() const { return ReductionMap; } + std::unordered_set vertex_set() const { return vertices; } + sparseRowMatrix collapsed_matrix() const { return *sparse_colpsd_adj_Matrix; } + + sparseRowMatrix uncollapsed_matrix() const { return sparseRowAdjMatrix; } - - void contraction(const Vertex & del, const Vertex & keep){ - if(del != keep){ - bool del_mem = membership (del); - bool keep_mem = membership(keep); - if( del_mem && keep_mem) - { - doubleVector del_indcs, keep_indcs, diff; - auto row_del = vertexToRow[del]; - auto row_keep = vertexToRow[keep]; - del_indcs = closed_neighbours_row_index(row_del); - keep_indcs = closed_neighbours_row_index(row_keep); - std::set_difference(del_indcs.begin(), del_indcs.end(), keep_indcs.begin(), keep_indcs.end(), std::inserter(diff, diff.begin())); - for (auto & v : diff) { - if( v != row_del){ - sparseRowAdjMatrix.insert(row_keep,v) = 1; - sparseRowAdjMatrix.insert(v, row_keep) = 1; - } - } - vertexToRow.erase(del); - vertices.erase(del); - rowToVertex.erase(row_del); - //setZero(row_del->second, row_keep->second); - } - else if(del_mem && not keep_mem) - { - vertexToRow.insert(std::make_pair(keep, vertexToRow.find(del)->second)); - rowToVertex[vertexToRow.find(del)->second] = keep; - vertices.emplace(keep); - vertices.erase(del); - vertexToRow.erase(del); - - } - else - { - std::cerr << "The first vertex entered in the method contraction() doesn't exist in the skeleton." <second] = true; - } - if(membership(v) && !membership(w)){ - relable(v,w); - } - } - void active_edge_insertion(const Vertex & v, const Vertex & w, double filt_val){ - insert_new_edges(v,w, filt_val); - //update_active_indicator(v,w); - } - - void print_sparse_skeleton(){ - std::cout << sparseRowAdjMatrix << std::endl; - } + edge_list all_edges() const { return oneSimplices; } + + vertexVector active_neighbors(const Vertex& v) { + vertexVector nb; + auto rw_v = vertexToRow.find(v); + if (rw_v != vertexToRow.end()) { + nb = vertex_closed_active_neighbours(rw_v->second); + } + return nb; + } + + vertexVector neighbors(const Vertex& v) { + vertexVector nb; + auto rw_v = vertexToRow.find(v); + if (rw_v != vertexToRow.end()) nb = closed_neighbours_vertex_index(rw_v->second); + + return nb; + } + + vertexVector active_relative_neighbors(const Vertex& v, const Vertex& w) { + std::vector diff; + if (membership(v) && membership(w)) { + auto nbhrs_v = active_neighbors(v); + auto nbhrs_w = active_neighbors(w); + std::set_difference(nbhrs_v.begin(), nbhrs_v.end(), nbhrs_w.begin(), nbhrs_w.end(), + std::inserter(diff, diff.begin())); + } + return diff; + } + + void contraction(const Vertex& del, const Vertex& keep) { + if (del != keep) { + bool del_mem = membership(del); + bool keep_mem = membership(keep); + if (del_mem && keep_mem) { + doubleVector del_indcs, keep_indcs, diff; + auto row_del = vertexToRow[del]; + auto row_keep = vertexToRow[keep]; + del_indcs = closed_neighbours_row_index(row_del); + keep_indcs = closed_neighbours_row_index(row_keep); + std::set_difference(del_indcs.begin(), del_indcs.end(), keep_indcs.begin(), keep_indcs.end(), + std::inserter(diff, diff.begin())); + for (auto& v : diff) { + if (v != row_del) { + sparseRowAdjMatrix.insert(row_keep, v) = 1; + sparseRowAdjMatrix.insert(v, row_keep) = 1; + } + } + vertexToRow.erase(del); + vertices.erase(del); + rowToVertex.erase(row_del); + // setZero(row_del->second, row_keep->second); + } else if (del_mem && not keep_mem) { + vertexToRow.insert(std::make_pair(keep, vertexToRow.find(del)->second)); + rowToVertex[vertexToRow.find(del)->second] = keep; + vertices.emplace(keep); + vertices.erase(del); + vertexToRow.erase(del); + + } else { + std::cerr << "The first vertex entered in the method contraction() doesn't exist in the skeleton." << std::endl; + exit(-1); + } + } + } + + void relable(const Vertex& v, const Vertex& w) { // relable v as w. + if (membership(v) and v != w) { + auto rw_v = vertexToRow[v]; + rowToVertex[rw_v] = w; + vertexToRow.insert(std::make_pair(w, rw_v)); + vertices.emplace(w); + vertexToRow.erase(v); + vertices.erase(v); + // std::cout<< "Re-named the vertex " << v << " as " << w << std::endl; + } + } + + // Returns the contracted edge. along with the contracted vertex in the begining of the list at {u,u} or {v,v} + + void active_strong_expansion(const Vertex& v, const Vertex& w, double filt_val) { + if (membership(v) && membership(w) && v != w) { + // std::cout << "Strong expansion of the vertex " << v << " and " << w << " begins. " << std::endl; + auto active_list_v_w = active_relative_neighbors(v, w); + auto active_list_w_v = active_relative_neighbors(w, v); + if (active_list_w_v.size() < + active_list_v_w.size()) { // simulate the contraction of w by expanding the star of v + for (auto& x : active_list_w_v) { + active_edge_insertion(v, x, filt_val); + // std::cout << "Inserted the edge " << v << " , " << x << std::endl; + } + swap_rows(v, w); + // std::cout << "A swap of the vertex " << v << " and " << w << "took place." << std::endl; + } else { + for (auto& y : active_list_v_w) { + active_edge_insertion(w, y, filt_val); + // std::cout << "Inserted the edge " << w << ", " << y << std::endl; + } + } + auto rw_v = vertexToRow.find(v); + contractionIndicator[rw_v->second] = true; + } + if (membership(v) && !membership(w)) { + relable(v, w); + } + } + void active_edge_insertion(const Vertex& v, const Vertex& w, double filt_val) { + insert_new_edges(v, w, filt_val); + // update_active_indicator(v,w); + } + void print_sparse_skeleton() { std::cout << sparseRowAdjMatrix << std::endl; } }; \ No newline at end of file -- cgit v1.2.3 From 44090f837b402941b345631a2ef92b3f9c88a738 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sun, 5 Apr 2020 09:00:44 +0200 Subject: Some cleanup --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 433 +---------------------- 1 file changed, 5 insertions(+), 428 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index ac02a46f..20db7fae 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -116,16 +116,6 @@ class FlagComplexSpMatrix { */ MapVertexToIndex vertexToRow; - //! Stores the number of vertices in the original Simplicial Complex. - /*! - This stores the count of vertices (which is also the number of rows in the Matrix). - */ - std::size_t rows; - - std::size_t numOneSimplices; - - std::size_t numDomEdge; - //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. /*! \code @@ -167,155 +157,23 @@ class FlagComplexSpMatrix { // Stores the indices from the sorted filtered edge vector. // std::set recurCriticalCoreIndcs; - //! Stores true if the current row is inserted in the queue rowIterator otherwise its value is - //! false. + //! Stores the number of vertices in the original Simplicial Complex. /*! - Initialised to a boolean vector of length equal to the value of the variable rows with all true - values. Subsequent removal/addition of a row from rowIterator is reflected by concerned entries changing to - false/true in this vector. + This stores the count of vertices (which is also the number of rows in the Matrix). */ - boolVector rowInsertIndicator; //(current iteration row insertion indicator) + std::size_t rows; - //! Map that stores the Reduction / Collapse of vertices. - /*! - \code - Map = std::unordered_map - \endcode - This is empty to begin with. As and when collapses are done (let's say from dominated vertex v to dominating - vertex v') :
ReductionMap[v] = v' is entered into the map.
This does not - store uncollapsed vertices. What it means is that say vertex x was never collapsed onto any other vertex. - Then, this map WILL NOT have any entry like x -> x. Basically, it will have no entry - corresponding to vertex x at all. - */ - Map ReductionMap; + std::size_t numOneSimplices; - bool vertexCollapsed; bool edgeCollapsed; - // Variable to indicate if filtered-edge-collapse has to be performed. - int expansion_limit; void init() { - rowToVertex.clear(); - vertexToRow.clear(); - oneSimplices.clear(); - ReductionMap.clear(); - - vertDomnIndicator.clear(); - rowInsertIndicator.clear(); - rowIterator.push(0); - rowIterator.pop(); - - filteredEgdeIter.push({{0, 0}, 0}); - filteredEgdeIter.pop(); - fEgdeVector.clear(); - rows = 0; - numDomEdge = 0; numOneSimplices = 0; - expansion_limit = 2; - - vertexCollapsed = false; edgeCollapsed = false; } - //! Function for computing the sparse-matrix corresponding to the core of the complex. It also prepares the working - //!list filteredEgdeIter for edge collapses - void after_vertex_collapse() { - sparse_colpsd_adj_Matrix = new sparseRowMatrix(rows, rows); // Just for debugging purpose. - oneSimplices.clear(); - if (not filteredEgdeIter.empty()) { - std::cout << "Working list for edge collapses are not empty before the edge-collapse." << std::endl; - } - for (std::size_t rw = 0; rw < rows; ++rw) { - if (not vertDomnIndicator[rw]) // If the current column is not dominated - { - auto nbhrs_to_insert = closed_neighbours_row_index(rw); // returns row indices of the non-dominated vertices. - for (auto& v : nbhrs_to_insert) { - sparse_colpsd_adj_Matrix->insert(rw, v) = 1; // This creates the full matrix - if (rw < v) { - oneSimplices.push_back({rowToVertex[rw], rowToVertex[v]}); - filteredEgdeIter.push({{rw, v}, 1}); - // if(rw == v) - // std::cout << "Pushed the edge {" << rw << ", " << v << "} " << std::endl; - } - } - } - } - // std::cout << "Total number of non-zero elements before domination check are: " << - // sparse_colpsd_adj_Matrix->nonZeros() << std::endl; std::cout << "Total number of edges for domination check are: - // " << filteredEgdeIter.size() << std::endl; - // std::cout << *sparse_colpsd_adj_Matrix << std::endl; - return; - } - - //! Function to fully compact a particular vertex of the ReductionMap. - /*! - It takes as argument the iterator corresponding to a particular vertex pair (key-value) stored in the ReductionMap. -
It then checks if the second element of this particular vertex pair is present as a first element of some other - key-value pair in the map. If no, then the first element of the vertex pair in consideration is fully compact. If - yes, then recursively call fully_compact_this_vertex() on the second element of the original pair in consideration - and assign its resultant image as the image of the first element of the original pair in consideration as well. - */ - void fully_compact_this_vertex(Map::iterator iter) { - Map::iterator found = ReductionMap.find(iter->second); - if (found == ReductionMap.end()) return; - - fully_compact_this_vertex(found); - iter->second = ReductionMap[iter->second]; - } - - //! Function to fully compact the Reduction Map. - /*! - While doing strong collapses, we store only the immediate collapse of a vertex. Which means that in one round, - vertex x may collapse to vertex y. And in some later round it may be possible that vertex y - collapses to z. In which case our map stores :
x -> y and also y -> z. But - it really should store : x -> z and y -> z. This function achieves the same.
It - basically calls fully_compact_this_vertex() for each entry in the map. - */ - void fully_compact() { - Map::iterator it = ReductionMap.begin(); - while (it != ReductionMap.end()) { - fully_compact_this_vertex(it); - it++; - } - } - - void sparse_strong_vertex_collapse() { - complete_vertex_domination_check( - rowIterator, rowInsertIndicator, - vertDomnIndicator); // Complete check for rows in rowIterator, rowInsertIndicator is a list of boolean - // indicator if a vertex is already inserted in the working row_queue (rowIterator) - if (not rowIterator.empty()) - sparse_strong_vertex_collapse(); - else - return; - } - - void complete_vertex_domination_check(doubleQueue& iterator, boolVector& insertIndicator, boolVector& domnIndicator) { - double k; - doubleVector nonZeroInnerIdcs; - while (not iterator.empty()) // "iterator" contains list(FIFO) of rows to be considered for domination check - { - k = iterator.front(); - iterator.pop(); - insertIndicator[k] = false; - if (not domnIndicator[k]) // Check if is already dominated - { - nonZeroInnerIdcs = closed_neighbours_row_index(k); - for (doubleVector::iterator it = nonZeroInnerIdcs.begin(); it != nonZeroInnerIdcs.end(); it++) { - int checkDom = vertex_domination_check(k, *it); // "true" for row domination comparison - if (checkDom == 1) // row k is dominated by *it, k <= *it; - { - setZero(k, *it); - break; - } else if (checkDom == -1) // row *it is dominated by k, *it <= k; - setZero(*it, k); - } - } - } - } - bool check_edge_domination(Edge e) // Edge e is the actual edge (u,v). Not the row ids in the matrixs { auto u = std::get<0>(e); @@ -456,22 +314,6 @@ class FlagComplexSpMatrix { std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; } - int vertex_domination_check(double i, double j) // True for row comparison, false for column comparison - { - if (i != j) { - doubleVector Listi = closed_neighbours_row_index(i); - doubleVector Listj = closed_neighbours_row_index(j); - if (Listj.size() <= Listi.size()) { - if (std::includes(Listi.begin(), Listi.end(), Listj.begin(), Listj.end())) // Listj is a subset of Listi - return -1; - } - - else if (std::includes(Listj.begin(), Listj.end(), Listi.begin(), Listi.end())) // Listi is a subset of Listj - return 1; - } - return 0; - } - doubleVector closed_neighbours_row_index(double indx) // Returns list of non-zero columns of the particular indx. { doubleVector nonZeroIndices; @@ -510,89 +352,13 @@ class FlagComplexSpMatrix { return common; } - void setZero(double dominated, double dominating) { - for (auto& v : closed_neighbours_row_index(dominated)) - if (not rowInsertIndicator[v]) // Checking if the row is already inserted - { - rowIterator.push(v); - rowInsertIndicator[v] = true; - } - vertDomnIndicator[dominated] = true; - ReductionMap[rowToVertex[dominated]] = rowToVertex[dominating]; - - vertexToRow.erase(rowToVertex[dominated]); - vertices.erase(rowToVertex[dominated]); - rowToVertex.erase(dominated); - } - - vertexVector closed_neighbours_vertex_index(double rowIndx) // Returns list of non-zero "vertices" of the particular - // colIndx. the difference is in the return type - { - vertexVector colmns; - for (auto& v : closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns - colmns.push_back(rowToVertex[v]); - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - vertexVector vertex_closed_active_neighbours( - double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx which are currently active. - // the difference is in the return type. - { - vertexVector colmns; - for (auto& v : closed_neighbours_row_index(rowIndx)) // Iterate over the non-zero columns - if (not contractionIndicator[v]) // Check if the row corresponds to a contracted vertex - colmns.push_back(rowToVertex[v]); - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - vertexVector closed_all_neighbours_row_index( - double rowIndx) // Returns list of all non-zero "vertices" of the particular colIndx whether dominated or not. - // the difference is in the return type. - { - vertexVector colmns; - for (rowInnerIterator itCol(sparseRowAdjMatrix, rowIndx); itCol; ++itCol) // Iterate over the non-zero columns - colmns.push_back(rowToVertex[itCol.index()]); // inner index, here it is equal to it.row() - std::sort(colmns.begin(), colmns.end()); - return colmns; - } - - void swap_rows(const Vertex& v, - const Vertex& w) { // swap the rows of v and w. Both should be members of the skeleton - if (membership(v) && membership(w)) { - auto rw_v = vertexToRow[v]; - auto rw_w = vertexToRow[w]; - vertexToRow[v] = rw_w; - vertexToRow[w] = rw_v; - rowToVertex[rw_v] = w; - rowToVertex[rw_w] = v; - } - } - public: - //! Default Constructor - /*! - Only initialises all Data Members of the class to empty/Null values as appropriate. - One WILL have to create the matrix using the Constructor that has an object of the Simplex_tree class as - argument. - */ - - FlagComplexSpMatrix() { init(); } - - FlagComplexSpMatrix(std::size_t expRows) { - init(); - sparseRowAdjMatrix = sparseRowMatrix( - expansion_limit * expRows, - expansion_limit * expRows); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - } - //! Main Constructor /*! Argument is an instance of Filtered_sorted_edge_list.
This is THE function that initialises all data members to appropriate values.
rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. - vertDomnIndicator, rowInsertIndicator ,rowIterator are initialised by init() function which is + vertDomnIndicator ,rowIterator are initialised by init() function which is called at the begining of this.
*/ FlagComplexSpMatrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) { @@ -616,84 +382,19 @@ class FlagComplexSpMatrix { */ ~FlagComplexSpMatrix() {} - //! Function for performing strong collapse. - /*! - calls sparse_strong_vertex_collapse(), and - Then, it compacts the ReductionMap by calling the function fully_compact(). - */ - double strong_vertex_collapse() { - auto begin_collapse = std::chrono::high_resolution_clock::now(); - sparse_strong_vertex_collapse(); - vertexCollapsed = true; - auto end_collapse = std::chrono::high_resolution_clock::now(); - - auto collapseTime = std::chrono::duration(end_collapse - begin_collapse).count(); - // std::cout << "Time of Collapse : " << collapseTime << " ms\n" << std::endl; - - // Now we complete the Reduction Map - fully_compact(); - // Post processing... - after_vertex_collapse(); - return collapseTime; - } - // Performs edge collapse in a decreasing sequence of the filtration value. Filtered_sorted_edge_list filtered_edge_collapse() { critical_core_edges(); - vertexCollapsed = false; edgeCollapsed = true; return criticalCoreEdges; } - // double strong_vertex_edge_collapse() { - // auto begin_collapse = std::chrono::high_resolution_clock::now(); - // strong_vertex_collapse(); - // strong_edge_collapse(); - // // strong_vertex_collapse(); - // auto end_collapse = std::chrono::high_resolution_clock::now(); - - // auto collapseTime = std::chrono::duration(end_collapse- begin_collapse).count(); - // return collapseTime; - // } - - bool membership(const Vertex& v) { - auto rw = vertexToRow.find(v); - if (rw != vertexToRow.end()) - return true; - else - return false; - } - - bool membership(const Edge& e) { - auto u = std::get<0>(e); - auto v = std::get<1>(e); - if (membership(u) && membership(v)) { - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - if (rw_u <= rw_v) - for (auto x : closed_neighbours_row_index(rw_v)) { // Taking advantage of sorted lists. - if (rw_u == x) - return true; - else if (rw_u < x) - return false; - } - else - for (auto x : closed_neighbours_row_index(rw_u)) { // Taking advantage of sorted lists. - if (rw_v == x) - return true; - else if (rw_v < x) - return false; - } - } - return false; - } void insert_vertex(const Vertex& vertex, double filt_val) { auto rw = vertexToRow.find(vertex); if (rw == vertexToRow.end()) { sparseRowAdjMatrix.insert(rows, rows) = filt_val; // Initializing the diagonal element of the adjency matrix corresponding to rw_b. vertDomnIndicator.push_back(false); - rowInsertIndicator.push_back(true); contractionIndicator.push_back(false); rowIterator.push(rows); vertexToRow.insert(std::make_pair(vertex, rows)); @@ -725,128 +426,4 @@ class FlagComplexSpMatrix { std::size_t num_vertices() const { return vertices.size(); } - //! Function for returning the ReductionMap. - /*! - This is the (stl's unordered) map that stores all the collapses of vertices.
- It is simply returned. - */ - - Map reduction_map() const { return ReductionMap; } - std::unordered_set vertex_set() const { return vertices; } - sparseRowMatrix collapsed_matrix() const { return *sparse_colpsd_adj_Matrix; } - - sparseRowMatrix uncollapsed_matrix() const { return sparseRowAdjMatrix; } - - edge_list all_edges() const { return oneSimplices; } - - vertexVector active_neighbors(const Vertex& v) { - vertexVector nb; - auto rw_v = vertexToRow.find(v); - if (rw_v != vertexToRow.end()) { - nb = vertex_closed_active_neighbours(rw_v->second); - } - return nb; - } - - vertexVector neighbors(const Vertex& v) { - vertexVector nb; - auto rw_v = vertexToRow.find(v); - if (rw_v != vertexToRow.end()) nb = closed_neighbours_vertex_index(rw_v->second); - - return nb; - } - - vertexVector active_relative_neighbors(const Vertex& v, const Vertex& w) { - std::vector diff; - if (membership(v) && membership(w)) { - auto nbhrs_v = active_neighbors(v); - auto nbhrs_w = active_neighbors(w); - std::set_difference(nbhrs_v.begin(), nbhrs_v.end(), nbhrs_w.begin(), nbhrs_w.end(), - std::inserter(diff, diff.begin())); - } - return diff; - } - - void contraction(const Vertex& del, const Vertex& keep) { - if (del != keep) { - bool del_mem = membership(del); - bool keep_mem = membership(keep); - if (del_mem && keep_mem) { - doubleVector del_indcs, keep_indcs, diff; - auto row_del = vertexToRow[del]; - auto row_keep = vertexToRow[keep]; - del_indcs = closed_neighbours_row_index(row_del); - keep_indcs = closed_neighbours_row_index(row_keep); - std::set_difference(del_indcs.begin(), del_indcs.end(), keep_indcs.begin(), keep_indcs.end(), - std::inserter(diff, diff.begin())); - for (auto& v : diff) { - if (v != row_del) { - sparseRowAdjMatrix.insert(row_keep, v) = 1; - sparseRowAdjMatrix.insert(v, row_keep) = 1; - } - } - vertexToRow.erase(del); - vertices.erase(del); - rowToVertex.erase(row_del); - // setZero(row_del->second, row_keep->second); - } else if (del_mem && not keep_mem) { - vertexToRow.insert(std::make_pair(keep, vertexToRow.find(del)->second)); - rowToVertex[vertexToRow.find(del)->second] = keep; - vertices.emplace(keep); - vertices.erase(del); - vertexToRow.erase(del); - - } else { - std::cerr << "The first vertex entered in the method contraction() doesn't exist in the skeleton." << std::endl; - exit(-1); - } - } - } - - void relable(const Vertex& v, const Vertex& w) { // relable v as w. - if (membership(v) and v != w) { - auto rw_v = vertexToRow[v]; - rowToVertex[rw_v] = w; - vertexToRow.insert(std::make_pair(w, rw_v)); - vertices.emplace(w); - vertexToRow.erase(v); - vertices.erase(v); - // std::cout<< "Re-named the vertex " << v << " as " << w << std::endl; - } - } - - // Returns the contracted edge. along with the contracted vertex in the begining of the list at {u,u} or {v,v} - - void active_strong_expansion(const Vertex& v, const Vertex& w, double filt_val) { - if (membership(v) && membership(w) && v != w) { - // std::cout << "Strong expansion of the vertex " << v << " and " << w << " begins. " << std::endl; - auto active_list_v_w = active_relative_neighbors(v, w); - auto active_list_w_v = active_relative_neighbors(w, v); - if (active_list_w_v.size() < - active_list_v_w.size()) { // simulate the contraction of w by expanding the star of v - for (auto& x : active_list_w_v) { - active_edge_insertion(v, x, filt_val); - // std::cout << "Inserted the edge " << v << " , " << x << std::endl; - } - swap_rows(v, w); - // std::cout << "A swap of the vertex " << v << " and " << w << "took place." << std::endl; - } else { - for (auto& y : active_list_v_w) { - active_edge_insertion(w, y, filt_val); - // std::cout << "Inserted the edge " << w << ", " << y << std::endl; - } - } - auto rw_v = vertexToRow.find(v); - contractionIndicator[rw_v->second] = true; - } - if (membership(v) && !membership(w)) { - relable(v, w); - } - } - void active_edge_insertion(const Vertex& v, const Vertex& w, double filt_val) { - insert_new_edges(v, w, filt_val); - // update_active_indicator(v,w); - } - - void print_sparse_skeleton() { std::cout << sparseRowAdjMatrix << std::endl; } }; \ No newline at end of file -- cgit v1.2.3 From b8332ff3846fe07b1a161fd87b8f7bcacbaa9cdf Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sun, 5 Apr 2020 10:12:45 +0200 Subject: Re-format comments and traces --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 134 ++++++++++++----------- 1 file changed, 72 insertions(+), 62 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index 20db7fae..ea43b986 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -78,8 +78,6 @@ class FlagComplexSpMatrix { // Vertices strored as an unordered_set std::unordered_set vertices; - //! Stores the 1-simplices(edges) of the original Simplicial Complex. - edge_list oneSimplices; // Unordered set of removed edges. (to enforce removal from the matrix) std::unordered_set> u_set_removed_redges; @@ -167,14 +165,8 @@ class FlagComplexSpMatrix { bool edgeCollapsed; - void init() { - rows = 0; - - numOneSimplices = 0; - edgeCollapsed = false; - } - - bool check_edge_domination(Edge e) // Edge e is the actual edge (u,v). Not the row ids in the matrixs + // Edge e is the actual edge (u,v). Not the row ids in the matrixs + bool check_edge_domination(Edge e) { auto u = std::get<0>(e); auto v = std::get<1>(e); @@ -182,13 +174,17 @@ class FlagComplexSpMatrix { auto rw_u = vertexToRow[u]; auto rw_v = vertexToRow[v]; auto rw_e = std::make_pair(rw_u, rw_v); - // std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; +#ifdef DEBUG_TRACES + std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; +#endif // DEBUG_TRACES auto commonNeighbours = closed_common_neighbours_row_index(rw_e); - // std::cout << "And its common neighbours are." << std::endl; - // for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - // std::cout << rowToVertex[*it] << ", " ; - // } - // std::cout<< std::endl; +#ifdef DEBUG_TRACES + std::cout << "And its common neighbours are." << std::endl; + for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + std::cout << rowToVertex[*it] << ", " ; + } + std::cout<< std::endl; +#endif // DEBUG_TRACES if (commonNeighbours.size() > 2) { if (commonNeighbours.size() == 3) return true; @@ -197,8 +193,9 @@ class FlagComplexSpMatrix { auto rw_c = *it; // Typecasting if (rw_c != rw_u and rw_c != rw_v) { auto neighbours_c = closed_neighbours_row_index(rw_c); + // If neighbours_c contains the common neighbours. if (std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), - commonNeighbours.end())) // If neighbours_c contains the common neighbours. + commonNeighbours.end())) return true; } } @@ -206,7 +203,8 @@ class FlagComplexSpMatrix { return false; } - bool check_domination_indicator(Edge e) // The edge should be sorted by the indices and indices are original + // The edge should be sorted by the indices and indices are original + bool check_domination_indicator(Edge e) { return dominated_edge_indicator[edge_to_index_map[e]]; } @@ -219,8 +217,10 @@ class FlagComplexSpMatrix { Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); - // std::cout << "The current critical edge to re-check criticality with filt value is : {" << u << "," << v << "}; - // "<< std::get<1>(fe) << std::endl; +#ifdef DEBUG_TRACES + std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v + << "} = " << std::get<1>(fe) << std::endl; +#endif // DEBUG_TRACES auto rw_u = vertexToRow[u]; auto rw_v = vertexToRow[v]; auto rw_critical_edge = std::make_pair(rw_u, rw_v); @@ -242,8 +242,10 @@ class FlagComplexSpMatrix { } void set_edge_critical(std::size_t indx, double filt) { - // std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << - // std::endl; +#ifdef DEBUG_TRACES + std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << + std::endl; +#endif // DEBUG_TRACES std::set effectedIndcs = three_clique_indices(indx); if (effectedIndcs.size() > 0) { for (auto idx = indx - 1; idx > 0; idx--) { @@ -251,12 +253,15 @@ class FlagComplexSpMatrix { Edge e = std::get<0>(fec); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); - if (not critical_edge_indicator.at( - idx)) { // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev - // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() - if (effectedIndcs.find(idx) != effectedIndcs.end()) { // If idx is affected + // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev + // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() + if (not critical_edge_indicator.at(idx)) { + // If idx is affected + if (effectedIndcs.find(idx) != effectedIndcs.end()) { if (not check_edge_domination(e)) { - // std::cout << "The curent index is became critical " << idx << std::endl; +#ifdef DEBUG_TRACES + std::cout << "The curent index became critical " << idx << std::endl; +#endif // DEBUG_TRACES critical_edge_indicator.at(idx) = true; criticalCoreEdges.push_back({filt, u, v}); std::set inner_effected_indcs = three_clique_indices(idx); @@ -264,11 +269,14 @@ class FlagComplexSpMatrix { if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); } inner_effected_indcs.clear(); - // std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << - // std::get<1>(e) << "}; " << filt << std::endl; +#ifdef DEBUG_TRACES + std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << + std::get<1>(e) << "}; " << filt << std::endl; +#endif // DEBUG_TRACES } else u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); - } else // Idx is not affected hence dominated. + } else + // Idx is not affected hence dominated. u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); } } @@ -289,8 +297,8 @@ class FlagComplexSpMatrix { while (endIdx < totEdges) { EdgeFilt fec = fEgdeVector.at(endIdx); - insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)), - std::get<1>(fec)); // Inserts the edge in the sparse matrix to update the graph (G_i) + // Inserts the edge in the sparse matrix to update the graph (G_i) + insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)), std::get<1>(fec)); Edge e = std::get<0>(fec); Vertex u = std::get<0>(e); @@ -310,25 +318,29 @@ class FlagComplexSpMatrix { endIdx++; } +#ifdef DEBUG_TRACES std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; +#endif // DEBUG_TRACES } - doubleVector closed_neighbours_row_index(double indx) // Returns list of non-zero columns of the particular indx. + // Returns list of non-zero columns of the particular indx. + doubleVector closed_neighbours_row_index(double indx) { doubleVector nonZeroIndices; Vertex u = indx; Vertex v; // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; if (not vertDomnIndicator[indx]) { - for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { // Iterate over the non-zero columns + // Iterate over the non-zero columns + for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { v = it.index(); + // If the vertex v is not dominated and the edge {u,v} is still in the matrix if (not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and - u_set_dominated_redges.find(std::minmax(u, v)) == - u_set_dominated_redges - .end()) { // If the vertex v is not dominated and the edge {u,v} is still in the matrix - nonZeroIndices.push_back(it.index()); // inner index, here it is equal to it.columns() - // std::cout << rowToVertex[it.index()] << ", " ; + u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { + // inner index, here it is equal to it.columns() + nonZeroIndices.push_back(it.index()); + // std::cout << rowToVertex[it.index()] << ", " ; } } // std::cout << std::endl; @@ -361,27 +373,19 @@ class FlagComplexSpMatrix { vertDomnIndicator ,rowIterator are initialised by init() function which is called at the begining of this.
*/ - FlagComplexSpMatrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) { - init(); - sparseRowAdjMatrix = sparseRowMatrix( - num_vertices, num_vertices); // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + FlagComplexSpMatrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) + : rows(0), + numOneSimplices(0), + edgeCollapsed(false) { + // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - // std::vector s = {std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}; - // insert_new_edges(std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx)), 1); fEgdeVector.push_back( {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); } - - // sparseRowAdjMatrix.makeCompressed(); } - //! Destructor. - /*! - Frees up memory locations on the heap. - */ - ~FlagComplexSpMatrix() {} - // Performs edge collapse in a decreasing sequence of the filtration value. Filtered_sorted_edge_list filtered_edge_collapse() { critical_core_edges(); @@ -392,8 +396,8 @@ class FlagComplexSpMatrix { void insert_vertex(const Vertex& vertex, double filt_val) { auto rw = vertexToRow.find(vertex); if (rw == vertexToRow.end()) { - sparseRowAdjMatrix.insert(rows, rows) = - filt_val; // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + sparseRowAdjMatrix.insert(rows, rows) = filt_val; vertDomnIndicator.push_back(false); contractionIndicator.push_back(false); rowIterator.push(rows); @@ -404,24 +408,30 @@ class FlagComplexSpMatrix { } } - void insert_new_edges(const Vertex& u, const Vertex& v, - double filt_val) // The edge must not be added before, it should be a new edge. + void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) { + // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); if (u != v) { insert_vertex(v, filt_val); - // std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; +#ifdef DEBUG_TRACES + std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES auto rw_u = vertexToRow.find(u); auto rw_v = vertexToRow.find(v); - // std::cout << "Inserting the edge " << u <<", " << v << std::endl; +#ifdef DEBUG_TRACES + std::cout << "Inserting the edge " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES sparseRowAdjMatrix.insert(rw_u->second, rw_v->second) = filt_val; sparseRowAdjMatrix.insert(rw_v->second, rw_u->second) = filt_val; - oneSimplices.emplace_back(u, v); numOneSimplices++; } - // else - // std::cout << "Already a member simplex, skipping..." << std::endl; +#ifdef DEBUG_TRACES + else { + std::cout << "Already a member simplex, skipping..." << std::endl; + } +#endif // DEBUG_TRACES } std::size_t num_vertices() const { return vertices.size(); } -- cgit v1.2.3 From a129158212bf63d04c341711d194414ad135baf4 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 08:37:48 +0200 Subject: Some cleanup --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 89 +++++++++++------------- src/Collapse/test/collapse_unit_test.cpp | 1 + 2 files changed, 43 insertions(+), 47 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h index ea43b986..32a6ad5c 100644 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h @@ -148,7 +148,7 @@ class FlagComplexSpMatrix { EdgeFiltQueue filteredEgdeIter; // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltVector fEgdeVector; + EdgeFiltVector f_edge_vector; // List of non-dominated edges, the indices of the edges are the vertex lables!!. Filtered_sorted_edge_list criticalCoreEdges; @@ -212,14 +212,13 @@ class FlagComplexSpMatrix { std::set three_clique_indices(std::size_t crit) { std::set edge_indices; - EdgeFilt fe = fEgdeVector.at(crit); - Edge e = std::get<0>(fe); + Edge e = std::get<0>(f_edge_vector[crit]); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); #ifdef DEBUG_TRACES std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v - << "} = " << std::get<1>(fe) << std::endl; + << "} = " << std::get<1>(f_edge_vector[crit]) << std::endl; #endif // DEBUG_TRACES auto rw_u = vertexToRow[u]; auto rw_v = vertexToRow[v]; @@ -249,8 +248,7 @@ class FlagComplexSpMatrix { std::set effectedIndcs = three_clique_indices(indx); if (effectedIndcs.size() > 0) { for (auto idx = indx - 1; idx > 0; idx--) { - EdgeFilt fec = fEgdeVector.at(idx); - Edge e = std::get<0>(fec); + Edge e = std::get<0>(f_edge_vector[idx]); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev @@ -285,45 +283,6 @@ class FlagComplexSpMatrix { u_set_dominated_redges.clear(); } - void critical_core_edges() { - std::size_t totEdges = fEgdeVector.size(); - - std::size_t endIdx = 0; - - u_set_removed_redges.clear(); - u_set_dominated_redges.clear(); - critical_edge_indicator.clear(); - - while (endIdx < totEdges) { - EdgeFilt fec = fEgdeVector.at(endIdx); - - // Inserts the edge in the sparse matrix to update the graph (G_i) - insert_new_edges(std::get<0>(std::get<0>(fec)), std::get<1>(std::get<0>(fec)), std::get<1>(fec)); - - Edge e = std::get<0>(fec); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - edge_to_index_map.emplace(std::minmax(u, v), endIdx); - critical_edge_indicator.push_back(false); - dominated_edge_indicator.push_back(false); - - if (not check_edge_domination(e)) { - critical_edge_indicator.at(endIdx) = true; - dominated_edge_indicator.at(endIdx) = false; - criticalCoreEdges.push_back({std::get<1>(fec), u, v}); - if (endIdx > 1) set_edge_critical(endIdx, std::get<1>(fec)); - - } else - dominated_edge_indicator.at(endIdx) = true; - endIdx++; - } - -#ifdef DEBUG_TRACES - std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; - std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; -#endif // DEBUG_TRACES - } - // Returns list of non-zero columns of the particular indx. doubleVector closed_neighbours_row_index(double indx) { @@ -381,14 +340,50 @@ class FlagComplexSpMatrix { sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - fEgdeVector.push_back( + f_edge_vector.push_back( {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); } } // Performs edge collapse in a decreasing sequence of the filtration value. Filtered_sorted_edge_list filtered_edge_collapse() { - critical_core_edges(); + std::size_t totEdges = f_edge_vector.size(); + + std::size_t endIdx = 0; + + u_set_removed_redges.clear(); + u_set_dominated_redges.clear(); + critical_edge_indicator.clear(); + + while (endIdx < totEdges) { + EdgeFilt fec = f_edge_vector[endIdx]; + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + double filt = std::get<1>(fec); + + // Inserts the edge in the sparse matrix to update the graph (G_i) + insert_new_edges(u, v, filt); + + edge_to_index_map.emplace(std::minmax(u, v), endIdx); + critical_edge_indicator.push_back(false); + dominated_edge_indicator.push_back(false); + + if (not check_edge_domination(e)) { + critical_edge_indicator.at(endIdx) = true; + dominated_edge_indicator.at(endIdx) = false; + criticalCoreEdges.push_back({filt, u, v}); + if (endIdx > 1) + set_edge_critical(endIdx, filt); + } else + dominated_edge_indicator.at(endIdx) = true; + endIdx++; + } + +#ifdef DEBUG_TRACES + std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; + std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; +#endif // DEBUG_TRACES edgeCollapsed = true; return criticalCoreEdges; } diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index b4bc0fc0..427c315e 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -75,6 +75,7 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt BOOST_CHECK(find_edge_in_list(edge_from_collapse, edges)); } + std::cout << "CHECK COLLAPSE - Total number of removed edges: " << removed_edges.size() << std::endl; for (auto removed_edge : removed_edges) { std::cout << "f[" << std::get<1>(removed_edge) << ", " << std::get<2>(removed_edge) << "] = " << std::get<0>(removed_edge) << std::endl; -- cgit v1.2.3 From 178a04c446400a501a7c40d8b6bcfadc542ce6bc Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 08:43:07 +0200 Subject: Some rename --- src/Collapse/include/gudhi/FlagComplexSpMatrix.h | 434 --------------------- .../include/gudhi/Flag_complex_sparse_matrix.h | 432 ++++++++++++++++++++ src/Collapse/test/collapse_unit_test.cpp | 4 +- ...tance_matrix_edge_collapse_rips_persistence.cpp | 4 +- .../point_cloud_edge_collapse_rips_persistence.cpp | 4 +- 5 files changed, 438 insertions(+), 440 deletions(-) delete mode 100644 src/Collapse/include/gudhi/FlagComplexSpMatrix.h create mode 100644 src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h b/src/Collapse/include/gudhi/FlagComplexSpMatrix.h deleted file mode 100644 index 32a6ad5c..00000000 --- a/src/Collapse/include/gudhi/FlagComplexSpMatrix.h +++ /dev/null @@ -1,434 +0,0 @@ -/* 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(s): Siddharth Pritam - * - * Copyright (C) 2018 INRIA Sophia Antipolis (France) - * - * 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 . - -*/ -#pragma once - -#include -#include -// #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -typedef std::size_t Vertex; -using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first - // element being the smaller i.e {2,3} not {3,2}. However this is at the level - // of row indices on actual vertex lables -using EdgeFilt = std::pair; -using edge_list = std::vector; - -using MapVertexToIndex = std::unordered_map; -using Map = std::unordered_map; - -using sparseRowMatrix = Eigen::SparseMatrix; -using rowInnerIterator = sparseRowMatrix::InnerIterator; - -using doubleVector = std::vector; -using vertexVector = std::vector; -using boolVector = std::vector; - -using doubleQueue = std::queue; - -using EdgeFiltQueue = std::queue; -using EdgeFiltVector = std::vector; - -typedef std::vector> Filtered_sorted_edge_list; -typedef std::unordered_map> u_edge_map; -typedef std::unordered_map> u_edge_to_idx_map; - -//! Class SparseMsMatrix -/*! - The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() - Algorithm. -*/ -class FlagComplexSpMatrix { - private: - std::unordered_map rowToVertex; - - // Vertices strored as an unordered_set - std::unordered_set vertices; - - // Unordered set of removed edges. (to enforce removal from the matrix) - std::unordered_set> u_set_removed_redges; - - // Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_redges; - - // Map from egde to its index - u_edge_to_idx_map edge_to_index_map; - // Boolean vector to indicate if the index is critical or not. - boolVector critical_edge_indicator; // critical indicator - - // Boolean vector to indicate if the index is critical or not. - boolVector dominated_edge_indicator; // domination indicator - - //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. - /*! - \code - MapVertexToIndex = std::unordered_map - \endcode - So, if the original simplex tree had vertices 0,1,4,5
- rowToVertex would store :
- \verbatim - Values = | 0 | 1 | 4 | 5 | - Indices = 0 1 2 3 - \endverbatim - And vertexToRow would be a map like the following :
- \verbatim - 0 -> 0 - 1 -> 1 - 4 -> 2 - 5 -> 3 - \endverbatim - */ - MapVertexToIndex vertexToRow; - - //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. - /*! - \code - sparseRowMatrix = Eigen::SparseMatrix ; - \endcode - ; - */ - - sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. - sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access - // to elements when traversing the matrix row-wise. - - //! Stores true for dominated rows and false for undominated rows. - /*! - Initialised to a vector of length equal to the value of the variable rows with all false values. - Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. - */ - boolVector vertDomnIndicator; //(domination indicator) - - boolVector contractionIndicator; //(contraction indicator) - - //! Stores the indices of the rows to-be checked for domination in the current iteration. - /*! - Initialised with all rows for the first iteration. - Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. - */ - // doubleQueue rowIterator; - - doubleQueue rowIterator; - - // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltQueue filteredEgdeIter; - - // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltVector f_edge_vector; - - // List of non-dominated edges, the indices of the edges are the vertex lables!!. - Filtered_sorted_edge_list criticalCoreEdges; - // Stores the indices from the sorted filtered edge vector. - // std::set recurCriticalCoreIndcs; - - //! Stores the number of vertices in the original Simplicial Complex. - /*! - This stores the count of vertices (which is also the number of rows in the Matrix). - */ - std::size_t rows; - - std::size_t numOneSimplices; - - bool edgeCollapsed; - - // Edge e is the actual edge (u,v). Not the row ids in the matrixs - bool check_edge_domination(Edge e) - { - auto u = std::get<0>(e); - auto v = std::get<1>(e); - - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - auto rw_e = std::make_pair(rw_u, rw_v); -#ifdef DEBUG_TRACES - std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; -#endif // DEBUG_TRACES - auto commonNeighbours = closed_common_neighbours_row_index(rw_e); -#ifdef DEBUG_TRACES - std::cout << "And its common neighbours are." << std::endl; - for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - std::cout << rowToVertex[*it] << ", " ; - } - std::cout<< std::endl; -#endif // DEBUG_TRACES - if (commonNeighbours.size() > 2) { - if (commonNeighbours.size() == 3) - return true; - else - for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { - auto rw_c = *it; // Typecasting - if (rw_c != rw_u and rw_c != rw_v) { - auto neighbours_c = closed_neighbours_row_index(rw_c); - // If neighbours_c contains the common neighbours. - if (std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), - commonNeighbours.end())) - return true; - } - } - } - return false; - } - - // The edge should be sorted by the indices and indices are original - bool check_domination_indicator(Edge e) - { - return dominated_edge_indicator[edge_to_index_map[e]]; - } - - std::set three_clique_indices(std::size_t crit) { - std::set edge_indices; - - Edge e = std::get<0>(f_edge_vector[crit]); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - -#ifdef DEBUG_TRACES - std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v - << "} = " << std::get<1>(f_edge_vector[crit]) << std::endl; -#endif // DEBUG_TRACES - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; - auto rw_critical_edge = std::make_pair(rw_u, rw_v); - - doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); - - if (commonNeighbours.size() > 2) { - for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { - auto rw_c = *it; - if (rw_c != rw_u and rw_c != rw_v) { - auto e_with_new_nbhr_v = std::minmax(u, rowToVertex[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v, rowToVertex[rw_c]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); - } - } - } - return edge_indices; - } - - void set_edge_critical(std::size_t indx, double filt) { -#ifdef DEBUG_TRACES - std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << - std::endl; -#endif // DEBUG_TRACES - std::set effectedIndcs = three_clique_indices(indx); - if (effectedIndcs.size() > 0) { - for (auto idx = indx - 1; idx > 0; idx--) { - Edge e = std::get<0>(f_edge_vector[idx]); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev - // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() - if (not critical_edge_indicator.at(idx)) { - // If idx is affected - if (effectedIndcs.find(idx) != effectedIndcs.end()) { - if (not check_edge_domination(e)) { -#ifdef DEBUG_TRACES - std::cout << "The curent index became critical " << idx << std::endl; -#endif // DEBUG_TRACES - critical_edge_indicator.at(idx) = true; - criticalCoreEdges.push_back({filt, u, v}); - std::set inner_effected_indcs = three_clique_indices(idx); - for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { - if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); - } - inner_effected_indcs.clear(); -#ifdef DEBUG_TRACES - std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << - std::get<1>(e) << "}; " << filt << std::endl; -#endif // DEBUG_TRACES - } else - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); - } else - // Idx is not affected hence dominated. - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); - } - } - } - effectedIndcs.clear(); - u_set_dominated_redges.clear(); - } - - // Returns list of non-zero columns of the particular indx. - doubleVector closed_neighbours_row_index(double indx) - { - doubleVector nonZeroIndices; - Vertex u = indx; - Vertex v; - // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; - if (not vertDomnIndicator[indx]) { - // Iterate over the non-zero columns - for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { - v = it.index(); - // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and - u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { - // inner index, here it is equal to it.columns() - nonZeroIndices.push_back(it.index()); - // std::cout << rowToVertex[it.index()] << ", " ; - } - } - // std::cout << std::endl; - } - return nonZeroIndices; - } - - doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. - { - doubleVector common; - doubleVector nonZeroIndices_u; - doubleVector nonZeroIndices_v; - double u = std::get<0>(e); - double v = std::get<1>(e); - - nonZeroIndices_u = closed_neighbours_row_index(u); - nonZeroIndices_v = closed_neighbours_row_index(v); - std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), - nonZeroIndices_v.end(), std::inserter(common, common.begin())); - - return common; - } - - public: - //! Main Constructor - /*! - Argument is an instance of Filtered_sorted_edge_list.
- This is THE function that initialises all data members to appropriate values.
- rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. - vertDomnIndicator ,rowIterator are initialised by init() function which is - called at the begining of this.
- */ - FlagComplexSpMatrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) - : rows(0), - numOneSimplices(0), - edgeCollapsed(false) { - // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); - - for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - f_edge_vector.push_back( - {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); - } - } - - // Performs edge collapse in a decreasing sequence of the filtration value. - Filtered_sorted_edge_list filtered_edge_collapse() { - std::size_t totEdges = f_edge_vector.size(); - - std::size_t endIdx = 0; - - u_set_removed_redges.clear(); - u_set_dominated_redges.clear(); - critical_edge_indicator.clear(); - - while (endIdx < totEdges) { - EdgeFilt fec = f_edge_vector[endIdx]; - Edge e = std::get<0>(fec); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - double filt = std::get<1>(fec); - - // Inserts the edge in the sparse matrix to update the graph (G_i) - insert_new_edges(u, v, filt); - - edge_to_index_map.emplace(std::minmax(u, v), endIdx); - critical_edge_indicator.push_back(false); - dominated_edge_indicator.push_back(false); - - if (not check_edge_domination(e)) { - critical_edge_indicator.at(endIdx) = true; - dominated_edge_indicator.at(endIdx) = false; - criticalCoreEdges.push_back({filt, u, v}); - if (endIdx > 1) - set_edge_critical(endIdx, filt); - } else - dominated_edge_indicator.at(endIdx) = true; - endIdx++; - } - -#ifdef DEBUG_TRACES - std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; - std::cout << "The total number of non-critical edges is: " << totEdges - criticalCoreEdges.size() << std::endl; -#endif // DEBUG_TRACES - edgeCollapsed = true; - return criticalCoreEdges; - } - - void insert_vertex(const Vertex& vertex, double filt_val) { - auto rw = vertexToRow.find(vertex); - if (rw == vertexToRow.end()) { - // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparseRowAdjMatrix.insert(rows, rows) = filt_val; - vertDomnIndicator.push_back(false); - contractionIndicator.push_back(false); - rowIterator.push(rows); - vertexToRow.insert(std::make_pair(vertex, rows)); - rowToVertex.insert(std::make_pair(rows, vertex)); - vertices.emplace(vertex); - rows++; - } - } - - void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) - { - // The edge must not be added before, it should be a new edge. - insert_vertex(u, filt_val); - if (u != v) { - insert_vertex(v, filt_val); -#ifdef DEBUG_TRACES - std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - - auto rw_u = vertexToRow.find(u); - auto rw_v = vertexToRow.find(v); -#ifdef DEBUG_TRACES - std::cout << "Inserting the edge " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - sparseRowAdjMatrix.insert(rw_u->second, rw_v->second) = filt_val; - sparseRowAdjMatrix.insert(rw_v->second, rw_u->second) = filt_val; - numOneSimplices++; - } -#ifdef DEBUG_TRACES - else { - std::cout << "Already a member simplex, skipping..." << std::endl; - } -#endif // DEBUG_TRACES - } - - std::size_t num_vertices() const { return vertices.size(); } - -}; \ No newline at end of file diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h new file mode 100644 index 00000000..7bbe86c4 --- /dev/null +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -0,0 +1,432 @@ +/* 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(s): Siddharth Pritam + * + * Copyright (C) 2018 INRIA Sophia Antipolis (France) + * + * 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 . + +*/ +#pragma once + +#include +#include +// #include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +typedef std::size_t Vertex; +using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first + // element being the smaller i.e {2,3} not {3,2}. However this is at the level + // of row indices on actual vertex lables +using EdgeFilt = std::pair; +using edge_list = std::vector; + +using MapVertexToIndex = std::unordered_map; +using Map = std::unordered_map; + +using sparseRowMatrix = Eigen::SparseMatrix; +using rowInnerIterator = sparseRowMatrix::InnerIterator; + +using doubleVector = std::vector; +using vertexVector = std::vector; +using boolVector = std::vector; + +using doubleQueue = std::queue; + +using EdgeFiltQueue = std::queue; +using EdgeFiltVector = std::vector; + +typedef std::vector> Filtered_sorted_edge_list; +typedef std::unordered_map> u_edge_map; +typedef std::unordered_map> u_edge_to_idx_map; + +//! Class SparseMsMatrix +/*! + The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() + Algorithm. +*/ +class Flag_complex_sparse_matrix { + private: + std::unordered_map rowToVertex; + + // Vertices strored as an unordered_set + std::unordered_set vertices; + + // Unordered set of removed edges. (to enforce removal from the matrix) + std::unordered_set> u_set_removed_redges; + + // Unordered set of dominated edges. (to inforce removal from the matrix) + std::unordered_set> u_set_dominated_redges; + + // Map from egde to its index + u_edge_to_idx_map edge_to_index_map; + // Boolean vector to indicate if the index is critical or not. + boolVector critical_edge_indicator; // critical indicator + + // Boolean vector to indicate if the index is critical or not. + boolVector dominated_edge_indicator; // domination indicator + + //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. + /*! + \code + MapVertexToIndex = std::unordered_map + \endcode + So, if the original simplex tree had vertices 0,1,4,5
+ rowToVertex would store :
+ \verbatim + Values = | 0 | 1 | 4 | 5 | + Indices = 0 1 2 3 + \endverbatim + And vertexToRow would be a map like the following :
+ \verbatim + 0 -> 0 + 1 -> 1 + 4 -> 2 + 5 -> 3 + \endverbatim + */ + MapVertexToIndex vertexToRow; + + //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. + /*! + \code + sparseRowMatrix = Eigen::SparseMatrix ; + \endcode + ; + */ + + sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. + sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access + // to elements when traversing the matrix row-wise. + + //! Stores true for dominated rows and false for undominated rows. + /*! + Initialised to a vector of length equal to the value of the variable rows with all false values. + Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. + */ + boolVector vertDomnIndicator; //(domination indicator) + + boolVector contractionIndicator; //(contraction indicator) + + //! Stores the indices of the rows to-be checked for domination in the current iteration. + /*! + Initialised with all rows for the first iteration. + Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. + */ + // doubleQueue rowIterator; + + doubleQueue rowIterator; + + // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltQueue filteredEgdeIter; + + // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + EdgeFiltVector f_edge_vector; + + // List of non-dominated edges, the indices of the edges are the vertex lables!!. + Filtered_sorted_edge_list criticalCoreEdges; + // Stores the indices from the sorted filtered edge vector. + // std::set recurCriticalCoreIndcs; + + //! Stores the number of vertices in the original Simplicial Complex. + /*! + This stores the count of vertices (which is also the number of rows in the Matrix). + */ + std::size_t rows; + + std::size_t numOneSimplices; + + bool edgeCollapsed; + + // Edge e is the actual edge (u,v). Not the row ids in the matrixs + bool check_edge_domination(Edge e) + { + auto u = std::get<0>(e); + auto v = std::get<1>(e); + + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_e = std::make_pair(rw_u, rw_v); +#ifdef DEBUG_TRACES + std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; +#endif // DEBUG_TRACES + auto commonNeighbours = closed_common_neighbours_row_index(rw_e); +#ifdef DEBUG_TRACES + std::cout << "And its common neighbours are." << std::endl; + for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { + std::cout << rowToVertex[*it] << ", " ; + } + std::cout<< std::endl; +#endif // DEBUG_TRACES + if (commonNeighbours.size() > 2) { + if (commonNeighbours.size() == 3) + return true; + else + for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { + auto rw_c = *it; // Typecasting + if (rw_c != rw_u and rw_c != rw_v) { + auto neighbours_c = closed_neighbours_row_index(rw_c); + // If neighbours_c contains the common neighbours. + if (std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), + commonNeighbours.end())) + return true; + } + } + } + return false; + } + + // The edge should be sorted by the indices and indices are original + bool check_domination_indicator(Edge e) + { + return dominated_edge_indicator[edge_to_index_map[e]]; + } + + std::set three_clique_indices(std::size_t crit) { + std::set edge_indices; + + Edge e = std::get<0>(f_edge_vector[crit]); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + +#ifdef DEBUG_TRACES + std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v + << "} = " << std::get<1>(f_edge_vector[crit]) << std::endl; +#endif // DEBUG_TRACES + auto rw_u = vertexToRow[u]; + auto rw_v = vertexToRow[v]; + auto rw_critical_edge = std::make_pair(rw_u, rw_v); + + doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); + + if (commonNeighbours.size() > 2) { + for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { + auto rw_c = *it; + if (rw_c != rw_u and rw_c != rw_v) { + auto e_with_new_nbhr_v = std::minmax(u, rowToVertex[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v, rowToVertex[rw_c]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); + edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); + } + } + } + return edge_indices; + } + + void set_edge_critical(std::size_t indx, double filt) { +#ifdef DEBUG_TRACES + std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << + std::endl; +#endif // DEBUG_TRACES + std::set effectedIndcs = three_clique_indices(indx); + if (effectedIndcs.size() > 0) { + for (auto idx = indx - 1; idx > 0; idx--) { + Edge e = std::get<0>(f_edge_vector[idx]); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev + // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() + if (not critical_edge_indicator.at(idx)) { + // If idx is affected + if (effectedIndcs.find(idx) != effectedIndcs.end()) { + if (not check_edge_domination(e)) { +#ifdef DEBUG_TRACES + std::cout << "The curent index became critical " << idx << std::endl; +#endif // DEBUG_TRACES + critical_edge_indicator.at(idx) = true; + criticalCoreEdges.push_back({filt, u, v}); + std::set inner_effected_indcs = three_clique_indices(idx); + for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { + if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); + } + inner_effected_indcs.clear(); +#ifdef DEBUG_TRACES + std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << + std::get<1>(e) << "}; " << filt << std::endl; +#endif // DEBUG_TRACES + } else + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + } else + // Idx is not affected hence dominated. + u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + } + } + } + effectedIndcs.clear(); + u_set_dominated_redges.clear(); + } + + // Returns list of non-zero columns of the particular indx. + doubleVector closed_neighbours_row_index(double indx) + { + doubleVector nonZeroIndices; + Vertex u = indx; + Vertex v; + // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; + if (not vertDomnIndicator[indx]) { + // Iterate over the non-zero columns + for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { + v = it.index(); + // If the vertex v is not dominated and the edge {u,v} is still in the matrix + if (not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and + u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { + // inner index, here it is equal to it.columns() + nonZeroIndices.push_back(it.index()); + // std::cout << rowToVertex[it.index()] << ", " ; + } + } + // std::cout << std::endl; + } + return nonZeroIndices; + } + + doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. + { + doubleVector common; + doubleVector nonZeroIndices_u; + doubleVector nonZeroIndices_v; + double u = std::get<0>(e); + double v = std::get<1>(e); + + nonZeroIndices_u = closed_neighbours_row_index(u); + nonZeroIndices_v = closed_neighbours_row_index(v); + std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), + nonZeroIndices_v.end(), std::inserter(common, common.begin())); + + return common; + } + + public: + //! Main Constructor + /*! + Argument is an instance of Filtered_sorted_edge_list.
+ This is THE function that initialises all data members to appropriate values.
+ rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. + vertDomnIndicator ,rowIterator are initialised by init() function which is + called at the begining of this.
+ */ + Flag_complex_sparse_matrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) + : rows(0), + numOneSimplices(0), + edgeCollapsed(false) { + // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. + sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); + + for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { + f_edge_vector.push_back( + {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); + } + } + + // Performs edge collapse in a decreasing sequence of the filtration value. + Filtered_sorted_edge_list filtered_edge_collapse() { + std::size_t endIdx = 0; + + u_set_removed_redges.clear(); + u_set_dominated_redges.clear(); + critical_edge_indicator.clear(); + + while (endIdx < f_edge_vector.size()) { + EdgeFilt fec = f_edge_vector[endIdx]; + Edge e = std::get<0>(fec); + Vertex u = std::get<0>(e); + Vertex v = std::get<1>(e); + double filt = std::get<1>(fec); + + // Inserts the edge in the sparse matrix to update the graph (G_i) + insert_new_edges(u, v, filt); + + edge_to_index_map.emplace(std::minmax(u, v), endIdx); + critical_edge_indicator.push_back(false); + dominated_edge_indicator.push_back(false); + + if (not check_edge_domination(e)) { + critical_edge_indicator.at(endIdx) = true; + dominated_edge_indicator.at(endIdx) = false; + criticalCoreEdges.push_back({filt, u, v}); + if (endIdx > 1) + set_edge_critical(endIdx, filt); + } else + dominated_edge_indicator.at(endIdx) = true; + endIdx++; + } + +#ifdef DEBUG_TRACES + std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; + std::cout << "The total number of non-critical edges is: " << f_edge_vector.size() - criticalCoreEdges.size() << std::endl; +#endif // DEBUG_TRACES + edgeCollapsed = true; + return criticalCoreEdges; + } + + void insert_vertex(const Vertex& vertex, double filt_val) { + auto rw = vertexToRow.find(vertex); + if (rw == vertexToRow.end()) { + // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + sparseRowAdjMatrix.insert(rows, rows) = filt_val; + vertDomnIndicator.push_back(false); + contractionIndicator.push_back(false); + rowIterator.push(rows); + vertexToRow.insert(std::make_pair(vertex, rows)); + rowToVertex.insert(std::make_pair(rows, vertex)); + vertices.emplace(vertex); + rows++; + } + } + + void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) + { + // The edge must not be added before, it should be a new edge. + insert_vertex(u, filt_val); + if (u != v) { + insert_vertex(v, filt_val); +#ifdef DEBUG_TRACES + std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES + + auto rw_u = vertexToRow.find(u); + auto rw_v = vertexToRow.find(v); +#ifdef DEBUG_TRACES + std::cout << "Inserting the edge " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES + sparseRowAdjMatrix.insert(rw_u->second, rw_v->second) = filt_val; + sparseRowAdjMatrix.insert(rw_v->second, rw_u->second) = filt_val; + numOneSimplices++; + } +#ifdef DEBUG_TRACES + else { + std::cout << "Already a member simplex, skipping..." << std::endl; + } +#endif // DEBUG_TRACES + } + + std::size_t num_vertices() const { return vertices.size(); } + +}; \ No newline at end of file diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 427c315e..67f35e89 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -25,7 +25,7 @@ // ^ // /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. -#include "gudhi/FlagComplexSpMatrix.h" +#include "gudhi/Flag_complex_sparse_matrix.h" #include "gudhi/Rips_edge_list.h" #include "gudhi/graph_simplicial_complex.h" #include "gudhi/distance_functions.h" @@ -64,7 +64,7 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt std::cout << "f[" << std::get<1>(edge) << ", " << std::get<2>(edge) << "] = " << std::get<0>(edge) << std::endl; } - FlagComplexSpMatrix flag_complex_sparse_matrix(5, edges); + Flag_complex_sparse_matrix flag_complex_sparse_matrix(5, edges); auto collapse_edges = flag_complex_sparse_matrix.filtered_edge_collapse(); std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; BOOST_CHECK(collapse_edges.size() <= edges.size()); diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 63c91ebc..75eb6d67 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -131,7 +131,7 @@ int main(int argc, char* argv[]) { // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - FlagComplexSpMatrix mat_filt_edge_coll(number_of_points, edge_t); + Flag_complex_sparse_matrix mat_filt_edge_coll(number_of_points, edge_t); std::cout << "Matrix instansiated" << std::endl; Filtered_sorted_edge_list collapse_edges; collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index af08477c..b316391b 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -115,7 +115,7 @@ int main(int argc, char* argv[]) { // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - FlagComplexSpMatrix mat_filt_edge_coll(number_of_points, edge_t); + Flag_complex_sparse_matrix mat_filt_edge_coll(number_of_points, edge_t); std::cout << "Matrix instansiated" << std::endl; Filtered_sorted_edge_list collapse_edges; collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); -- cgit v1.2.3 From eaa2ce2a1e28dc7a9c55a801d53da04ce5f58a29 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 09:20:39 +0200 Subject: Some rename variables and cleanup --- .../include/gudhi/Flag_complex_sparse_matrix.h | 141 +++++++++------------ 1 file changed, 59 insertions(+), 82 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 7bbe86c4..ba4cd05e 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -1,26 +1,15 @@ -/* This file is part of the Gudhi Library. The Gudhi library - * (Geometric Understanding in Higher Dimensions) is a generic C++ - * library for computational topology. - * +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Siddharth Pritam * - * Copyright (C) 2018 INRIA Sophia Antipolis (France) - * - * 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. + * Copyright (C) 2018 Inria * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ -*/ -#pragma once +#ifndef FLAG_COMPLEX_SPARSE_MATRIX_H_ +#define FLAG_COMPLEX_SPARSE_MATRIX_H_ #include #include @@ -58,9 +47,6 @@ using doubleVector = std::vector; using vertexVector = std::vector; using boolVector = std::vector; -using doubleQueue = std::queue; - -using EdgeFiltQueue = std::queue; using EdgeFiltVector = std::vector; typedef std::vector> Filtered_sorted_edge_list; @@ -74,7 +60,7 @@ typedef std::unordered_map> u_edge_to_idx_m */ class Flag_complex_sparse_matrix { private: - std::unordered_map rowToVertex; + std::unordered_map row_to_vertex; // Vertices strored as an unordered_set std::unordered_set vertices; @@ -93,18 +79,18 @@ class Flag_complex_sparse_matrix { // Boolean vector to indicate if the index is critical or not. boolVector dominated_edge_indicator; // domination indicator - //! Stores the Map between verticesrowToVertex and row indices rowToVertex -> row-index. + //! Stores the Map between verticesrow_to_vertex and row indices row_to_vertex -> row-index. /*! \code MapVertexToIndex = std::unordered_map \endcode So, if the original simplex tree had vertices 0,1,4,5
- rowToVertex would store :
+ row_to_vertex would store :
\verbatim Values = | 0 | 1 | 4 | 5 | Indices = 0 1 2 3 \endverbatim - And vertexToRow would be a map like the following :
+ And vertex_to_row would be a map like the following :
\verbatim 0 -> 0 1 -> 1 @@ -112,7 +98,7 @@ class Flag_complex_sparse_matrix { 5 -> 3 \endverbatim */ - MapVertexToIndex vertexToRow; + MapVertexToIndex vertex_to_row; //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. /*! @@ -122,8 +108,7 @@ class Flag_complex_sparse_matrix { ; */ - sparseRowMatrix* sparse_colpsd_adj_Matrix; // Stores the collapsed sparse matrix representaion. - sparseRowMatrix sparseRowAdjMatrix; // This is row-major version of the same sparse-matrix, to facilitate easy access + sparseRowMatrix sparse_row_adjacency_matrix; // This is row-major version of the same sparse-matrix, to facilitate easy access // to elements when traversing the matrix row-wise. //! Stores true for dominated rows and false for undominated rows. @@ -131,27 +116,13 @@ class Flag_complex_sparse_matrix { Initialised to a vector of length equal to the value of the variable rows with all false values. Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. */ - boolVector vertDomnIndicator; //(domination indicator) - - boolVector contractionIndicator; //(contraction indicator) - - //! Stores the indices of the rows to-be checked for domination in the current iteration. - /*! - Initialised with all rows for the first iteration. - Subsequently once a dominated row is found, its non-dominated neighbhour indices are inserted. - */ - // doubleQueue rowIterator; - - doubleQueue rowIterator; - - // Queue of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltQueue filteredEgdeIter; + boolVector domination_indicator; //(domination indicator) // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. EdgeFiltVector f_edge_vector; // List of non-dominated edges, the indices of the edges are the vertex lables!!. - Filtered_sorted_edge_list criticalCoreEdges; + Filtered_sorted_edge_list critical_core_edges; // Stores the indices from the sorted filtered edge vector. // std::set recurCriticalCoreIndcs; @@ -171,8 +142,8 @@ class Flag_complex_sparse_matrix { auto u = std::get<0>(e); auto v = std::get<1>(e); - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; + auto rw_u = vertex_to_row[u]; + auto rw_v = vertex_to_row[v]; auto rw_e = std::make_pair(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; @@ -181,7 +152,7 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "And its common neighbours are." << std::endl; for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - std::cout << rowToVertex[*it] << ", " ; + std::cout << row_to_vertex[*it] << ", " ; } std::cout<< std::endl; #endif // DEBUG_TRACES @@ -220,8 +191,8 @@ class Flag_complex_sparse_matrix { std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v << "} = " << std::get<1>(f_edge_vector[crit]) << std::endl; #endif // DEBUG_TRACES - auto rw_u = vertexToRow[u]; - auto rw_v = vertexToRow[v]; + auto rw_u = vertex_to_row[u]; + auto rw_v = vertex_to_row[v]; auto rw_critical_edge = std::make_pair(rw_u, rw_v); doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); @@ -230,8 +201,8 @@ class Flag_complex_sparse_matrix { for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { auto rw_c = *it; if (rw_c != rw_u and rw_c != rw_v) { - auto e_with_new_nbhr_v = std::minmax(u, rowToVertex[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v, rowToVertex[rw_c]); + auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex[rw_c]); edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); } @@ -261,7 +232,7 @@ class Flag_complex_sparse_matrix { std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES critical_edge_indicator.at(idx) = true; - criticalCoreEdges.push_back({filt, u, v}); + critical_core_edges.push_back({filt, u, v}); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); @@ -272,10 +243,10 @@ class Flag_complex_sparse_matrix { std::get<1>(e) << "}; " << filt << std::endl; #endif // DEBUG_TRACES } else - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + u_set_dominated_redges.emplace(std::minmax(vertex_to_row[u], vertex_to_row[v])); } else // Idx is not affected hence dominated. - u_set_dominated_redges.emplace(std::minmax(vertexToRow[u], vertexToRow[v])); + u_set_dominated_redges.emplace(std::minmax(vertex_to_row[u], vertex_to_row[v])); } } } @@ -289,20 +260,26 @@ class Flag_complex_sparse_matrix { doubleVector nonZeroIndices; Vertex u = indx; Vertex v; - // std::cout << "The neighbours of the vertex: " << rowToVertex[u] << " are. " << std::endl; - if (not vertDomnIndicator[indx]) { +#ifdef DEBUG_TRACES + std::cout << "The neighbours of the vertex: " << row_to_vertex[u] << " are. " << std::endl; +#endif // DEBUG_TRACES + if (not domination_indicator[indx]) { // Iterate over the non-zero columns - for (rowInnerIterator it(sparseRowAdjMatrix, indx); it; ++it) { + for (rowInnerIterator it(sparse_row_adjacency_matrix, indx); it; ++it) { v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not vertDomnIndicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and + if (not domination_indicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { // inner index, here it is equal to it.columns() nonZeroIndices.push_back(it.index()); - // std::cout << rowToVertex[it.index()] << ", " ; +#ifdef DEBUG_TRACES + std::cout << row_to_vertex[it.index()] << ", " ; +#endif // DEBUG_TRACES } } - // std::cout << std::endl; +#ifdef DEBUG_TRACES + std::cout << std::endl; +#endif // DEBUG_TRACES } return nonZeroIndices; } @@ -328,16 +305,16 @@ class Flag_complex_sparse_matrix { /*! Argument is an instance of Filtered_sorted_edge_list.
This is THE function that initialises all data members to appropriate values.
- rowToVertex, vertexToRow, rows, cols, sparseRowAdjMatrix are initialised here. - vertDomnIndicator ,rowIterator are initialised by init() function which is + row_to_vertex, vertex_to_row, rows, cols, sparse_row_adjacency_matrix are initialised here. + domination_indicator are initialised by init() function which is called at the begining of this.
*/ Flag_complex_sparse_matrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) : rows(0), numOneSimplices(0), edgeCollapsed(false) { - // Initializing sparseRowAdjMatrix, This is a row-major sparse matrix. - sparseRowAdjMatrix = sparseRowMatrix(num_vertices, num_vertices); + // Initializing sparse_row_adjacency_matrix, This is a row-major sparse matrix. + sparse_row_adjacency_matrix = sparseRowMatrix(num_vertices, num_vertices); for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { f_edge_vector.push_back( @@ -370,7 +347,7 @@ class Flag_complex_sparse_matrix { if (not check_edge_domination(e)) { critical_edge_indicator.at(endIdx) = true; dominated_edge_indicator.at(endIdx) = false; - criticalCoreEdges.push_back({filt, u, v}); + critical_core_edges.push_back({filt, u, v}); if (endIdx > 1) set_edge_critical(endIdx, filt); } else @@ -379,23 +356,21 @@ class Flag_complex_sparse_matrix { } #ifdef DEBUG_TRACES - std::cout << "The total number of critical edges is: " << criticalCoreEdges.size() << std::endl; - std::cout << "The total number of non-critical edges is: " << f_edge_vector.size() - criticalCoreEdges.size() << std::endl; + std::cout << "The total number of critical edges is: " << critical_core_edges.size() << std::endl; + std::cout << "The total number of non-critical edges is: " << f_edge_vector.size() - critical_core_edges.size() << std::endl; #endif // DEBUG_TRACES edgeCollapsed = true; - return criticalCoreEdges; + return critical_core_edges; } void insert_vertex(const Vertex& vertex, double filt_val) { - auto rw = vertexToRow.find(vertex); - if (rw == vertexToRow.end()) { + auto rw = vertex_to_row.find(vertex); + if (rw == vertex_to_row.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparseRowAdjMatrix.insert(rows, rows) = filt_val; - vertDomnIndicator.push_back(false); - contractionIndicator.push_back(false); - rowIterator.push(rows); - vertexToRow.insert(std::make_pair(vertex, rows)); - rowToVertex.insert(std::make_pair(rows, vertex)); + sparse_row_adjacency_matrix.insert(rows, rows) = filt_val; + domination_indicator.push_back(false); + vertex_to_row.insert(std::make_pair(vertex, rows)); + row_to_vertex.insert(std::make_pair(rows, vertex)); vertices.emplace(vertex); rows++; } @@ -411,13 +386,13 @@ class Flag_complex_sparse_matrix { std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - auto rw_u = vertexToRow.find(u); - auto rw_v = vertexToRow.find(v); + auto rw_u = vertex_to_row.find(u); + auto rw_v = vertex_to_row.find(v); #ifdef DEBUG_TRACES std::cout << "Inserting the edge " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - sparseRowAdjMatrix.insert(rw_u->second, rw_v->second) = filt_val; - sparseRowAdjMatrix.insert(rw_v->second, rw_u->second) = filt_val; + sparse_row_adjacency_matrix.insert(rw_u->second, rw_v->second) = filt_val; + sparse_row_adjacency_matrix.insert(rw_v->second, rw_u->second) = filt_val; numOneSimplices++; } #ifdef DEBUG_TRACES @@ -429,4 +404,6 @@ class Flag_complex_sparse_matrix { std::size_t num_vertices() const { return vertices.size(); } -}; \ No newline at end of file +}; + +#endif // FLAG_COMPLEX_SPARSE_MATRIX_H_ \ No newline at end of file -- cgit v1.2.3 From 5a3c20d419dee546e2eefe1081f8ae2ce509b2e2 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 09:35:40 +0200 Subject: Rename some variables --- .../include/gudhi/Flag_complex_sparse_matrix.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ba4cd05e..57151371 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -257,7 +257,7 @@ class Flag_complex_sparse_matrix { // Returns list of non-zero columns of the particular indx. doubleVector closed_neighbours_row_index(double indx) { - doubleVector nonZeroIndices; + doubleVector non_zero_indices; Vertex u = indx; Vertex v; #ifdef DEBUG_TRACES @@ -271,7 +271,7 @@ class Flag_complex_sparse_matrix { if (not domination_indicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { // inner index, here it is equal to it.columns() - nonZeroIndices.push_back(it.index()); + non_zero_indices.push_back(it.index()); #ifdef DEBUG_TRACES std::cout << row_to_vertex[it.index()] << ", " ; #endif // DEBUG_TRACES @@ -281,21 +281,21 @@ class Flag_complex_sparse_matrix { std::cout << std::endl; #endif // DEBUG_TRACES } - return nonZeroIndices; + return non_zero_indices; } doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. { doubleVector common; - doubleVector nonZeroIndices_u; - doubleVector nonZeroIndices_v; + doubleVector non_zero_indices_u; + doubleVector non_zero_indices_v; double u = std::get<0>(e); double v = std::get<1>(e); - nonZeroIndices_u = closed_neighbours_row_index(u); - nonZeroIndices_v = closed_neighbours_row_index(v); - std::set_intersection(nonZeroIndices_u.begin(), nonZeroIndices_u.end(), nonZeroIndices_v.begin(), - nonZeroIndices_v.end(), std::inserter(common, common.begin())); + non_zero_indices_u = closed_neighbours_row_index(u); + non_zero_indices_v = closed_neighbours_row_index(v); + std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), + non_zero_indices_v.end(), std::inserter(common, common.begin())); return common; } -- cgit v1.2.3 From 076cc203005373ddcb58055af3db604240157601 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 15:01:38 +0200 Subject: remove num_vertices from flag complex sparse matrix constructor as demanded by Marc in strong complex review. Some cleanup --- .../include/gudhi/Flag_complex_sparse_matrix.h | 24 ++++++++++------------ src/Collapse/test/collapse_unit_test.cpp | 22 +++----------------- ...tance_matrix_edge_collapse_rips_persistence.cpp | 2 +- .../point_cloud_edge_collapse_rips_persistence.cpp | 2 +- 4 files changed, 16 insertions(+), 34 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 57151371..786a970a 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -62,7 +62,7 @@ class Flag_complex_sparse_matrix { private: std::unordered_map row_to_vertex; - // Vertices strored as an unordered_set + // Vertices stored as an unordered_set std::unordered_set vertices; // Unordered set of removed edges. (to enforce removal from the matrix) @@ -132,8 +132,6 @@ class Flag_complex_sparse_matrix { */ std::size_t rows; - std::size_t numOneSimplices; - bool edgeCollapsed; // Edge e is the actual edge (u,v). Not the row ids in the matrixs @@ -309,16 +307,15 @@ class Flag_complex_sparse_matrix { domination_indicator are initialised by init() function which is called at the begining of this.
*/ - Flag_complex_sparse_matrix(const size_t& num_vertices, const Filtered_sorted_edge_list& edge_t) + Flag_complex_sparse_matrix(const Filtered_sorted_edge_list& edge_t) : rows(0), - numOneSimplices(0), edgeCollapsed(false) { - // Initializing sparse_row_adjacency_matrix, This is a row-major sparse matrix. - sparse_row_adjacency_matrix = sparseRowMatrix(num_vertices, num_vertices); - for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - f_edge_vector.push_back( - {{std::get<1>(edge_t.at(bgn_idx)), std::get<2>(edge_t.at(bgn_idx))}, std::get<0>(edge_t.at(bgn_idx))}); + Vertex u = std::get<1>(edge_t.at(bgn_idx)); + Vertex v = std::get<2>(edge_t.at(bgn_idx)); + f_edge_vector.push_back({{u, v}, std::get<0>(edge_t.at(bgn_idx))}); + vertices.emplace(u); + vertices.emplace(v); } } @@ -330,6 +327,9 @@ class Flag_complex_sparse_matrix { u_set_dominated_redges.clear(); critical_edge_indicator.clear(); + // Initializing sparse_row_adjacency_matrix, This is a row-major sparse matrix. + sparse_row_adjacency_matrix = sparseRowMatrix(vertices.size(), vertices.size()); + while (endIdx < f_edge_vector.size()) { EdgeFilt fec = f_edge_vector[endIdx]; Edge e = std::get<0>(fec); @@ -371,7 +371,6 @@ class Flag_complex_sparse_matrix { domination_indicator.push_back(false); vertex_to_row.insert(std::make_pair(vertex, rows)); row_to_vertex.insert(std::make_pair(rows, vertex)); - vertices.emplace(vertex); rows++; } } @@ -393,7 +392,6 @@ class Flag_complex_sparse_matrix { #endif // DEBUG_TRACES sparse_row_adjacency_matrix.insert(rw_u->second, rw_v->second) = filt_val; sparse_row_adjacency_matrix.insert(rw_v->second, rw_u->second) = filt_val; - numOneSimplices++; } #ifdef DEBUG_TRACES else { @@ -406,4 +404,4 @@ class Flag_complex_sparse_matrix { }; -#endif // FLAG_COMPLEX_SPARSE_MATRIX_H_ \ No newline at end of file +#endif // FLAG_COMPLEX_SPARSE_MATRIX_H_ diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 67f35e89..4857580c 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -23,27 +23,11 @@ #include #include -// ^ -// /!\ Nothing else from Simplex_tree shall be included to test includes are well defined. #include "gudhi/Flag_complex_sparse_matrix.h" #include "gudhi/Rips_edge_list.h" #include "gudhi/graph_simplicial_complex.h" #include "gudhi/distance_functions.h" -//using namespace Gudhi; - -// Types definition -//using Vector_of_points = std::vector>; - -//using Simplex_tree = Gudhi::Simplex_tree; -//using Filtration_value = double; -//using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; -/*using Rips_complex = Gudhi::rips_complex::Rips_complex; -using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; -using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; -*/ -//using Distance_matrix = std::vector>; - using Filtration_value = double; using Vertex_handle = size_t; using Filtered_edge = std::tuple; @@ -64,7 +48,7 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt std::cout << "f[" << std::get<1>(edge) << ", " << std::get<2>(edge) << "] = " << std::get<0>(edge) << std::endl; } - Flag_complex_sparse_matrix flag_complex_sparse_matrix(5, edges); + Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); auto collapse_edges = flag_complex_sparse_matrix.filtered_edge_collapse(); std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; BOOST_CHECK(collapse_edges.size() <= edges.size()); @@ -136,7 +120,7 @@ BOOST_AUTO_TEST_CASE(collapse) { */ edges.push_back({4., 2, 5}); edges.push_back({4., 4, 3}); - trace_and_check_collapse(edges, {{2., 1, 3}, {4., 2, 5}, {4., 4, 3}}); + trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}}); /* 1 2 4 @@ -149,7 +133,7 @@ BOOST_AUTO_TEST_CASE(collapse) { */ edges.push_back({5., 1, 5}); edges.push_back({5., 0, 4}); - trace_and_check_collapse(edges, {{2., 1, 3}, {4., 2, 5}, {4., 4, 3}, {5., 0, 4}}); + trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}, {5., 0, 4}}); } diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 75eb6d67..7f5a9454 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -131,7 +131,7 @@ int main(int argc, char* argv[]) { // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - Flag_complex_sparse_matrix mat_filt_edge_coll(number_of_points, edge_t); + Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); std::cout << "Matrix instansiated" << std::endl; Filtered_sorted_edge_list collapse_edges; collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index b316391b..e3290b7a 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -115,7 +115,7 @@ int main(int argc, char* argv[]) { // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - Flag_complex_sparse_matrix mat_filt_edge_coll(number_of_points, edge_t); + Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); std::cout << "Matrix instansiated" << std::endl; Filtered_sorted_edge_list collapse_edges; collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); -- cgit v1.2.3 From 599e910811e1c4c743a61be65e089e798f578d4a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 6 Apr 2020 23:40:29 +0200 Subject: Remove rips edge list first part --- .../include/gudhi/Flag_complex_sparse_matrix.h | 40 ++++++++++++++++++++-- .../point_cloud_edge_collapse_rips_persistence.cpp | 39 +++++++++++---------- 2 files changed, 58 insertions(+), 21 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 786a970a..d7014f2f 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -12,8 +12,15 @@ #define FLAG_COMPLEX_SPARSE_MATRIX_H_ #include +#include + #include -// #include + +#include + +#ifdef GUDHI_USE_TBB +#include +#endif #include #include @@ -28,8 +35,6 @@ #include #include -#include - typedef std::size_t Vertex; using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level @@ -319,6 +324,35 @@ class Flag_complex_sparse_matrix { } } + template + Flag_complex_sparse_matrix(const OneSkeletonGraph& one_skeleton_graph) + : rows(0), + edgeCollapsed(false) { + // Insert all vertices + for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { + vertices.emplace(*(v_it.first)); + } + // Insert all edges + for (auto edge_it = boost::edges(one_skeleton_graph); + edge_it.first != edge_it.second; ++edge_it.first) { + auto edge = *(edge_it.first); + Vertex u = source(edge, one_skeleton_graph); + Vertex v = target(edge, one_skeleton_graph); + f_edge_vector.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); + } + // Sort edges + auto sort_by_filtration = [](const EdgeFilt& edge_a, const EdgeFilt& edge_b) -> bool + { + return (get<1>(edge_a) < get<1>(edge_b)); + }; + +#ifdef GUDHI_USE_TBB + tbb::parallel_sort(f_edge_vector.begin(), f_edge_vector.end(), sort_by_filtration); +#else + std::stable_sort(f_edge_vector.begin(), f_edge_vector.end(), sort_by_filtration); +#endif + } + // Performs edge collapse in a decreasing sequence of the filtration value. Filtered_sorted_edge_list filtered_edge_collapse() { std::size_t endIdx = 0; diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index e3290b7a..a2840674 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -6,23 +6,29 @@ #include #include #include +#include -#include - +#include #include // Types definition -using Point = CGAL::Epick_d::Point_d; + +using Simplex_tree = Gudhi::Simplex_tree<>; +using Filtration_value = Simplex_tree::Filtration_value; +using Point = std::vector; using Vector_of_points = std::vector; -using Simplex_tree = Gudhi::Simplex_tree; -using Filtration_value = double; + using Rips_complex = Gudhi::rips_complex::Rips_complex; using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; using Distance_matrix = std::vector>; +using Adjacency_list = boost::adjacency_list, + boost::property>; + class filt_edge_to_dist_matrix { public: @@ -92,30 +98,27 @@ int main(int argc, char* argv[]) { exit(-1); // ----- >> } - int dimension = point_vector[0].dimension(); + //int dimension = point_vector[0].dimension(); number_of_points = point_vector.size(); std::cout << "Successfully read " << number_of_points << " point_vector.\n"; - std::cout << "Ambient dimension is " << dimension << ".\n"; + //std::cout << "Ambient dimension is " << dimension << ".\n"; std::cout << "Point Set Generated." << std::endl; - Filtered_sorted_edge_list edge_t; - std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; - - Rips_edge_list Rips_edge_list_from_file(point_vector, threshold, Gudhi::Euclidean_distance()); - Rips_edge_list_from_file.create_edges(edge_t); - - std::cout << "Sorted edge list computed" << std::endl; - std::cout << "Total number of edges before collapse are: " << edge_t.size() << std::endl; + Adjacency_list proximity_graph = Gudhi::compute_proximity_graph(off_reader.get_point_cloud(), + threshold, + Gudhi::Euclidean_distance()); - if (edge_t.size() <= 0) { + if (num_edges(proximity_graph) <= 0) { std::cerr << "Total number of egdes are zero." << std::endl; exit(-1); } - // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); + Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); + + std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; + std::cout << "Matrix instansiated" << std::endl; Filtered_sorted_edge_list collapse_edges; collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); -- cgit v1.2.3 From 9654c177078fc598c8a8424dd67d0742bf0defb9 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 9 Apr 2020 21:46:42 +0200 Subject: Use an output iterator for edge collapse return instead of storing it --- .../include/gudhi/Flag_complex_sparse_matrix.h | 20 +++----- src/Collapse/test/collapse_unit_test.cpp | 6 ++- ...tance_matrix_edge_collapse_rips_persistence.cpp | 46 ++++------------- .../point_cloud_edge_collapse_rips_persistence.cpp | 59 ++++++---------------- 4 files changed, 37 insertions(+), 94 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index d7014f2f..033c27a3 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -55,7 +55,6 @@ using boolVector = std::vector; using EdgeFiltVector = std::vector; typedef std::vector> Filtered_sorted_edge_list; -typedef std::unordered_map> u_edge_map; typedef std::unordered_map> u_edge_to_idx_map; //! Class SparseMsMatrix @@ -126,8 +125,6 @@ class Flag_complex_sparse_matrix { // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. EdgeFiltVector f_edge_vector; - // List of non-dominated edges, the indices of the edges are the vertex lables!!. - Filtered_sorted_edge_list critical_core_edges; // Stores the indices from the sorted filtered edge vector. // std::set recurCriticalCoreIndcs; @@ -214,7 +211,8 @@ class Flag_complex_sparse_matrix { return edge_indices; } - void set_edge_critical(std::size_t indx, double filt) { + template + void set_edge_critical(std::size_t indx, double filt, FilteredEdgeInsertion filtered_edge_insert) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; @@ -235,7 +233,7 @@ class Flag_complex_sparse_matrix { std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES critical_edge_indicator.at(idx) = true; - critical_core_edges.push_back({filt, u, v}); + filtered_edge_insert({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); @@ -354,7 +352,8 @@ class Flag_complex_sparse_matrix { } // Performs edge collapse in a decreasing sequence of the filtration value. - Filtered_sorted_edge_list filtered_edge_collapse() { + template + void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { std::size_t endIdx = 0; u_set_removed_redges.clear(); @@ -381,20 +380,15 @@ class Flag_complex_sparse_matrix { if (not check_edge_domination(e)) { critical_edge_indicator.at(endIdx) = true; dominated_edge_indicator.at(endIdx) = false; - critical_core_edges.push_back({filt, u, v}); + filtered_edge_insert({u, v}, filt); if (endIdx > 1) - set_edge_critical(endIdx, filt); + set_edge_critical(endIdx, filt, filtered_edge_insert); } else dominated_edge_indicator.at(endIdx) = true; endIdx++; } -#ifdef DEBUG_TRACES - std::cout << "The total number of critical edges is: " << critical_core_edges.size() << std::endl; - std::cout << "The total number of non-critical edges is: " << f_edge_vector.size() - critical_core_edges.size() << std::endl; -#endif // DEBUG_TRACES edgeCollapsed = true; - return critical_core_edges; } void insert_vertex(const Vertex& vertex, double filt_val) { diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 4857580c..29f33219 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -49,7 +49,11 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt } Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); - auto collapse_edges = flag_complex_sparse_matrix.filtered_edge_collapse(); + Filtered_sorted_edge_list collapse_edges; + flag_complex_sparse_matrix.filtered_edge_collapse( + [&collapse_edges](std::pair edge, double filtration) { + collapse_edges.push_back({std::get<0>(edge), std::get<1>(edge), filtration}); + }); std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; BOOST_CHECK(collapse_edges.size() <= edges.size()); for (auto edge_from_collapse : collapse_edges) { diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 7f5a9454..98a90892 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -17,7 +16,6 @@ using Vector_of_points = std::vector; using Simplex_tree = Gudhi::Simplex_tree; using Filtration_value = double; -using Rips_complex = Gudhi::rips_complex::Rips_complex; using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -62,32 +60,6 @@ void program_options(int argc, char* const argv[], double& min_persistence, doub } } -class filt_edge_to_dist_matrix { - public: - template - filt_edge_to_dist_matrix(Distance_matrix& distance_mat, Filtered_sorted_edge_list& edge_filt, - std::size_t number_of_points) { - double inf = std::numeric_limits::max(); - doubleVector distances; - std::pair e; - for (std::size_t indx = 0; indx < number_of_points; indx++) { - for (std::size_t j = 0; j <= indx; j++) { - if (j == indx) - distances.push_back(0); - else - distances.push_back(inf); - } - distance_mat.push_back(distances); - distances.clear(); - } - - for (auto edIt = edge_filt.begin(); edIt != edge_filt.end(); edIt++) { - e = std::minmax(std::get<1>(*edIt), std::get<2>(*edIt)); - distance_mat.at(std::get<1>(e)).at(std::get<0>(e)) = std::get<0>(*edIt); - } - } -}; - void program_options(int argc, char* argv[], std::string& csv_matrix_file, std::string& filediag, Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence); @@ -133,16 +105,18 @@ int main(int argc, char* argv[]) { std::cout << "Filtered edge collapse begins" << std::endl; Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); std::cout << "Matrix instansiated" << std::endl; - Filtered_sorted_edge_list collapse_edges; - collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); - filt_edge_to_dist_matrix(sparse_distances, collapse_edges, number_of_points); - std::cout << "Total number of vertices after collapse in the sparse matrix are: " << mat_filt_edge_coll.num_vertices() - << std::endl; - - Rips_complex rips_complex_after_collapse(sparse_distances, threshold); Simplex_tree stree; - rips_complex_after_collapse.create_complex(stree, dim_max); + mat_filt_edge_coll.filtered_edge_collapse( + [&stree](std::vector edge, double filtration) { + // insert the 2 vertices with a 0. filtration value just like a Rips + stree.insert_simplex({edge[0]}, 0.); + stree.insert_simplex({edge[1]}, 0.); + // insert the edge + stree.insert_simplex(edge, filtration); + }); + + stree.expansion(dim_max); std::cout << "The complex contains " << stree.num_simplices() << " simplices after collapse. \n"; std::cout << " and has dimension " << stree.dimension() << " \n"; diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index a2840674..70d8d9c5 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -1,8 +1,6 @@ #include -#include #include #include -#include #include #include #include @@ -11,16 +9,18 @@ #include #include +#include // for std::pair +#include + // Types definition using Simplex_tree = Gudhi::Simplex_tree<>; using Filtration_value = Simplex_tree::Filtration_value; +using Vertex_handle = std::size_t; /*Simplex_tree::Vertex_handle;*/ using Point = std::vector; using Vector_of_points = std::vector; -using Rips_complex = Gudhi::rips_complex::Rips_complex; -using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; using Distance_matrix = std::vector>; @@ -29,38 +29,10 @@ using Adjacency_list = boost::adjacency_list, boost::property>; - -class filt_edge_to_dist_matrix { - public: - template - filt_edge_to_dist_matrix(Distance_matrix& distance_mat, Filtered_sorted_edge_list& edge_filt, - std::size_t number_of_points) { - double inf = std::numeric_limits::max(); - doubleVector distances; - std::pair e; - for (std::size_t indx = 0; indx < number_of_points; indx++) { - for (std::size_t j = 0; j <= indx; j++) { - if (j == indx) - distances.push_back(0); - else - distances.push_back(inf); - } - distance_mat.push_back(distances); - distances.clear(); - } - - for (auto edIt = edge_filt.begin(); edIt != edge_filt.end(); edIt++) { - e = std::minmax(std::get<1>(*edIt), std::get<2>(*edIt)); - distance_mat.at(std::get<1>(e)).at(std::get<0>(e)) = std::get<0>(*edIt); - } - } -}; - void program_options(int argc, char* argv[], std::string& off_file_points, std::string& filediag, Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence); int main(int argc, char* argv[]) { - typedef size_t Vertex_handle; typedef std::vector> Filtered_sorted_edge_list; auto the_begin = std::chrono::high_resolution_clock::now(); @@ -82,8 +54,6 @@ int main(int argc, char* argv[]) { std::cout << min_persistence << ", " << threshold << ", " << dim_max << ", " << off_file_points << ", " << filediag << std::endl; - Map map_empty; - Distance_matrix sparse_distances; Gudhi::Points_off_reader off_reader(off_file_points); @@ -120,18 +90,19 @@ int main(int argc, char* argv[]) { std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; std::cout << "Matrix instansiated" << std::endl; - Filtered_sorted_edge_list collapse_edges; - collapse_edges = mat_filt_edge_coll.filtered_edge_collapse(); - filt_edge_to_dist_matrix(sparse_distances, collapse_edges, number_of_points); - std::cout << "Total number of vertices after collapse in the sparse matrix are: " << mat_filt_edge_coll.num_vertices() - << std::endl; - - // Rips_complex rips_complex_before_collapse(distances, threshold); - Rips_complex rips_complex_after_collapse(sparse_distances, threshold); Simplex_tree stree; - rips_complex_after_collapse.create_complex(stree, dim_max); - + mat_filt_edge_coll.filtered_edge_collapse( + [&stree](std::vector edge, double filtration) { + // insert the 2 vertices with a 0. filtration value just like a Rips + stree.insert_simplex({edge[0]}, 0.); + stree.insert_simplex({edge[1]}, 0.); + // insert the edge + stree.insert_simplex(edge, filtration); + }); + + stree.expansion(dim_max); + std::cout << "The complex contains " << stree.num_simplices() << " simplices after collapse. \n"; std::cout << " and has dimension " << stree.dimension() << " \n"; -- cgit v1.2.3 From bdcb50a167702a4649d866fd11dab6976ec9b3db Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 9 Apr 2020 22:31:10 +0200 Subject: Use operator[] instead of method at() --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 033c27a3..4862c1b0 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -225,14 +225,14 @@ class Flag_complex_sparse_matrix { Vertex v = std::get<1>(e); // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() - if (not critical_edge_indicator.at(idx)) { + if (not critical_edge_indicator[idx]) { // If idx is affected if (effectedIndcs.find(idx) != effectedIndcs.end()) { if (not check_edge_domination(e)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES - critical_edge_indicator.at(idx) = true; + critical_edge_indicator[idx] = true; filtered_edge_insert({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { @@ -314,9 +314,9 @@ class Flag_complex_sparse_matrix { : rows(0), edgeCollapsed(false) { for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - Vertex u = std::get<1>(edge_t.at(bgn_idx)); - Vertex v = std::get<2>(edge_t.at(bgn_idx)); - f_edge_vector.push_back({{u, v}, std::get<0>(edge_t.at(bgn_idx))}); + Vertex u = std::get<1>(edge_t[bgn_idx]); + Vertex v = std::get<2>(edge_t[bgn_idx]); + f_edge_vector.push_back({{u, v}, std::get<0>(edge_t[bgn_idx])}); vertices.emplace(u); vertices.emplace(v); } @@ -378,13 +378,13 @@ class Flag_complex_sparse_matrix { dominated_edge_indicator.push_back(false); if (not check_edge_domination(e)) { - critical_edge_indicator.at(endIdx) = true; - dominated_edge_indicator.at(endIdx) = false; + critical_edge_indicator[endIdx] = true; + dominated_edge_indicator[endIdx] = false; filtered_edge_insert({u, v}, filt); if (endIdx > 1) set_edge_critical(endIdx, filt, filtered_edge_insert); } else - dominated_edge_indicator.at(endIdx) = true; + dominated_edge_indicator[endIdx] = true; endIdx++; } -- cgit v1.2.3 From 050fde353b73da4e93aaee2beab1291cc044be42 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 10 Apr 2020 07:55:30 +0200 Subject: All in a Gudhi::collapse namespace --- src/Collapse/doc/intro_edge_collapse.h | 4 ++-- .../include/gudhi/Flag_complex_sparse_matrix.h | 19 ++++++++++++------- src/Collapse/test/collapse_unit_test.cpp | 2 +- ...distance_matrix_edge_collapse_rips_persistence.cpp | 4 +--- .../point_cloud_edge_collapse_rips_persistence.cpp | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/doc/intro_edge_collapse.h b/src/Collapse/doc/intro_edge_collapse.h index b42b5e65..70c816f4 100644 --- a/src/Collapse/doc/intro_edge_collapse.h +++ b/src/Collapse/doc/intro_edge_collapse.h @@ -13,7 +13,7 @@ namespace Gudhi { -namespace edge_collapse { +namespace collapse { /** \defgroup edge_collapse Edge collapse * @@ -91,7 +91,7 @@ namespace edge_collapse { */ /** @} */ // end defgroup strong_collapse -} // namespace edge_collapse +} // namespace collapse } // namespace Gudhi diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 4862c1b0..0d5f37a4 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -35,27 +35,28 @@ #include #include +namespace Gudhi { + +namespace collapse { + + typedef std::size_t Vertex; using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level // of row indices on actual vertex lables using EdgeFilt = std::pair; -using edge_list = std::vector; using MapVertexToIndex = std::unordered_map; -using Map = std::unordered_map; using sparseRowMatrix = Eigen::SparseMatrix; -using rowInnerIterator = sparseRowMatrix::InnerIterator; using doubleVector = std::vector; -using vertexVector = std::vector; using boolVector = std::vector; using EdgeFiltVector = std::vector; -typedef std::vector> Filtered_sorted_edge_list; -typedef std::unordered_map> u_edge_to_idx_map; +using Filtered_sorted_edge_list = std::vector>; +using u_edge_to_idx_map = std::unordered_map>; //! Class SparseMsMatrix /*! @@ -266,7 +267,7 @@ class Flag_complex_sparse_matrix { #endif // DEBUG_TRACES if (not domination_indicator[indx]) { // Iterate over the non-zero columns - for (rowInnerIterator it(sparse_row_adjacency_matrix, indx); it; ++it) { + for (sparseRowMatrix::InnerIterator it(sparse_row_adjacency_matrix, indx); it; ++it) { v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix if (not domination_indicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and @@ -432,4 +433,8 @@ class Flag_complex_sparse_matrix { }; +} // namespace collapse + +} // namespace Gudhi + #endif // FLAG_COMPLEX_SPARSE_MATRIX_H_ diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 88af53e8..8cfa7d5f 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -40,7 +40,7 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt } std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); + Gudhi::collapse::Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); Filtered_sorted_edge_list collapse_edges; flag_complex_sparse_matrix.filtered_edge_collapse( [&collapse_edges](std::pair edge, double filtration) { diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 98a90892..b937a8ff 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -78,8 +78,6 @@ int main(int argc, char* argv[]) { program_options(argc, argv, csv_matrix_file, filediag, threshold, dim_max, p, min_persistence); - Map map_empty; - Distance_matrix distances; Distance_matrix sparse_distances; @@ -103,7 +101,7 @@ int main(int argc, char* argv[]) { // Now we will perform filtered edge collapse to sparsify the edge list edge_t. std::cout << "Filtered edge collapse begins" << std::endl; - Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); + Gudhi::collapse::Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); std::cout << "Matrix instansiated" << std::endl; Simplex_tree stree; diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index 70d8d9c5..5fa24306 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -85,7 +85,7 @@ int main(int argc, char* argv[]) { } std::cout << "Filtered edge collapse begins" << std::endl; - Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); + Gudhi::collapse::Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; -- cgit v1.2.3 From 2acc203de9dcdb55983db29a903ef0ff16e0a597 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 10 Apr 2020 09:02:52 +0200 Subject: Conventions for variables and type names --- .../include/gudhi/Flag_complex_sparse_matrix.h | 257 ++++++++++----------- 1 file changed, 121 insertions(+), 136 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 0d5f37a4..7e3e5a62 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -44,19 +44,15 @@ typedef std::size_t Vertex; using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level // of row indices on actual vertex lables -using EdgeFilt = std::pair; +using Filtered_edge = std::pair; -using MapVertexToIndex = std::unordered_map; +using Map_vertex_to_index = std::unordered_map; -using sparseRowMatrix = Eigen::SparseMatrix; +using Sparse_row_matrix = Eigen::SparseMatrix; using doubleVector = std::vector; -using boolVector = std::vector; - -using EdgeFiltVector = std::vector; using Filtered_sorted_edge_list = std::vector>; -using u_edge_to_idx_map = std::unordered_map>; //! Class SparseMsMatrix /*! @@ -65,37 +61,34 @@ using u_edge_to_idx_map = std::unordered_map row_to_vertex; + std::unordered_map row_to_vertex_; // Vertices stored as an unordered_set - std::unordered_set vertices; + std::unordered_set vertices_; // Unordered set of removed edges. (to enforce removal from the matrix) - std::unordered_set> u_set_removed_redges; + std::unordered_set> u_set_removed_redges_; // Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_redges; + std::unordered_set> u_set_dominated_redges_; // Map from egde to its index - u_edge_to_idx_map edge_to_index_map; + std::unordered_map> edge_to_index_map_; // Boolean vector to indicate if the index is critical or not. - boolVector critical_edge_indicator; // critical indicator + std::vector critical_edge_indicator_; // critical indicator // Boolean vector to indicate if the index is critical or not. - boolVector dominated_edge_indicator; // domination indicator + std::vector dominated_edge_indicator_; // domination indicator - //! Stores the Map between verticesrow_to_vertex and row indices row_to_vertex -> row-index. + //! Stores the Map between vertices_row_to_vertex_ and row indices row_to_vertex_ -> row-index. /*! - \code - MapVertexToIndex = std::unordered_map - \endcode - So, if the original simplex tree had vertices 0,1,4,5
- row_to_vertex would store :
+ So, if the original simplex tree had vertices_ 0,1,4,5
+ row_to_vertex_ would store :
\verbatim Values = | 0 | 1 | 4 | 5 | Indices = 0 1 2 3 \endverbatim - And vertex_to_row would be a map like the following :
+ And vertex_to_row_ would be a map like the following :
\verbatim 0 -> 0 1 -> 1 @@ -103,71 +96,68 @@ class Flag_complex_sparse_matrix { 5 -> 3 \endverbatim */ - MapVertexToIndex vertex_to_row; + std::unordered_map vertex_to_row_; //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. /*! \code - sparseRowMatrix = Eigen::SparseMatrix ; + Sparse_row_matrix = Eigen::SparseMatrix ; \endcode ; */ - sparseRowMatrix sparse_row_adjacency_matrix; // This is row-major version of the same sparse-matrix, to facilitate easy access + Sparse_row_matrix sparse_row_adjacency_matrix_; // This is row-major version of the same sparse-matrix, to facilitate easy access // to elements when traversing the matrix row-wise. //! Stores true for dominated rows and false for undominated rows. /*! Initialised to a vector of length equal to the value of the variable rows with all false values. - Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. + Subsequent removal of dominated vertices_ is reflected by concerned entries changing to true in this vector. */ - boolVector domination_indicator; //(domination indicator) + std::vector domination_indicator_; //(domination indicator) // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. - EdgeFiltVector f_edge_vector; + std::vector f_edge_vector_; // Stores the indices from the sorted filtered edge vector. // std::set recurCriticalCoreIndcs; - //! Stores the number of vertices in the original Simplicial Complex. + //! Stores the number of vertices_ in the original Simplicial Complex. /*! - This stores the count of vertices (which is also the number of rows in the Matrix). + This stores the count of vertices_ (which is also the number of rows in the Matrix). */ std::size_t rows; - bool edgeCollapsed; - // Edge e is the actual edge (u,v). Not the row ids in the matrixs bool check_edge_domination(Edge e) { auto u = std::get<0>(e); auto v = std::get<1>(e); - auto rw_u = vertex_to_row[u]; - auto rw_v = vertex_to_row[v]; + auto rw_u = vertex_to_row_[u]; + auto rw_v = vertex_to_row_[v]; auto rw_e = std::make_pair(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; #endif // DEBUG_TRACES - auto commonNeighbours = closed_common_neighbours_row_index(rw_e); + auto common_neighbours = closed_common_neighbours_row_index(rw_e); #ifdef DEBUG_TRACES std::cout << "And its common neighbours are." << std::endl; - for (doubleVector::iterator it = commonNeighbours.begin(); it!=commonNeighbours.end(); it++) { - std::cout << row_to_vertex[*it] << ", " ; + for (auto neighbour : common_neighbours) { + std::cout << row_to_vertex_[neighbour] << ", " ; } std::cout<< std::endl; #endif // DEBUG_TRACES - if (commonNeighbours.size() > 2) { - if (commonNeighbours.size() == 3) + if (common_neighbours.size() > 2) { + if (common_neighbours.size() == 3) return true; else - for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { - auto rw_c = *it; // Typecasting + for (auto rw_c : common_neighbours) { if (rw_c != rw_u and rw_c != rw_v) { auto neighbours_c = closed_neighbours_row_index(rw_c); // If neighbours_c contains the common neighbours. - if (std::includes(neighbours_c.begin(), neighbours_c.end(), commonNeighbours.begin(), - commonNeighbours.end())) + if (std::includes(neighbours_c.begin(), neighbours_c.end(), common_neighbours.begin(), + common_neighbours.end())) return true; } } @@ -178,34 +168,33 @@ class Flag_complex_sparse_matrix { // The edge should be sorted by the indices and indices are original bool check_domination_indicator(Edge e) { - return dominated_edge_indicator[edge_to_index_map[e]]; + return dominated_edge_indicator_[edge_to_index_map_[e]]; } std::set three_clique_indices(std::size_t crit) { std::set edge_indices; - Edge e = std::get<0>(f_edge_vector[crit]); + Edge e = std::get<0>(f_edge_vector_[crit]); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); #ifdef DEBUG_TRACES std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v - << "} = " << std::get<1>(f_edge_vector[crit]) << std::endl; + << "} = " << std::get<1>(f_edge_vector_[crit]) << std::endl; #endif // DEBUG_TRACES - auto rw_u = vertex_to_row[u]; - auto rw_v = vertex_to_row[v]; + auto rw_u = vertex_to_row_[u]; + auto rw_v = vertex_to_row_[v]; auto rw_critical_edge = std::make_pair(rw_u, rw_v); - doubleVector commonNeighbours = closed_common_neighbours_row_index(rw_critical_edge); + doubleVector common_neighbours = closed_common_neighbours_row_index(rw_critical_edge); - if (commonNeighbours.size() > 2) { - for (doubleVector::iterator it = commonNeighbours.begin(); it != commonNeighbours.end(); it++) { - auto rw_c = *it; + if (common_neighbours.size() > 2) { + for (auto rw_c : common_neighbours) { if (rw_c != rw_u and rw_c != rw_v) { - auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex[rw_c]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_v]); - edge_indices.emplace(edge_to_index_map[e_with_new_nbhr_u]); + auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex_[rw_c]); + edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_v]); + edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_u]); } } } @@ -221,19 +210,19 @@ class Flag_complex_sparse_matrix { std::set effectedIndcs = three_clique_indices(indx); if (effectedIndcs.size() > 0) { for (auto idx = indx - 1; idx > 0; idx--) { - Edge e = std::get<0>(f_edge_vector[idx]); + Edge e = std::get<0>(f_edge_vector_[idx]); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() - if (not critical_edge_indicator[idx]) { + if (not critical_edge_indicator_[idx]) { // If idx is affected if (effectedIndcs.find(idx) != effectedIndcs.end()) { if (not check_edge_domination(e)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES - critical_edge_indicator[idx] = true; + critical_edge_indicator_[idx] = true; filtered_edge_insert({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { @@ -245,15 +234,15 @@ class Flag_complex_sparse_matrix { std::get<1>(e) << "}; " << filt << std::endl; #endif // DEBUG_TRACES } else - u_set_dominated_redges.emplace(std::minmax(vertex_to_row[u], vertex_to_row[v])); + u_set_dominated_redges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } else // Idx is not affected hence dominated. - u_set_dominated_redges.emplace(std::minmax(vertex_to_row[u], vertex_to_row[v])); + u_set_dominated_redges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } } } effectedIndcs.clear(); - u_set_dominated_redges.clear(); + u_set_dominated_redges_.clear(); } // Returns list of non-zero columns of the particular indx. @@ -263,19 +252,19 @@ class Flag_complex_sparse_matrix { Vertex u = indx; Vertex v; #ifdef DEBUG_TRACES - std::cout << "The neighbours of the vertex: " << row_to_vertex[u] << " are. " << std::endl; + std::cout << "The neighbours of the vertex: " << row_to_vertex_[u] << " are. " << std::endl; #endif // DEBUG_TRACES - if (not domination_indicator[indx]) { + if (not domination_indicator_[indx]) { // Iterate over the non-zero columns - for (sparseRowMatrix::InnerIterator it(sparse_row_adjacency_matrix, indx); it; ++it) { + for (Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, indx); it; ++it) { v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not domination_indicator[v] and u_set_removed_redges.find(std::minmax(u, v)) == u_set_removed_redges.end() and - u_set_dominated_redges.find(std::minmax(u, v)) == u_set_dominated_redges.end()) { + if (not domination_indicator_[v] and u_set_removed_redges_.find(std::minmax(u, v)) == u_set_removed_redges_.end() and + u_set_dominated_redges_.find(std::minmax(u, v)) == u_set_dominated_redges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(it.index()); #ifdef DEBUG_TRACES - std::cout << row_to_vertex[it.index()] << ", " ; + std::cout << row_to_vertex_[it.index()] << ", " ; #endif // DEBUG_TRACES } } @@ -301,35 +290,70 @@ class Flag_complex_sparse_matrix { return common; } + + void insert_vertex(const Vertex& vertex, double filt_val) { + auto rw = vertex_to_row_.find(vertex); + if (rw == vertex_to_row_.end()) { + // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + sparse_row_adjacency_matrix_.insert(rows, rows) = filt_val; + domination_indicator_.push_back(false); + vertex_to_row_.insert(std::make_pair(vertex, rows)); + row_to_vertex_.insert(std::make_pair(rows, vertex)); + rows++; + } + } + + void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) + { + // The edge must not be added before, it should be a new edge. + insert_vertex(u, filt_val); + if (u != v) { + insert_vertex(v, filt_val); +#ifdef DEBUG_TRACES + std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES + + auto rw_u = vertex_to_row_.find(u); + auto rw_v = vertex_to_row_.find(v); +#ifdef DEBUG_TRACES + std::cout << "Inserting the edge " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES + sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = filt_val; + sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = filt_val; + } +#ifdef DEBUG_TRACES + else { + std::cout << "Already a member simplex, skipping..." << std::endl; + } +#endif // DEBUG_TRACES + } public: //! Main Constructor /*! Argument is an instance of Filtered_sorted_edge_list.
This is THE function that initialises all data members to appropriate values.
- row_to_vertex, vertex_to_row, rows, cols, sparse_row_adjacency_matrix are initialised here. - domination_indicator are initialised by init() function which is + row_to_vertex_, vertex_to_row_, rows, cols, sparse_row_adjacency_matrix_ are initialised here. + domination_indicator_ are initialised by init() function which is called at the begining of this.
*/ Flag_complex_sparse_matrix(const Filtered_sorted_edge_list& edge_t) - : rows(0), - edgeCollapsed(false) { + : rows(0) { for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { Vertex u = std::get<1>(edge_t[bgn_idx]); Vertex v = std::get<2>(edge_t[bgn_idx]); - f_edge_vector.push_back({{u, v}, std::get<0>(edge_t[bgn_idx])}); - vertices.emplace(u); - vertices.emplace(v); + f_edge_vector_.push_back({{u, v}, std::get<0>(edge_t[bgn_idx])}); + vertices_.emplace(u); + vertices_.emplace(v); } } template Flag_complex_sparse_matrix(const OneSkeletonGraph& one_skeleton_graph) - : rows(0), - edgeCollapsed(false) { - // Insert all vertices - for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { - vertices.emplace(*(v_it.first)); + : rows(0) { + // Insert all vertices_ + for (auto v_it = boost::vertices_(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { + vertices_.emplace(*(v_it.first)); } // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); @@ -337,18 +361,18 @@ class Flag_complex_sparse_matrix { auto edge = *(edge_it.first); Vertex u = source(edge, one_skeleton_graph); Vertex v = target(edge, one_skeleton_graph); - f_edge_vector.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); + f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); } // Sort edges - auto sort_by_filtration = [](const EdgeFilt& edge_a, const EdgeFilt& edge_b) -> bool + auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { return (get<1>(edge_a) < get<1>(edge_b)); }; #ifdef GUDHI_USE_TBB - tbb::parallel_sort(f_edge_vector.begin(), f_edge_vector.end(), sort_by_filtration); + tbb::parallel_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #else - std::stable_sort(f_edge_vector.begin(), f_edge_vector.end(), sort_by_filtration); + std::stable_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif } @@ -357,15 +381,15 @@ class Flag_complex_sparse_matrix { void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { std::size_t endIdx = 0; - u_set_removed_redges.clear(); - u_set_dominated_redges.clear(); - critical_edge_indicator.clear(); + u_set_removed_redges_.clear(); + u_set_dominated_redges_.clear(); + critical_edge_indicator_.clear(); - // Initializing sparse_row_adjacency_matrix, This is a row-major sparse matrix. - sparse_row_adjacency_matrix = sparseRowMatrix(vertices.size(), vertices.size()); + // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. + sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices_.size(), vertices_.size()); - while (endIdx < f_edge_vector.size()) { - EdgeFilt fec = f_edge_vector[endIdx]; + while (endIdx < f_edge_vector_.size()) { + Filtered_edge fec = f_edge_vector_[endIdx]; Edge e = std::get<0>(fec); Vertex u = std::get<0>(e); Vertex v = std::get<1>(e); @@ -374,62 +398,23 @@ class Flag_complex_sparse_matrix { // Inserts the edge in the sparse matrix to update the graph (G_i) insert_new_edges(u, v, filt); - edge_to_index_map.emplace(std::minmax(u, v), endIdx); - critical_edge_indicator.push_back(false); - dominated_edge_indicator.push_back(false); + edge_to_index_map_.emplace(std::minmax(u, v), endIdx); + critical_edge_indicator_.push_back(false); + dominated_edge_indicator_.push_back(false); if (not check_edge_domination(e)) { - critical_edge_indicator[endIdx] = true; - dominated_edge_indicator[endIdx] = false; + critical_edge_indicator_[endIdx] = true; + dominated_edge_indicator_[endIdx] = false; filtered_edge_insert({u, v}, filt); if (endIdx > 1) set_edge_critical(endIdx, filt, filtered_edge_insert); } else - dominated_edge_indicator[endIdx] = true; + dominated_edge_indicator_[endIdx] = true; endIdx++; } - - edgeCollapsed = true; - } - - void insert_vertex(const Vertex& vertex, double filt_val) { - auto rw = vertex_to_row.find(vertex); - if (rw == vertex_to_row.end()) { - // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix.insert(rows, rows) = filt_val; - domination_indicator.push_back(false); - vertex_to_row.insert(std::make_pair(vertex, rows)); - row_to_vertex.insert(std::make_pair(rows, vertex)); - rows++; - } - } - - void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) - { - // The edge must not be added before, it should be a new edge. - insert_vertex(u, filt_val); - if (u != v) { - insert_vertex(v, filt_val); -#ifdef DEBUG_TRACES - std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - - auto rw_u = vertex_to_row.find(u); - auto rw_v = vertex_to_row.find(v); -#ifdef DEBUG_TRACES - std::cout << "Inserting the edge " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - sparse_row_adjacency_matrix.insert(rw_u->second, rw_v->second) = filt_val; - sparse_row_adjacency_matrix.insert(rw_v->second, rw_u->second) = filt_val; - } -#ifdef DEBUG_TRACES - else { - std::cout << "Already a member simplex, skipping..." << std::endl; - } -#endif // DEBUG_TRACES } - std::size_t num_vertices() const { return vertices.size(); } + std::size_t num_vertices() const { return vertices_.size(); } }; -- cgit v1.2.3 From b5bb9fd2a129ab9c429a0c7c67ca4442e6e7b1b0 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sat, 11 Apr 2020 09:21:36 +0200 Subject: Vertex_handle, Filtration_value and Row_index type --- .../include/gudhi/Flag_complex_sparse_matrix.h | 178 ++++++++++----------- src/Collapse/test/collapse_unit_test.cpp | 11 +- ...tance_matrix_edge_collapse_rips_persistence.cpp | 40 ++--- .../point_cloud_edge_collapse_rips_persistence.cpp | 31 +--- 4 files changed, 111 insertions(+), 149 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 7e3e5a62..edf3f415 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -30,41 +30,48 @@ #include #include #include -#include - -#include -#include namespace Gudhi { namespace collapse { - -typedef std::size_t Vertex; -using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first +/** + * \class Flag_complex_sparse_matrix + * \brief Flag complex sparse matrix data structure. + * + * \ingroup collapse + * + * \details + * A class to store the vertices v/s MaxSimplices Sparse Matrix and to perform collapse operations using the N^2() + * Algorithm. + * + * \tparam Vertex_handle type must be a signed integer type. It admits a total order <. + * \tparam Filtration_value type for the value of the filtration function. Must be comparable with <. + */ +template +class Flag_complex_sparse_matrix { + private: + using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level // of row indices on actual vertex lables -using Filtered_edge = std::pair; + using Filtered_edge = std::pair; -using Map_vertex_to_index = std::unordered_map; + using Row_index = std::size_t; -using Sparse_row_matrix = Eigen::SparseMatrix; + using Map_vertex_to_index = std::unordered_map; -using doubleVector = std::vector; + using Sparse_row_matrix = Eigen::SparseMatrix; -using Filtered_sorted_edge_list = std::vector>; + using Row_indices_vector = std::vector; + + public: + using Filtered_sorted_edge_list = std::vector>; -//! Class SparseMsMatrix -/*! - The class for storing the Vertices v/s MaxSimplices Sparse Matrix and performing collapses operations using the N^2() - Algorithm. -*/ -class Flag_complex_sparse_matrix { private: - std::unordered_map row_to_vertex_; + std::unordered_map row_to_vertex_; // Vertices stored as an unordered_set - std::unordered_set vertices_; + std::unordered_set vertices_; // Unordered set of removed edges. (to enforce removal from the matrix) std::unordered_set> u_set_removed_redges_; @@ -72,8 +79,8 @@ class Flag_complex_sparse_matrix { // Unordered set of dominated edges. (to inforce removal from the matrix) std::unordered_set> u_set_dominated_redges_; - // Map from egde to its index - std::unordered_map> edge_to_index_map_; + // Map from edge to its index + std::unordered_map> edge_to_index_map_; // Boolean vector to indicate if the index is critical or not. std::vector critical_edge_indicator_; // critical indicator @@ -96,12 +103,12 @@ class Flag_complex_sparse_matrix { 5 -> 3 \endverbatim */ - std::unordered_map vertex_to_row_; + std::unordered_map vertex_to_row_; - //! Stores the Sparse matrix of double values representing the Original Simplicial Complex. + //! Stores the Sparse matrix of Filtration_value values representing the Original Simplicial Complex. /*! \code - Sparse_row_matrix = Eigen::SparseMatrix ; + Sparse_row_matrix = Eigen::SparseMatrix ; \endcode ; */ @@ -119,23 +126,21 @@ class Flag_complex_sparse_matrix { // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. std::vector f_edge_vector_; - // Stores the indices from the sorted filtered edge vector. - // std::set recurCriticalCoreIndcs; //! Stores the number of vertices_ in the original Simplicial Complex. /*! This stores the count of vertices_ (which is also the number of rows in the Matrix). */ - std::size_t rows; + Row_index rows; // Edge e is the actual edge (u,v). Not the row ids in the matrixs - bool check_edge_domination(Edge e) + bool check_edge_domination(Edge edge) { - auto u = std::get<0>(e); - auto v = std::get<1>(e); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); - auto rw_u = vertex_to_row_[u]; - auto rw_v = vertex_to_row_[v]; + Row_index rw_u = vertex_to_row_[u]; + Row_index rw_v = vertex_to_row_[v]; auto rw_e = std::make_pair(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; @@ -165,18 +170,12 @@ class Flag_complex_sparse_matrix { return false; } - // The edge should be sorted by the indices and indices are original - bool check_domination_indicator(Edge e) - { - return dominated_edge_indicator_[edge_to_index_map_[e]]; - } + std::set three_clique_indices(Row_index crit) { + std::set edge_indices; - std::set three_clique_indices(std::size_t crit) { - std::set edge_indices; - - Edge e = std::get<0>(f_edge_vector_[crit]); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); + Edge edge = std::get<0>(f_edge_vector_[crit]); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); #ifdef DEBUG_TRACES std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v @@ -186,7 +185,7 @@ class Flag_complex_sparse_matrix { auto rw_v = vertex_to_row_[v]; auto rw_critical_edge = std::make_pair(rw_u, rw_v); - doubleVector common_neighbours = closed_common_neighbours_row_index(rw_critical_edge); + Row_indices_vector common_neighbours = closed_common_neighbours_row_index(rw_critical_edge); if (common_neighbours.size() > 2) { for (auto rw_c : common_neighbours) { @@ -202,36 +201,36 @@ class Flag_complex_sparse_matrix { } template - void set_edge_critical(std::size_t indx, double filt, FilteredEdgeInsertion filtered_edge_insert) { + void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeInsertion filtered_edge_insert) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; #endif // DEBUG_TRACES - std::set effectedIndcs = three_clique_indices(indx); + std::set effectedIndcs = three_clique_indices(indx); if (effectedIndcs.size() > 0) { for (auto idx = indx - 1; idx > 0; idx--) { - Edge e = std::get<0>(f_edge_vector_[idx]); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); + Edge edge = std::get<0>(f_edge_vector_[idx]); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() if (not critical_edge_indicator_[idx]) { // If idx is affected if (effectedIndcs.find(idx) != effectedIndcs.end()) { - if (not check_edge_domination(e)) { + if (not check_edge_domination(edge)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES critical_edge_indicator_[idx] = true; filtered_edge_insert({u, v}, filt); - std::set inner_effected_indcs = three_clique_indices(idx); + std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); } inner_effected_indcs.clear(); #ifdef DEBUG_TRACES - std::cout << "The following edge is critical with filt value: {" << std::get<0>(e) << "," << - std::get<1>(e) << "}; " << filt << std::endl; + std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " + << filt << std::endl; #endif // DEBUG_TRACES } else u_set_dominated_redges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); @@ -245,26 +244,24 @@ class Flag_complex_sparse_matrix { u_set_dominated_redges_.clear(); } - // Returns list of non-zero columns of the particular indx. - doubleVector closed_neighbours_row_index(double indx) + // Returns list of non-zero columns of a particular indx. + Row_indices_vector closed_neighbours_row_index(Row_index rw_u) { - doubleVector non_zero_indices; - Vertex u = indx; - Vertex v; + Row_indices_vector non_zero_indices; #ifdef DEBUG_TRACES - std::cout << "The neighbours of the vertex: " << row_to_vertex_[u] << " are. " << std::endl; + std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES - if (not domination_indicator_[indx]) { + if (not domination_indicator_[rw_u]) { // Iterate over the non-zero columns - for (Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, indx); it; ++it) { - v = it.index(); + for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { + Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not domination_indicator_[v] and u_set_removed_redges_.find(std::minmax(u, v)) == u_set_removed_redges_.end() and - u_set_dominated_redges_.find(std::minmax(u, v)) == u_set_dominated_redges_.end()) { + if (not domination_indicator_[rw_v] and u_set_removed_redges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_redges_.end() and + u_set_dominated_redges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_redges_.end()) { // inner index, here it is equal to it.columns() - non_zero_indices.push_back(it.index()); + non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES - std::cout << row_to_vertex_[it.index()] << ", " ; + std::cout << row_to_vertex_[rw_v] << ", " ; #endif // DEBUG_TRACES } } @@ -275,23 +272,24 @@ class Flag_complex_sparse_matrix { return non_zero_indices; } - doubleVector closed_common_neighbours_row_index(Edge e) // Returns the list of closed neighbours of the edge :{u,v}. + // Returns the list of closed neighbours of the edge :{u,v}. + Row_indices_vector closed_common_neighbours_row_index(const std::pair& rw_edge) { - doubleVector common; - doubleVector non_zero_indices_u; - doubleVector non_zero_indices_v; - double u = std::get<0>(e); - double v = std::get<1>(e); - - non_zero_indices_u = closed_neighbours_row_index(u); - non_zero_indices_v = closed_neighbours_row_index(v); + Row_indices_vector common; + Row_indices_vector non_zero_indices_u; + Row_indices_vector non_zero_indices_v; + Row_index rw_u = std::get<0>(rw_edge); + Row_index rw_v = std::get<1>(rw_edge); + + non_zero_indices_u = closed_neighbours_row_index(rw_u); + non_zero_indices_v = closed_neighbours_row_index(rw_v); std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), non_zero_indices_v.end(), std::inserter(common, common.begin())); return common; } - - void insert_vertex(const Vertex& vertex, double filt_val) { + + void insert_vertex(const Vertex_handle& vertex, Filtration_value filt_val) { auto rw = vertex_to_row_.find(vertex); if (rw == vertex_to_row_.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. @@ -303,7 +301,7 @@ class Flag_complex_sparse_matrix { } } - void insert_new_edges(const Vertex& u, const Vertex& v, double filt_val) + void insert_new_edges(const Vertex_handle& u, const Vertex_handle& v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); @@ -340,8 +338,8 @@ class Flag_complex_sparse_matrix { Flag_complex_sparse_matrix(const Filtered_sorted_edge_list& edge_t) : rows(0) { for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - Vertex u = std::get<1>(edge_t[bgn_idx]); - Vertex v = std::get<2>(edge_t[bgn_idx]); + Vertex_handle u = std::get<1>(edge_t[bgn_idx]); + Vertex_handle v = std::get<2>(edge_t[bgn_idx]); f_edge_vector_.push_back({{u, v}, std::get<0>(edge_t[bgn_idx])}); vertices_.emplace(u); vertices_.emplace(v); @@ -352,15 +350,15 @@ class Flag_complex_sparse_matrix { Flag_complex_sparse_matrix(const OneSkeletonGraph& one_skeleton_graph) : rows(0) { // Insert all vertices_ - for (auto v_it = boost::vertices_(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { + for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { vertices_.emplace(*(v_it.first)); } // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { auto edge = *(edge_it.first); - Vertex u = source(edge, one_skeleton_graph); - Vertex v = target(edge, one_skeleton_graph); + Vertex_handle u = source(edge, one_skeleton_graph); + Vertex_handle v = target(edge, one_skeleton_graph); f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); } // Sort edges @@ -379,7 +377,7 @@ class Flag_complex_sparse_matrix { // Performs edge collapse in a decreasing sequence of the filtration value. template void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { - std::size_t endIdx = 0; + Row_index endIdx = 0; u_set_removed_redges_.clear(); u_set_dominated_redges_.clear(); @@ -390,10 +388,10 @@ class Flag_complex_sparse_matrix { while (endIdx < f_edge_vector_.size()) { Filtered_edge fec = f_edge_vector_[endIdx]; - Edge e = std::get<0>(fec); - Vertex u = std::get<0>(e); - Vertex v = std::get<1>(e); - double filt = std::get<1>(fec); + Edge edge = std::get<0>(fec); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + Filtration_value filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) insert_new_edges(u, v, filt); @@ -402,7 +400,7 @@ class Flag_complex_sparse_matrix { critical_edge_indicator_.push_back(false); dominated_edge_indicator_.push_back(false); - if (not check_edge_domination(e)) { + if (not check_edge_domination(edge)) { critical_edge_indicator_[endIdx] = true; dominated_edge_indicator_[endIdx] = false; filtered_edge_insert({u, v}, filt); diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 8cfa7d5f..38adfa8a 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -19,10 +19,11 @@ #include "gudhi/Flag_complex_sparse_matrix.h" -using Filtration_value = double; -using Vertex_handle = size_t; +using Filtration_value = float; +using Vertex_handle = short; using Filtered_edge = std::tuple; -using Filtered_sorted_edge_list = std::vector>; +using Filtered_sorted_edge_list = std::vector; +using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; bool find_edge_in_list(const Filtered_edge& edge, const Filtered_sorted_edge_list& edge_list) { for (auto edge_from_list : edge_list) { @@ -40,10 +41,10 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt } std::cout << "COLLAPSE - keep edges: " << std::endl; - Gudhi::collapse::Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); + Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); Filtered_sorted_edge_list collapse_edges; flag_complex_sparse_matrix.filtered_edge_collapse( - [&collapse_edges](std::pair edge, double filtration) { + [&collapse_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; collapse_edges.push_back({filtration, std::get<0>(edge), std::get<1>(edge)}); }); diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index b937a8ff..56e9bab6 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -6,16 +6,14 @@ #include #include -#include - #include -// Types definition -using Point = CGAL::Epick_d::Point_d; -using Vector_of_points = std::vector; - using Simplex_tree = Gudhi::Simplex_tree; -using Filtration_value = double; +using Filtration_value = Simplex_tree::Filtration_value; +using Vertex_handle = Simplex_tree::Vertex_handle; + +using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; + using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -64,17 +62,12 @@ void program_options(int argc, char* argv[], std::string& csv_matrix_file, std:: Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence); int main(int argc, char* argv[]) { - auto the_begin = std::chrono::high_resolution_clock::now(); - - typedef size_t Vertex_handle; - typedef std::vector> Filtered_sorted_edge_list; - std::string csv_matrix_file; std::string filediag; - double threshold; + Filtration_value threshold; int dim_max = 2; int p; - double min_persistence; + Filtration_value min_persistence; program_options(argc, argv, csv_matrix_file, filediag, threshold, dim_max, p, min_persistence); @@ -82,15 +75,12 @@ int main(int argc, char* argv[]) { Distance_matrix sparse_distances; distances = Gudhi::read_lower_triangular_matrix_from_csv_file(csv_matrix_file); - std::size_t number_of_points = distances.size(); - std::cout << "Read the distance matrix succesfully, of size: " << number_of_points << std::endl; + std::cout << "Read the distance matrix succesfully, of size: " << distances.size() << std::endl; - Filtered_sorted_edge_list edge_t; - std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; + Flag_complex_sparse_matrix::Filtered_sorted_edge_list edge_t; Rips_edge_list Rips_edge_list_from_file(distances, threshold); Rips_edge_list_from_file.create_edges(edge_t); - std::cout<< "Sorted edge list computed" << std::endl; if (edge_t.size() <= 0) { std::cerr << "Total number of egdes are zero." << std::endl; @@ -100,13 +90,11 @@ int main(int argc, char* argv[]) { std::cout << "Total number of edges before collapse are: " << edge_t.size() << std::endl; // Now we will perform filtered edge collapse to sparsify the edge list edge_t. - std::cout << "Filtered edge collapse begins" << std::endl; - Gudhi::collapse::Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); - std::cout << "Matrix instansiated" << std::endl; + Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); Simplex_tree stree; mat_filt_edge_coll.filtered_edge_collapse( - [&stree](std::vector edge, double filtration) { + [&stree](std::vector edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); stree.insert_simplex({edge[1]}, 0.); @@ -134,12 +122,6 @@ int main(int argc, char* argv[]) { pcoh.output_diagram(out); out.close(); } - - auto the_end = std::chrono::high_resolution_clock::now(); - - std::cout << "Total computation time : " << std::chrono::duration(the_end - the_begin).count() - << " ms\n" - << std::endl; return 0; } diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index 5fa24306..4b52e4c6 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -16,10 +16,11 @@ using Simplex_tree = Gudhi::Simplex_tree<>; using Filtration_value = Simplex_tree::Filtration_value; -using Vertex_handle = std::size_t; /*Simplex_tree::Vertex_handle;*/ +using Vertex_handle = Simplex_tree::Vertex_handle; using Point = std::vector; using Vector_of_points = std::vector; +using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -33,12 +34,6 @@ void program_options(int argc, char* argv[], std::string& off_file_points, std:: Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence); int main(int argc, char* argv[]) { - typedef std::vector> Filtered_sorted_edge_list; - - auto the_begin = std::chrono::high_resolution_clock::now(); - std::size_t number_of_points; - - std::string off_file_points; std::string filediag; double threshold; @@ -68,12 +63,8 @@ int main(int argc, char* argv[]) { exit(-1); // ----- >> } - //int dimension = point_vector[0].dimension(); - number_of_points = point_vector.size(); - std::cout << "Successfully read " << number_of_points << " point_vector.\n"; - //std::cout << "Ambient dimension is " << dimension << ".\n"; - - std::cout << "Point Set Generated." << std::endl; + std::cout << "Successfully read " << point_vector.size() << " point_vector.\n"; + std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n"; Adjacency_list proximity_graph = Gudhi::compute_proximity_graph(off_reader.get_point_cloud(), threshold, @@ -84,16 +75,11 @@ int main(int argc, char* argv[]) { exit(-1); } - std::cout << "Filtered edge collapse begins" << std::endl; - Gudhi::collapse::Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); - - std::cout << "Computing the one-skeleton for threshold: " << threshold << std::endl; - - std::cout << "Matrix instansiated" << std::endl; + Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); Simplex_tree stree; mat_filt_edge_coll.filtered_edge_collapse( - [&stree](std::vector edge, double filtration) { + [&stree](std::vector edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); stree.insert_simplex({edge[1]}, 0.); @@ -122,11 +108,6 @@ int main(int argc, char* argv[]) { out.close(); } - auto the_end = std::chrono::high_resolution_clock::now(); - - std::cout << "Total computation time : " << std::chrono::duration(the_end - the_begin).count() - << " ms\n" - << std::endl; return 0; } -- cgit v1.2.3 From 23ea38b9c879088c58e02ea4cf5aa5799e8d00b0 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sat, 11 Apr 2020 10:02:27 +0200 Subject: Proper copyrights and doc for utils --- .../include/gudhi/Flag_complex_sparse_matrix.h | 1 + src/Collapse/utilities/collapse.md | 63 ++++++++++++++++++++++ ...tance_matrix_edge_collapse_rips_persistence.cpp | 10 ++++ .../point_cloud_edge_collapse_rips_persistence.cpp | 10 ++++ 4 files changed, 84 insertions(+) create mode 100644 src/Collapse/utilities/collapse.md (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index edf3f415..09237500 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -5,6 +5,7 @@ * Copyright (C) 2018 Inria * * Modification(s): + * - 2020/03 Vincent Rouvreau: integration to the gudhi library * - YYYY/MM Author: Description of the modification */ diff --git a/src/Collapse/utilities/collapse.md b/src/Collapse/utilities/collapse.md new file mode 100644 index 00000000..9ca5077a --- /dev/null +++ b/src/Collapse/utilities/collapse.md @@ -0,0 +1,63 @@ +--- +layout: page +title: "Collapse" +meta_title: "Edge collapse" +teaser: "" +permalink: /collapse/ +--- +{::comment} +Leave the lines above as it is required by the web site generator 'Jekyll' +{:/comment} + + +## point_cloud_edge_collapse_rips_persistence ## +This program computes the one-skeleton graph defined on a set of input points, using Euclidean distance, and collapse edges. +This program finally computes persistent homology with coefficient field *Z/pZ* of the Rips complex built on top of these collapse edges. +The output diagram contains one bar per line, written with the convention: + +`p dim birth death` + +where `dim` is the dimension of the homological feature, `birth` and `death` are respectively the birth and death of the feature, and `p` is the characteristic of the field *Z/pZ* used for homology coefficients (`p` must be a prime number). + +**Usage** + +`point_cloud_edge_collapse_rips_persistence [options] ` + +**Allowed options** + +* `-h [ --help ]` Produce help message +* `-o [ --output-file ]` Name of file in which the persistence diagram is written. Default print in standard output. +* `-r [ --max-edge-length ]` (default = inf) Maximal length of an edge for the Rips complex construction. +* `-d [ --cpx-dimension ]` (default = 1) Maximal dimension of the Rips complex we want to compute. +* `-p [ --field-charac ]` (default = 11) Characteristic p of the coefficient field Z/pZ for computing homology. +* `-m [ --min-persistence ]` (default = 0) Minimal lifetime of homology feature to be recorded. Enter a negative value to see zero length intervals. + +Beware: this program may use a lot of RAM and take a lot of time if `max-edge-length` is set to a large value. + +**Example 1 with Z/2Z coefficients** + +`point_cloud_edge_collapse_rips_persistence ../../data/points/tore3D_1307.off -r 0.25 -m 0.5 -d 3 -p 2` + +**Example 2 with Z/3Z coefficients** + +`point_cloud_edge_collapse_rips_persistence ../../data/points/tore3D_1307.off -r 0.25 -m 0.5 -d 3 -p 3` + + +## distance_matrix_edge_collapse_rips_persistence ## + +Same as `point_cloud_edge_collapse_rips_persistence` but taking a distance matrix as input. + +**Usage** + +`distance_matrix_edge_collapse_rips_persistence [options] ` + +where +`` is the path to the file containing a distance matrix. Can be square or lower triangular matrix. Separator is ';'. +The code do not check if it is dealing with a distance matrix. It is the user responsibility to provide a valid input. +Please refer to data/distance_matrix/lower_triangular_distance_matrix.csv for an example of a file. + +**Example** + +`distance_matrix_edge_collapse_rips_persistence data/distance_matrix/full_square_distance_matrix.csv -r 15 -d 3 -p 3 -m 0` + + diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 56e9bab6..f6926224 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -1,3 +1,13 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Siddharth Pritam, Vincent Rouvreau + * + * Copyright (C) 2020 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + #include #include #include diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index 4b52e4c6..e322d3cd 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -1,3 +1,13 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Siddharth Pritam, Vincent Rouvreau + * + * Copyright (C) 2020 Inria + * + * Modification(s): + * - YYYY/MM Author: Description of the modification + */ + #include #include #include -- cgit v1.2.3 From f000725296c1962155e2ec331a3db6244d7c9f9e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sun, 12 Apr 2020 07:57:48 +0200 Subject: constify --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 09237500..d472bf15 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -135,13 +135,13 @@ class Flag_complex_sparse_matrix { Row_index rows; // Edge e is the actual edge (u,v). Not the row ids in the matrixs - bool check_edge_domination(Edge edge) + bool check_edge_domination(const Edge& edge) const { Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); - Row_index rw_u = vertex_to_row_[u]; - Row_index rw_v = vertex_to_row_[v]; + const Row_index rw_u = vertex_to_row_.at(u); + const Row_index rw_v = vertex_to_row_.at(v); auto rw_e = std::make_pair(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; @@ -246,7 +246,7 @@ class Flag_complex_sparse_matrix { } // Returns list of non-zero columns of a particular indx. - Row_indices_vector closed_neighbours_row_index(Row_index rw_u) + Row_indices_vector closed_neighbours_row_index(Row_index rw_u) const { Row_indices_vector non_zero_indices; #ifdef DEBUG_TRACES @@ -274,7 +274,7 @@ class Flag_complex_sparse_matrix { } // Returns the list of closed neighbours of the edge :{u,v}. - Row_indices_vector closed_common_neighbours_row_index(const std::pair& rw_edge) + Row_indices_vector closed_common_neighbours_row_index(const std::pair& rw_edge) const { Row_indices_vector common; Row_indices_vector non_zero_indices_u; @@ -290,7 +290,7 @@ class Flag_complex_sparse_matrix { return common; } - void insert_vertex(const Vertex_handle& vertex, Filtration_value filt_val) { + void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { auto rw = vertex_to_row_.find(vertex); if (rw == vertex_to_row_.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. @@ -302,7 +302,7 @@ class Flag_complex_sparse_matrix { } } - void insert_new_edges(const Vertex_handle& u, const Vertex_handle& v, Filtration_value filt_val) + void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); -- cgit v1.2.3 From 1ce5d0d19e13a14e8a67442aec7bc40eae68dc8e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Sun, 12 Apr 2020 10:33:38 +0200 Subject: Modify interface and utils --- .../include/gudhi/Flag_complex_sparse_matrix.h | 86 ++++++++------ src/Collapse/test/collapse_unit_test.cpp | 129 +++++++++++++-------- ...tance_matrix_edge_collapse_rips_persistence.cpp | 28 ++--- .../point_cloud_edge_collapse_rips_persistence.cpp | 15 +-- 4 files changed, 148 insertions(+), 110 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index d472bf15..e90d284d 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -16,6 +16,7 @@ #include #include +#include #include @@ -32,6 +33,7 @@ #include #include + namespace Gudhi { namespace collapse { @@ -47,26 +49,28 @@ namespace collapse { * Algorithm. * * \tparam Vertex_handle type must be a signed integer type. It admits a total order <. - * \tparam Filtration_value type for the value of the filtration function. Must be comparable with <. + * \tparam Filtration type for the value of the filtration function. Must be comparable with <. */ -template +template class Flag_complex_sparse_matrix { private: using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level // of row indices on actual vertex lables - using Filtered_edge = std::pair; + using Filtered_edge = std::pair; using Row_index = std::size_t; using Map_vertex_to_index = std::unordered_map; - using Sparse_row_matrix = Eigen::SparseMatrix; + using Sparse_row_matrix = Eigen::SparseMatrix; using Row_indices_vector = std::vector; public: - using Filtered_sorted_edge_list = std::vector>; + using Filtered_sorted_edge_list = std::vector>; + using Filtration_value = Filtration; + using Proximity_graph = Gudhi::Proximity_graph; private: std::unordered_map row_to_vertex_; @@ -88,9 +92,9 @@ class Flag_complex_sparse_matrix { // Boolean vector to indicate if the index is critical or not. std::vector dominated_edge_indicator_; // domination indicator - //! Stores the Map between vertices_row_to_vertex_ and row indices row_to_vertex_ -> row-index. + //! Stores the Map between verticesrow_to_vertex_ and row indices row_to_vertex_ -> row-index. /*! - So, if the original simplex tree had vertices_ 0,1,4,5
+ So, if the original simplex tree had vertices 0,1,4,5
row_to_vertex_ would store :
\verbatim Values = | 0 | 1 | 4 | 5 | @@ -106,10 +110,10 @@ class Flag_complex_sparse_matrix { */ std::unordered_map vertex_to_row_; - //! Stores the Sparse matrix of Filtration_value values representing the Original Simplicial Complex. + //! Stores the Sparse matrix of Filtration values representing the Original Simplicial Complex. /*! \code - Sparse_row_matrix = Eigen::SparseMatrix ; + Sparse_row_matrix = Eigen::SparseMatrix ; \endcode ; */ @@ -120,7 +124,7 @@ class Flag_complex_sparse_matrix { //! Stores true for dominated rows and false for undominated rows. /*! Initialised to a vector of length equal to the value of the variable rows with all false values. - Subsequent removal of dominated vertices_ is reflected by concerned entries changing to true in this vector. + Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. */ std::vector domination_indicator_; //(domination indicator) @@ -128,9 +132,9 @@ class Flag_complex_sparse_matrix { std::vector f_edge_vector_; - //! Stores the number of vertices_ in the original Simplicial Complex. + //! Stores the number of vertices in the original Simplicial Complex. /*! - This stores the count of vertices_ (which is also the number of rows in the Matrix). + This stores the count of vertices (which is also the number of rows in the Matrix). */ Row_index rows; @@ -202,7 +206,7 @@ class Flag_complex_sparse_matrix { } template - void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeInsertion filtered_edge_insert) { + void set_edge_critical(Row_index indx, Filtration filt, FilteredEdgeInsertion filtered_edge_insert) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; @@ -290,7 +294,7 @@ class Flag_complex_sparse_matrix { return common; } - void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { + void insert_vertex(Vertex_handle vertex, Filtration filt_val) { auto rw = vertex_to_row_.find(vertex); if (rw == vertex_to_row_.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. @@ -302,7 +306,7 @@ class Flag_complex_sparse_matrix { } } - void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) + void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); @@ -336,19 +340,27 @@ class Flag_complex_sparse_matrix { domination_indicator_ are initialised by init() function which is called at the begining of this.
*/ - Flag_complex_sparse_matrix(const Filtered_sorted_edge_list& edge_t) + template + Flag_complex_sparse_matrix(const DistanceMatrix& distance_matrix) : rows(0) { - for (size_t bgn_idx = 0; bgn_idx < edge_t.size(); bgn_idx++) { - Vertex_handle u = std::get<1>(edge_t[bgn_idx]); - Vertex_handle v = std::get<2>(edge_t[bgn_idx]); - f_edge_vector_.push_back({{u, v}, std::get<0>(edge_t[bgn_idx])}); - vertices_.emplace(u); - vertices_.emplace(v); + Vertex_handle num_vertices = std::distance(std::begin(distance_matrix), std::end(distance_matrix)); + + // This one is not part of the loop + vertices_.emplace(0); + // Only browse the lower part of the distance matrix + for (Vertex_handle line_index = 1; line_index < num_vertices; line_index++) { + for (Vertex_handle row_index = 0; row_index < line_index; row_index++) { +#ifdef DEBUG_TRACES + std::cout << "Insert edge: fn[" << row_index << ", " << line_index << "] = " + << distance_matrix[line_index][row_index] << std::endl; +#endif // DEBUG_TRACES + f_edge_vector_.push_back({{row_index, line_index}, distance_matrix[line_index][row_index]}); + } + vertices_.emplace(line_index); } } - template - Flag_complex_sparse_matrix(const OneSkeletonGraph& one_skeleton_graph) + Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) : rows(0) { // Insert all vertices_ for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { @@ -362,6 +374,18 @@ class Flag_complex_sparse_matrix { Vertex_handle v = target(edge, one_skeleton_graph); f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); } + } + + // Performs edge collapse in a decreasing sequence of the filtration value. + template + void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { + Row_index endIdx = 0; + + u_set_removed_redges_.clear(); + u_set_dominated_redges_.clear(); + critical_edge_indicator_.clear(); + + std::cout << "Sort it - " << f_edge_vector_.size() << std::endl; // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { @@ -373,17 +397,9 @@ class Flag_complex_sparse_matrix { #else std::stable_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif - } - - // Performs edge collapse in a decreasing sequence of the filtration value. - template - void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { - Row_index endIdx = 0; - - u_set_removed_redges_.clear(); - u_set_dominated_redges_.clear(); - critical_edge_indicator_.clear(); + std::cout << "Sorted" << std::endl; + std::cout << vertices_.size() << std::endl; // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices_.size(), vertices_.size()); @@ -392,7 +408,7 @@ class Flag_complex_sparse_matrix { Edge edge = std::get<0>(fec); Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); - Filtration_value filt = std::get<1>(fec); + Filtration filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) insert_new_edges(u, v, filt); diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 38adfa8a..3a07e088 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE "collapse" @@ -32,7 +33,7 @@ bool find_edge_in_list(const Filtered_edge& edge, const Filtered_sorted_edge_lis } return false; } - +/* void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filtered_sorted_edge_list& removed_edges) { std::cout << "BEFORE COLLAPSE - Total number of edges: " << edges.size() << std::endl; BOOST_CHECK(edges.size() > 0); @@ -68,70 +69,104 @@ void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filt } BOOST_AUTO_TEST_CASE(collapse) { - /* - 1 2 - o---o - | | - | | - | | - o---o - 0 3 - */ + // 1 2 + // o---o + // | | + // | | + // | | + // o---o + // 0 3 Filtered_sorted_edge_list edges {{1., 0, 1}, {1., 1, 2}, {1., 2, 3}, {1., 3, 0}}; trace_and_check_collapse(edges, {}); - /* - 1 2 - o---o - |\ /| - | x | - |/ \| - o---o - 0 3 - */ + // 1 2 + // o---o + // |\ /| + // | x | + // |/ \| + // o---o + // 0 3 edges.push_back({2., 0, 2}); edges.push_back({2., 1, 3}); trace_and_check_collapse(edges, {{2., 1, 3}}); - /* - 1 2 4 - o---o---o - |\ /| | - | x | | - |/ \| | - o---o---o - 0 3 5 - */ + // 1 2 4 + // o---o---o + // |\ /| | + // | x | | + // |/ \| | + // o---o---o + // 0 3 5 edges.push_back({3., 2, 4}); edges.push_back({3., 4, 5}); edges.push_back({3., 5, 3}); trace_and_check_collapse(edges, {{2., 1, 3}}); - /* - 1 2 4 - o---o---o - |\ /|\ /| - | x | x | - |/ \|/ \| - o---o---o - 0 3 5 - */ + // 1 2 4 + // o---o---o + // |\ /|\ /| + // | x | x | + // |/ \|/ \| + // o---o---o + // 0 3 5 edges.push_back({4., 2, 5}); edges.push_back({4., 4, 3}); trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}}); - /* - 1 2 4 - o---o---o - |\ /|\ /| - | x | x | + [0,4] and [1,5] - |/ \|/ \| - o---o---o - 0 3 5 - */ + // 1 2 4 + // o---o---o + // |\ /|\ /| + // | x | x | + [0,4] and [1,5] + // |/ \|/ \| + // o---o---o + // 0 3 5 edges.push_back({5., 1, 5}); edges.push_back({5., 0, 4}); trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}, {5., 0, 4}}); -} +}*/ + + +BOOST_AUTO_TEST_CASE(collapse_from_distance_matrix) { + // 1 2 + // o---o + // |\ /| + // | x | + // |/ \| + // o---o + // 0 3 + // Lower diagonal distance matrix + std::array, 4> distance_matrix = {{{0., 0., 0., 0.}, + {1., 0., 0., 0.}, + {2., 1., 0., 0.}, + {1., 2., 1., 0.} }}; + + std::cout << "COLLAPSE - keep edges: " << std::endl; + Flag_complex_sparse_matrix flag_complex_sparse_matrix(distance_matrix); + Filtered_sorted_edge_list collapse_edges; + flag_complex_sparse_matrix.filtered_edge_collapse( + [&collapse_edges](std::pair edge, Filtration_value filtration) { + std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; + collapse_edges.push_back({filtration, std::get<0>(edge), std::get<1>(edge)}); + }); + std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; + BOOST_CHECK(collapse_edges.size() == 5); + Filtered_sorted_edge_list edges {{1., 0, 1}, {1., 1, 2}, {1., 2, 3}, {1., 0, 3}, {2., 0, 2}, {2., 1, 3}}; + + for (auto edge_from_collapse : collapse_edges) { + std::cout << "f[" << std::get<1>(edge_from_collapse) << ", " << std::get<2>(edge_from_collapse) << "] = " + << std::get<0>(edge_from_collapse) << std::endl; + // Check each edge from collapse is in the input + BOOST_CHECK(find_edge_in_list(edge_from_collapse, edges)); + } + Filtered_sorted_edge_list removed_edges {{2., 1, 3}}; + + std::cout << "CHECK COLLAPSE - Total number of removed edges: " << removed_edges.size() << std::endl; + for (auto removed_edge : removed_edges) { + std::cout << "f[" << std::get<1>(removed_edge) << ", " << std::get<2>(removed_edge) << "] = " + << std::get<0>(removed_edge) << std::endl; + // Check each removed edge from collapse is in the input + BOOST_CHECK(!find_edge_in_list(removed_edge, collapse_edges)); + } +} \ No newline at end of file diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index f6926224..f4a460ab 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -11,10 +11,8 @@ #include #include #include -#include -#include #include -#include +#include #include @@ -23,8 +21,8 @@ using Filtration_value = Simplex_tree::Filtration_value; using Vertex_handle = Simplex_tree::Vertex_handle; using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; +using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; -using Rips_edge_list = Gudhi::rips_edge_list::Rips_edge_list; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; using Distance_matrix = std::vector>; @@ -82,28 +80,22 @@ int main(int argc, char* argv[]) { program_options(argc, argv, csv_matrix_file, filediag, threshold, dim_max, p, min_persistence); Distance_matrix distances; - Distance_matrix sparse_distances; distances = Gudhi::read_lower_triangular_matrix_from_csv_file(csv_matrix_file); std::cout << "Read the distance matrix succesfully, of size: " << distances.size() << std::endl; - Flag_complex_sparse_matrix::Filtered_sorted_edge_list edge_t; - - Rips_edge_list Rips_edge_list_from_file(distances, threshold); - Rips_edge_list_from_file.create_edges(edge_t); - - if (edge_t.size() <= 0) { - std::cerr << "Total number of egdes are zero." << std::endl; - exit(-1); - } - - std::cout << "Total number of edges before collapse are: " << edge_t.size() << std::endl; + Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(boost::irange((size_t)0, + distances.size()), + threshold, + [&distances](size_t i, size_t j) { + return distances[j][i]; + }); // Now we will perform filtered edge collapse to sparsify the edge list edge_t. - Flag_complex_sparse_matrix mat_filt_edge_coll(edge_t); + Flag_complex_sparse_matrix flag_complex(proximity_graph); Simplex_tree stree; - mat_filt_edge_coll.filtered_edge_collapse( + flag_complex.filtered_edge_collapse( [&stree](std::vector edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index e322d3cd..b9130d4c 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -12,11 +12,9 @@ #include #include #include -#include #include #include -#include #include #include // for std::pair @@ -31,15 +29,12 @@ using Point = std::vector; using Vector_of_points = std::vector; using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; +using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; using Distance_matrix = std::vector>; -using Adjacency_list = boost::adjacency_list, - boost::property>; - void program_options(int argc, char* argv[], std::string& off_file_points, std::string& filediag, Filtration_value& threshold, int& dim_max, int& p, Filtration_value& min_persistence); @@ -76,9 +71,9 @@ int main(int argc, char* argv[]) { std::cout << "Successfully read " << point_vector.size() << " point_vector.\n"; std::cout << "Ambient dimension is " << point_vector[0].size() << ".\n"; - Adjacency_list proximity_graph = Gudhi::compute_proximity_graph(off_reader.get_point_cloud(), - threshold, - Gudhi::Euclidean_distance()); + Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(off_reader.get_point_cloud(), + threshold, + Gudhi::Euclidean_distance()); if (num_edges(proximity_graph) <= 0) { std::cerr << "Total number of egdes are zero." << std::endl; @@ -89,7 +84,7 @@ int main(int argc, char* argv[]) { Simplex_tree stree; mat_filt_edge_coll.filtered_edge_collapse( - [&stree](std::vector edge, Filtration_value filtration) { + [&stree](const std::vector& edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); stree.insert_simplex({edge[1]}, 0.); -- cgit v1.2.3 From 8c7eafebb4db99057820ddc226c5e9d55e95c31d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 13 Apr 2020 11:44:29 +0200 Subject: Remove Rips_edge_list and review the interfaces --- .../include/gudhi/Flag_complex_sparse_matrix.h | 66 ++++---- src/Collapse/include/gudhi/Rips_edge_list.h | 184 --------------------- src/Collapse/test/collapse_unit_test.cpp | 159 ++++++++++-------- 3 files changed, 117 insertions(+), 292 deletions(-) delete mode 100644 src/Collapse/include/gudhi/Rips_edge_list.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index e90d284d..e225f7db 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -12,7 +12,6 @@ #ifndef FLAG_COMPLEX_SPARSE_MATRIX_H_ #define FLAG_COMPLEX_SPARSE_MATRIX_H_ -#include #include #include @@ -25,14 +24,14 @@ #endif #include -#include +#include // for std::pair #include -#include #include -#include -#include -#include - +#include +#include +#include // for std::tie +#include // for std::includes +#include // for std::inserter namespace Gudhi { @@ -48,28 +47,29 @@ namespace collapse { * A class to store the vertices v/s MaxSimplices Sparse Matrix and to perform collapse operations using the N^2() * Algorithm. * - * \tparam Vertex_handle type must be a signed integer type. It admits a total order <. + * \tparam Vertex type must be a signed integer type. It admits a total order <. * \tparam Filtration type for the value of the filtration function. Must be comparable with <. */ -template +template class Flag_complex_sparse_matrix { + public: + using Vertex_handle = Vertex; + using Filtration_value = Filtration; private: using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first // element being the smaller i.e {2,3} not {3,2}. However this is at the level // of row indices on actual vertex lables - using Filtered_edge = std::pair; using Row_index = std::size_t; using Map_vertex_to_index = std::unordered_map; - using Sparse_row_matrix = Eigen::SparseMatrix; + using Sparse_row_matrix = Eigen::SparseMatrix; using Row_indices_vector = std::vector; public: - using Filtered_sorted_edge_list = std::vector>; - using Filtration_value = Filtration; + using Filtered_edge = std::pair; using Proximity_graph = Gudhi::Proximity_graph; private: @@ -113,7 +113,7 @@ class Flag_complex_sparse_matrix { //! Stores the Sparse matrix of Filtration values representing the Original Simplicial Complex. /*! \code - Sparse_row_matrix = Eigen::SparseMatrix ; + Sparse_row_matrix = Eigen::SparseMatrix ; \endcode ; */ @@ -206,7 +206,7 @@ class Flag_complex_sparse_matrix { } template - void set_edge_critical(Row_index indx, Filtration filt, FilteredEdgeInsertion filtered_edge_insert) { + void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeInsertion filtered_edge_insert) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; @@ -294,7 +294,7 @@ class Flag_complex_sparse_matrix { return common; } - void insert_vertex(Vertex_handle vertex, Filtration filt_val) { + void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { auto rw = vertex_to_row_.find(vertex); if (rw == vertex_to_row_.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. @@ -306,7 +306,7 @@ class Flag_complex_sparse_matrix { } } - void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration filt_val) + void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); @@ -340,23 +340,16 @@ class Flag_complex_sparse_matrix { domination_indicator_ are initialised by init() function which is called at the begining of this.
*/ - template - Flag_complex_sparse_matrix(const DistanceMatrix& distance_matrix) - : rows(0) { - Vertex_handle num_vertices = std::distance(std::begin(distance_matrix), std::end(distance_matrix)); - - // This one is not part of the loop - vertices_.emplace(0); - // Only browse the lower part of the distance matrix - for (Vertex_handle line_index = 1; line_index < num_vertices; line_index++) { - for (Vertex_handle row_index = 0; row_index < line_index; row_index++) { -#ifdef DEBUG_TRACES - std::cout << "Insert edge: fn[" << row_index << ", " << line_index << "] = " - << distance_matrix[line_index][row_index] << std::endl; -#endif // DEBUG_TRACES - f_edge_vector_.push_back({{row_index, line_index}, distance_matrix[line_index][row_index]}); - } - vertices_.emplace(line_index); + template + Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) + : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()), + rows(0) { + for (Filtered_edge filtered_edge : filtered_edge_range) { + Vertex_handle u; + Vertex_handle v; + std::tie(u,v) = std::get<0>(filtered_edge); + vertices_.emplace(u); + vertices_.emplace(v); } } @@ -385,7 +378,6 @@ class Flag_complex_sparse_matrix { u_set_dominated_redges_.clear(); critical_edge_indicator_.clear(); - std::cout << "Sort it - " << f_edge_vector_.size() << std::endl; // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { @@ -397,9 +389,7 @@ class Flag_complex_sparse_matrix { #else std::stable_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif - std::cout << "Sorted" << std::endl; - std::cout << vertices_.size() << std::endl; // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices_.size(), vertices_.size()); @@ -408,7 +398,7 @@ class Flag_complex_sparse_matrix { Edge edge = std::get<0>(fec); Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); - Filtration filt = std::get<1>(fec); + Filtration_value filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) insert_new_edges(u, v, filt); diff --git a/src/Collapse/include/gudhi/Rips_edge_list.h b/src/Collapse/include/gudhi/Rips_edge_list.h deleted file mode 100644 index b7c4dcff..00000000 --- a/src/Collapse/include/gudhi/Rips_edge_list.h +++ /dev/null @@ -1,184 +0,0 @@ -/* 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(s): Clément Maria, Pawel Dlotko, Vincent Rouvreau Siddharth Pritam - * - * Copyright (C) 2016 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 RIPS_edge_list_H_ -#define RIPS_edge_list_H_ - -#include -#include -#include - -#include -#include -#include -#include -#include // for numeric_limits -#include // for pair<> - - -namespace Gudhi { - -namespace rips_edge_list { - -/** - * \class Rips_complex - * \brief Rips complex data structure. - * - * \ingroup rips_complex - * - * \details - * The data structure is a one skeleton graph, or Rips graph, containing edges when the edge length is less or equal - * to a given threshold. Edge length is computed from a user given point cloud with a given distance function, or a - * distance matrix. - * - * \tparam Filtration_value is the type used to store the filtration values of the simplicial complex. - */ -template -class Rips_edge_list { - public: - /** - * \brief Type of the one skeleton graph stored inside the Rips complex structure. - */ - // typedef typename boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS - // , boost::property < vertex_filtration_t, Filtration_value > - // , boost::property < edge_filtration_t, Filtration_value >> OneSkeletonGraph; - - private: - typedef int Vertex_handle; - - public: - /** \brief Rips_complex constructor from a list of points. - * - * @param[in] points Range of points. - * @param[in] threshold Rips value. - * @param[in] distance distance function that returns a `Filtration_value` from 2 given points. - * - * \tparam ForwardPointRange must be a range for which `std::begin` and `std::end` return input iterators on a - * point. - * - * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where - * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. - */ - template - Rips_edge_list(const ForwardPointRange& points, Filtration_value threshold, Distance distance) { - compute_proximity_graph(points, threshold, distance); - } - - /** \brief Rips_complex constructor from a distance matrix. - * - * @param[in] distance_matrix Range of distances. - * @param[in] threshold Rips value. - * - * \tparam DistanceMatrix must have a `size()` method and on which `distance_matrix[i][j]` returns - * the distance between points \f$i\f$ and \f$j\f$ as long as \f$ 0 \leqslant i < j \leqslant - * distance\_matrix.size().\f$ - */ - template - Rips_edge_list(const DistanceMatrix& distance_matrix, Filtration_value threshold) { - compute_proximity_graph(boost::irange((size_t)0, distance_matrix.size()), threshold, - [&](size_t i, size_t j){return distance_matrix[j][i];}); - } - - /** \brief Initializes the egde list (one skeleton) complex from the Rips graph - * - * \tparam EdgeListForRips must meet `EdgeListForRips` concept. - * - * @param[in] edges EdgeListForRips to be created. - * @param[in] dim_max graph expansion for Rips until this given maximal dimension. - * @exception std::invalid_argument In debug mode, if `edges.num_vertices()` does not return 0. - * - */ - template - void create_edges(EdgeListForRips& edge_list) { - GUDHI_CHECK(edges.num_vertices() == 0, - std::invalid_argument("Rips_complex::create_complex - edge list is not empty")); - - // sort the tuple (filteration_valuem, (v1,v2){edge}) - //By default the sort is done on the first element, so here it's filteration value. - std::sort(edges.begin(),edges.end()); - for(size_t i = 0; i < edges.size(); i++ ) - edge_list.emplace_back(edges.at(i)); - - } - - private: - /** \brief Computes the proximity graph of the points. - * - * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the - * distance function between points u and v is smaller than threshold. - * - * \tparam ForwardPointRange furnishes `.begin()` and `.end()` - * methods. - * - * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where - * `Point` is a point from the `ForwardPointRange`, and that returns a `Filtration_value`. - */ - template< typename ForwardPointRange, typename Distance > - void compute_proximity_graph(const ForwardPointRange& points, Filtration_value threshold, - Distance distance) { - edges.clear(); - // Compute the proximity graph of the points. - // If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the - // distance function between points u and v is smaller than threshold. - // -------------------------------------------------------------------------------------------- - // Creates the vector of edges and its filtration values (returned by distance function) - Vertex_handle idx_u = 0; - for (auto it_u = std::begin(points); it_u != std::end(points); ++it_u, ++idx_u) { - Vertex_handle idx_v = idx_u + 1; - for (auto it_v = it_u + 1; it_v != std::end(points); ++it_v, ++idx_v) { - Filtration_value fil = distance(*it_u, *it_v); - if (fil <= threshold) { - edges.emplace_back(fil, idx_u, idx_v); - } - } - } - - // -------------------------------------------------------------------------------------------- - // Creates the proximity graph from edges and sets the property with the filtration value. - // Number of points is labeled from 0 to idx_u-1 - // -------------------------------------------------------------------------------------------- - // Do not use : rips_skeleton_graph_ = OneSkeletonGraph(...) -> deep copy of the graph (boost graph is not - // move-enabled) - // rips_skeleton_graph_.~OneSkeletonGraph(); - // new(&rips_skeleton_graph_)OneSkeletonGraph(edges.begin(), edges.end(), edges_fil.begin(), idx_u); - - // auto vertex_prop = boost::get(vertex_filtration_t(), rips_skeleton_graph_); - - // using vertex_iterator = typename boost::graph_traits::vertex_iterator; - // vertex_iterator vi, vi_end; - // for (std::tie(vi, vi_end) = boost::vertices(rips_skeleton_graph_); - // vi != vi_end; ++vi) { - // boost::put(vertex_prop, *vi, 0.); - // } - } - - private: - // OneSkeletonGraph rips_skeleton_graph_; - std::vector< std::tuple < Filtration_value, Vertex_handle, Vertex_handle > > edges; - // std::vector< Filtration_value > edges_fil; -}; - -} // namespace rips_complex - -} // namespace Gudhi - -#endif // RIPS_COMPLEX_H_ diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 3a07e088..1bec3810 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -8,67 +8,77 @@ * - YYYY/MM Author: Description of the modification */ -#include -#include -#include -#include #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE "collapse" #include #include -#include "gudhi/Flag_complex_sparse_matrix.h" +#include +#include +#include + +#include +#include +#include +#include +#include using Filtration_value = float; using Vertex_handle = short; -using Filtered_edge = std::tuple; -using Filtered_sorted_edge_list = std::vector; using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; +using Filtered_edge = Flag_complex_sparse_matrix::Filtered_edge; +using Filtered_edge_list = std::vector; -bool find_edge_in_list(const Filtered_edge& edge, const Filtered_sorted_edge_list& edge_list) { +template +bool find_edge_in_list(const Filtered_edge& edge, const Filtered_edge_range& edge_list) { for (auto edge_from_list : edge_list) { if (edge_from_list == edge) return true; } return false; } -/* -void trace_and_check_collapse(const Filtered_sorted_edge_list& edges, const Filtered_sorted_edge_list& removed_edges) { - std::cout << "BEFORE COLLAPSE - Total number of edges: " << edges.size() << std::endl; - BOOST_CHECK(edges.size() > 0); - for (auto edge : edges) { - std::cout << "f[" << std::get<1>(edge) << ", " << std::get<2>(edge) << "] = " << std::get<0>(edge) << std::endl; + +template +void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const Filtered_edge_list& removed_edges) { + std::cout << "BEFORE COLLAPSE - Total number of edges: " << filtered_edges.size() << std::endl; + BOOST_CHECK(filtered_edges.size() > 0); + for (auto filtered_edge : filtered_edges) { + auto edge = std::get<0>(filtered_edge); + std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << std::get<1>(filtered_edge) << std::endl; } std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_sparse_matrix flag_complex_sparse_matrix(edges); - Filtered_sorted_edge_list collapse_edges; + Flag_complex_sparse_matrix flag_complex_sparse_matrix(filtered_edges); + Filtered_edge_list collapse_edges; flag_complex_sparse_matrix.filtered_edge_collapse( [&collapse_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - collapse_edges.push_back({filtration, std::get<0>(edge), std::get<1>(edge)}); + collapse_edges.push_back({edge, filtration}); }); std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; - BOOST_CHECK(collapse_edges.size() <= edges.size()); - for (auto edge_from_collapse : collapse_edges) { - std::cout << "f[" << std::get<1>(edge_from_collapse) << ", " << std::get<2>(edge_from_collapse) << "] = " - << std::get<0>(edge_from_collapse) << std::endl; + BOOST_CHECK(collapse_edges.size() <= filtered_edges.size()); + for (auto filtered_edge_from_collapse : collapse_edges) { + auto edge_from_collapse = std::get<0>(filtered_edge_from_collapse); + std::cout << "f[" << std::get<0>(edge_from_collapse) << ", " << std::get<1>(edge_from_collapse) << "] = " + << std::get<1>(filtered_edge_from_collapse) << std::endl; // Check each edge from collapse is in the input - BOOST_CHECK(find_edge_in_list(edge_from_collapse, edges)); + BOOST_CHECK(find_edge_in_list(filtered_edge_from_collapse, filtered_edges)); } std::cout << "CHECK COLLAPSE - Total number of removed edges: " << removed_edges.size() << std::endl; - for (auto removed_edge : removed_edges) { - std::cout << "f[" << std::get<1>(removed_edge) << ", " << std::get<2>(removed_edge) << "] = " - << std::get<0>(removed_edge) << std::endl; + for (auto removed_filtered_edge : removed_edges) { + auto removed_edge = std::get<0>(removed_filtered_edge); + std::cout << "f[" << std::get<0>(removed_edge) << ", " << std::get<1>(removed_edge) << "] = " + << std::get<1>(removed_filtered_edge) << std::endl; // Check each removed edge from collapse is in the input - BOOST_CHECK(!find_edge_in_list(removed_edge, collapse_edges)); + BOOST_CHECK(!find_edge_in_list(removed_filtered_edge, collapse_edges)); } } BOOST_AUTO_TEST_CASE(collapse) { + std::cout << "***** COLLAPSE *****" << std::endl; // 1 2 // o---o // | | @@ -76,7 +86,7 @@ BOOST_AUTO_TEST_CASE(collapse) { // | | // o---o // 0 3 - Filtered_sorted_edge_list edges {{1., 0, 1}, {1., 1, 2}, {1., 2, 3}, {1., 3, 0}}; + Filtered_edge_list edges {{{0, 1}, 1.}, {{1, 2}, 1.}, {{2, 3}, 1.}, {{3, 0}, 1.}}; trace_and_check_collapse(edges, {}); // 1 2 @@ -86,9 +96,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| // o---o // 0 3 - edges.push_back({2., 0, 2}); - edges.push_back({2., 1, 3}); - trace_and_check_collapse(edges, {{2., 1, 3}}); + edges.push_back({{0, 2}, 2.}); + edges.push_back({{1, 3}, 2.}); + trace_and_check_collapse(edges, {{{1, 3}, 2.}}); // 1 2 4 // o---o---o @@ -97,10 +107,10 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| | // o---o---o // 0 3 5 - edges.push_back({3., 2, 4}); - edges.push_back({3., 4, 5}); - edges.push_back({3., 5, 3}); - trace_and_check_collapse(edges, {{2., 1, 3}}); + edges.push_back({{2, 4}, 3.}); + edges.push_back({{4, 5}, 3.}); + edges.push_back({{5, 3}, 3.}); + trace_and_check_collapse(edges, {{{1, 3}, 2.}}); // 1 2 4 // o---o---o @@ -109,9 +119,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.push_back({4., 2, 5}); - edges.push_back({4., 4, 3}); - trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}}); + edges.push_back({{2, 5}, 4.}); + edges.push_back({{4, 3}, 4.}); + trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}}); // 1 2 4 // o---o---o @@ -120,13 +130,27 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.push_back({5., 1, 5}); - edges.push_back({5., 0, 4}); - trace_and_check_collapse(edges, {{2., 1, 3}, {4., 4, 3}, {5., 0, 4}}); -}*/ + edges.push_back({{1, 5}, 5.}); + edges.push_back({{0, 4}, 5.}); + trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}, {{0, 4}, 5.}}); +} + +BOOST_AUTO_TEST_CASE(collapse_from_array) { + std::cout << "***** COLLAPSE FROM ARRAY *****" << std::endl; + // 1 2 + // o---o + // |\ /| + // | x | + // |/ \| + // o---o + // 0 3 + std::array f_edge_array = {{{{0, 1}, 1.}, {{1, 2}, 1.}, {{2, 3}, 1.}, {{3, 0}, 1.}, {{0, 2}, 2.}, {{1, 3}, 2.}}}; + trace_and_check_collapse(f_edge_array, {{{1, 3}, 2.}}); +} -BOOST_AUTO_TEST_CASE(collapse_from_distance_matrix) { +BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { + std::cout << "***** COLLAPSE FROM PROXIMITY GRAPH *****" << std::endl; // 1 2 // o---o // |\ /| @@ -134,39 +158,34 @@ BOOST_AUTO_TEST_CASE(collapse_from_distance_matrix) { // |/ \| // o---o // 0 3 - // Lower diagonal distance matrix - std::array, 4> distance_matrix = {{{0., 0., 0., 0.}, - {1., 0., 0., 0.}, - {2., 1., 0., 0.}, - {1., 2., 1., 0.} }}; - - std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_sparse_matrix flag_complex_sparse_matrix(distance_matrix); - Filtered_sorted_edge_list collapse_edges; + std::vector> point_cloud = {{0., 0.}, + {0., 1.}, + {1., 0.}, + {1., 1.} }; + + Filtration_value threshold = std::numeric_limits::infinity(); + using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; + Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(point_cloud, + threshold, + Gudhi::Euclidean_distance()); + Flag_complex_sparse_matrix flag_complex_sparse_matrix(proximity_graph); + Filtered_edge_list collapse_edges; flag_complex_sparse_matrix.filtered_edge_collapse( [&collapse_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - collapse_edges.push_back({filtration, std::get<0>(edge), std::get<1>(edge)}); + collapse_edges.push_back({edge, filtration}); }); - std::cout << "AFTER COLLAPSE - Total number of edges: " << collapse_edges.size() << std::endl; BOOST_CHECK(collapse_edges.size() == 5); - Filtered_sorted_edge_list edges {{1., 0, 1}, {1., 1, 2}, {1., 2, 3}, {1., 0, 3}, {2., 0, 2}, {2., 1, 3}}; - - for (auto edge_from_collapse : collapse_edges) { - std::cout << "f[" << std::get<1>(edge_from_collapse) << ", " << std::get<2>(edge_from_collapse) << "] = " - << std::get<0>(edge_from_collapse) << std::endl; - // Check each edge from collapse is in the input - BOOST_CHECK(find_edge_in_list(edge_from_collapse, edges)); - } - - Filtered_sorted_edge_list removed_edges {{2., 1, 3}}; - - std::cout << "CHECK COLLAPSE - Total number of removed edges: " << removed_edges.size() << std::endl; - for (auto removed_edge : removed_edges) { - std::cout << "f[" << std::get<1>(removed_edge) << ", " << std::get<2>(removed_edge) << "] = " - << std::get<0>(removed_edge) << std::endl; - // Check each removed edge from collapse is in the input - BOOST_CHECK(!find_edge_in_list(removed_edge, collapse_edges)); + std::size_t filtration_is_edge_length_nb = 0; + std::size_t filtration_is_diagonal_length_nb = 0; + float epsilon = std::numeric_limits::epsilon(); + for (auto filtered_edge : collapse_edges) { + if (std::get<1>(filtered_edge) == 1.) + filtration_is_edge_length_nb++; + if (std::fabs(std::get<1>(filtered_edge) - std::sqrt(2.)) <= epsilon) + filtration_is_diagonal_length_nb++; } + BOOST_CHECK(filtration_is_edge_length_nb == 4); + BOOST_CHECK(filtration_is_diagonal_length_nb == 1); } \ No newline at end of file -- cgit v1.2.3 From 1e1b7aa9b3855499c754551a84802c1f92d24f84 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 13 Apr 2020 22:53:52 +0200 Subject: Add some documentation --- .../include/gudhi/Flag_complex_sparse_matrix.h | 154 ++++++++++----------- 1 file changed, 72 insertions(+), 82 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index e225f7db..ee957294 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -53,90 +53,70 @@ namespace collapse { template class Flag_complex_sparse_matrix { public: + // Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph using Vertex_handle = Vertex; + // Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph using Filtration_value = Filtration; private: - using Edge = std::pair; // This is an ordered pair, An edge is stored with convention of the first - // element being the smaller i.e {2,3} not {3,2}. However this is at the level - // of row indices on actual vertex lables + // This is an ordered pair, An edge is stored with convention of the first + // element being the smaller i.e {2,3} not {3,2}. However this is at the level + // of row indices on actual vertex lables + using Edge = std::pair; + // Row_index type in the sparse matrix using Row_index = std::size_t; - using Map_vertex_to_index = std::unordered_map; - + // The sparse matrix data type using Sparse_row_matrix = Eigen::SparseMatrix; + // A range of row indices using Row_indices_vector = std::vector; public: + // A Filtered_edge is a std::pair, Filtration_value> using Filtered_edge = std::pair; + // Proximity_graph is a type that can be used to construct easily a Flag_complex_sparse_matrix using Proximity_graph = Gudhi::Proximity_graph; private: + // Map from row index to its vertex handle std::unordered_map row_to_vertex_; // Vertices stored as an unordered_set std::unordered_set vertices_; - // Unordered set of removed edges. (to enforce removal from the matrix) - std::unordered_set> u_set_removed_redges_; + // Unordered set of removed edges. (to enforce removal from the matrix) + std::unordered_set> u_set_removed_edges_; - // Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_redges_; + // Unordered set of dominated edges. (to inforce removal from the matrix) + std::unordered_set> u_set_dominated_edges_; // Map from edge to its index std::unordered_map> edge_to_index_map_; - // Boolean vector to indicate if the index is critical or not. - std::vector critical_edge_indicator_; // critical indicator // Boolean vector to indicate if the index is critical or not. - std::vector dominated_edge_indicator_; // domination indicator - - //! Stores the Map between verticesrow_to_vertex_ and row indices row_to_vertex_ -> row-index. - /*! - So, if the original simplex tree had vertices 0,1,4,5
- row_to_vertex_ would store :
- \verbatim - Values = | 0 | 1 | 4 | 5 | - Indices = 0 1 2 3 - \endverbatim - And vertex_to_row_ would be a map like the following :
- \verbatim - 0 -> 0 - 1 -> 1 - 4 -> 2 - 5 -> 3 - \endverbatim - */ - std::unordered_map vertex_to_row_; + std::vector critical_edge_indicator_; - //! Stores the Sparse matrix of Filtration values representing the Original Simplicial Complex. - /*! - \code - Sparse_row_matrix = Eigen::SparseMatrix ; - \endcode - ; - */ + // Map from vertex handle to its row index + std::unordered_map vertex_to_row_; - Sparse_row_matrix sparse_row_adjacency_matrix_; // This is row-major version of the same sparse-matrix, to facilitate easy access - // to elements when traversing the matrix row-wise. + // Stores the Sparse matrix of Filtration values representing the original graph. + // This is row-major version of the same sparse-matrix, to facilitate easy access + // to elements when traversing the matrix row-wise. + Sparse_row_matrix sparse_row_adjacency_matrix_; - //! Stores true for dominated rows and false for undominated rows. - /*! - Initialised to a vector of length equal to the value of the variable rows with all false values. - Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. - */ - std::vector domination_indicator_; //(domination indicator) + // Stores true for dominated rows and false otherwise. + // Initialised to a vector of length equal to the value of the variable rows_ with all false values. + // Subsequent removal of dominated vertices is reflected by concerned entries changing to true + // in this vector. + std::vector domination_indicator_; // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. std::vector f_edge_vector_; - //! Stores the number of vertices in the original Simplicial Complex. - /*! - This stores the count of vertices (which is also the number of rows in the Matrix). - */ - Row_index rows; + //! Stores the number of vertices in the original graph (which is also the number of rows in the Matrix). + Row_index rows_; // Edge e is the actual edge (u,v). Not the row ids in the matrixs bool check_edge_domination(const Edge& edge) const @@ -205,23 +185,23 @@ class Flag_complex_sparse_matrix { return edge_indices; } + // Detect and set all indices that are becoming critical template void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeInsertion filtered_edge_insert) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; #endif // DEBUG_TRACES - std::set effectedIndcs = three_clique_indices(indx); - if (effectedIndcs.size() > 0) { + std::set effected_indices = three_clique_indices(indx); + if (effected_indices.size() > 0) { for (auto idx = indx - 1; idx > 0; idx--) { Edge edge = std::get<0>(f_edge_vector_[idx]); Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); - // If idx is not critical so it should be proceses, otherwise it stays in the graph // prev - // code : recurCriticalCoreIndcs.find(idx) == recurCriticalCoreIndcs.end() + // If idx is not critical so it should be processed, otherwise it stays in the graph if (not critical_edge_indicator_[idx]) { // If idx is affected - if (effectedIndcs.find(idx) != effectedIndcs.end()) { + if (effected_indices.find(idx) != effected_indices.end()) { if (not check_edge_domination(edge)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; @@ -230,7 +210,7 @@ class Flag_complex_sparse_matrix { filtered_edge_insert({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { - if (*inr_idx < idx) effectedIndcs.emplace(*inr_idx); + if (*inr_idx < idx) effected_indices.emplace(*inr_idx); } inner_effected_indcs.clear(); #ifdef DEBUG_TRACES @@ -238,15 +218,15 @@ class Flag_complex_sparse_matrix { << filt << std::endl; #endif // DEBUG_TRACES } else - u_set_dominated_redges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); + u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } else // Idx is not affected hence dominated. - u_set_dominated_redges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); + u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } } } - effectedIndcs.clear(); - u_set_dominated_redges_.clear(); + effected_indices.clear(); + u_set_dominated_edges_.clear(); } // Returns list of non-zero columns of a particular indx. @@ -261,8 +241,8 @@ class Flag_complex_sparse_matrix { for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not domination_indicator_[rw_v] and u_set_removed_redges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_redges_.end() and - u_set_dominated_redges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_redges_.end()) { + if (not domination_indicator_[rw_v] and u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() and + u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES @@ -294,18 +274,20 @@ class Flag_complex_sparse_matrix { return common; } + // Insert a vertex in the data structure void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { auto rw = vertex_to_row_.find(vertex); if (rw == vertex_to_row_.end()) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix_.insert(rows, rows) = filt_val; + sparse_row_adjacency_matrix_.insert(rows_, rows_) = filt_val; domination_indicator_.push_back(false); - vertex_to_row_.insert(std::make_pair(vertex, rows)); - row_to_vertex_.insert(std::make_pair(rows, vertex)); - rows++; + vertex_to_row_.insert(std::make_pair(vertex, rows_)); + row_to_vertex_.insert(std::make_pair(rows_, vertex)); + rows_++; } } + // Insert an edge in the data structure void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. @@ -332,18 +314,20 @@ class Flag_complex_sparse_matrix { } public: - //! Main Constructor - /*! - Argument is an instance of Filtered_sorted_edge_list.
- This is THE function that initialises all data members to appropriate values.
- row_to_vertex_, vertex_to_row_, rows, cols, sparse_row_adjacency_matrix_ are initialised here. - domination_indicator_ are initialised by init() function which is - called at the begining of this.
- */ + /** \brief Flag_complex_sparse_matrix constructor from a range of filtered edges. + * + * @param[in] filtered_edge_range Range of filtered edges. Filtered edges must be in + * `Flag_complex_sparse_matrix::Filtered_edge`. + * + * @pre Available if Alpha_complex_3d is not Periodic. + * + * There is no need the range to be sorted, as it will be performed in + * `Flag_complex_sparse_matrix::filtered_edge_collapse. + */ template Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()), - rows(0) { + rows_(0) { for (Filtered_edge filtered_edge : filtered_edge_range) { Vertex_handle u; Vertex_handle v; @@ -353,8 +337,13 @@ class Flag_complex_sparse_matrix { } } + /** \brief Flag_complex_sparse_matrix constructor from a proximity graph. + * + * @param[in] one_skeleton_graph The one skeleton graph. The graph must be in + * `Flag_complex_sparse_matrix::Proximity_graph`. + */ Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) - : rows(0) { + : rows_(0) { // Insert all vertices_ for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { vertices_.emplace(*(v_it.first)); @@ -374,8 +363,8 @@ class Flag_complex_sparse_matrix { void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { Row_index endIdx = 0; - u_set_removed_redges_.clear(); - u_set_dominated_redges_.clear(); + u_set_removed_edges_.clear(); + u_set_dominated_edges_.clear(); critical_edge_indicator_.clear(); // Sort edges @@ -405,20 +394,21 @@ class Flag_complex_sparse_matrix { edge_to_index_map_.emplace(std::minmax(u, v), endIdx); critical_edge_indicator_.push_back(false); - dominated_edge_indicator_.push_back(false); if (not check_edge_domination(edge)) { critical_edge_indicator_[endIdx] = true; - dominated_edge_indicator_[endIdx] = false; filtered_edge_insert({u, v}, filt); if (endIdx > 1) set_edge_critical(endIdx, filt, filtered_edge_insert); - } else - dominated_edge_indicator_[endIdx] = true; + } endIdx++; } } + /** \brief Returns the number of vertices in the data structure. + * + * @return the number of vertices (which is also the number of rows in the Matrix). + */ std::size_t num_vertices() const { return vertices_.size(); } }; -- cgit v1.2.3 From 0e756c2aa5793890500f4f849149c902e184ec1e Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 14 Apr 2020 08:02:01 +0200 Subject: Some documentation --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ee957294..c92dd60b 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -337,10 +337,12 @@ class Flag_complex_sparse_matrix { } } - /** \brief Flag_complex_sparse_matrix constructor from a proximity graph. + /** \brief Flag_complex_sparse_matrix constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. * * @param[in] one_skeleton_graph The one skeleton graph. The graph must be in * `Flag_complex_sparse_matrix::Proximity_graph`. + * + * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` */ Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) : rows_(0) { @@ -358,7 +360,11 @@ class Flag_complex_sparse_matrix { } } - // Performs edge collapse in a decreasing sequence of the filtration value. + /** \brief Performs edge collapse in a decreasing sequence of the filtration value. + * + * \tparam FilteredEdgeInsertion is an output iterator that furnishes + * `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` that will fill the user defined data structure. + */ template void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { Row_index endIdx = 0; -- cgit v1.2.3 From 8400ce874e0d17c6d6c80bbd4b34dff40a768fe0 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 14 Apr 2020 10:19:38 +0200 Subject: Some documentation and examples --- biblio/bibliography.bib | 13 ++++ biblio/how_to_cite_gudhi.bib.in | 10 +++ src/CMakeLists.txt | 1 + src/Collapse/doc/intro_edge_collapse.h | 77 +++++++++++----------- src/Collapse/example/CMakeLists.txt | 10 +++ .../example/edge_collapse_basic_example.cpp | 45 +++++++++++++ .../example/edge_collapse_example_basic.txt | 5 ++ .../include/gudhi/Flag_complex_sparse_matrix.h | 20 +++--- src/common/doc/main_page.md | 30 +++++++++ 9 files changed, 163 insertions(+), 48 deletions(-) create mode 100644 src/Collapse/example/CMakeLists.txt create mode 100644 src/Collapse/example/edge_collapse_basic_example.cpp create mode 100644 src/Collapse/example/edge_collapse_example_basic.txt (limited to 'src/Collapse/include') diff --git a/biblio/bibliography.bib b/biblio/bibliography.bib index b017a07e..24f85b48 100644 --- a/biblio/bibliography.bib +++ b/biblio/bibliography.bib @@ -1208,3 +1208,16 @@ numpages = {11}, location = {Montr\'{e}al, Canada}, series = {NIPS’18} } + +@unpublished{edgecollapsesocg2020, + title = {{Edge Collapse and Persistence of Flag Complexes}}, + author = {Boissonnat, Jean-Daniel and Pritam, Siddharth}, + url = {https://hal.inria.fr/hal-02395227}, + note = {working paper or preprint}, + year = {2019}, + month = Dec, + keywords = {Persistent homology ; Strong Collapse ; Computational geometry ; Topological Data Analysis ; 2012 ACM Subject Classification Mathematics of computing ; Computational Topology}, + pdf = {https://hal.inria.fr/hal-02395227/file/socg2020_paper_152.pdf}, + hal_id = {hal-02395227}, + hal_version = {v1}, +} \ No newline at end of file diff --git a/biblio/how_to_cite_gudhi.bib.in b/biblio/how_to_cite_gudhi.bib.in index 05d3cc98..54d10857 100644 --- a/biblio/how_to_cite_gudhi.bib.in +++ b/biblio/how_to_cite_gudhi.bib.in @@ -156,3 +156,13 @@ , url = "https://gudhi.inria.fr/doc/@GUDHI_VERSION@/group___persistence__representations.html" , year = @GUDHI_VERSION_YEAR@ } + +@incollection{gudhi:Collapse +, author = "Siddharth Pritam" +, title = "Edge collapse" +, publisher = "{GUDHI Editorial Board}" +, edition = "{@GUDHI_VERSION@}" +, booktitle = "{GUDHI} User and Reference Manual" +, url = "https://gudhi.inria.fr/doc/@GUDHI_VERSION@/group__edge__collapse.html" +, year = @GUDHI_VERSION_YEAR@ +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 561aa049..9e4d78ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ add_gudhi_module(Bitmap_cubical_complex) add_gudhi_module(Bottleneck_distance) add_gudhi_module(Cech_complex) add_gudhi_module(Contraction) +add_gudhi_module(Collapse) add_gudhi_module(Hasse_complex) add_gudhi_module(Persistence_representations) add_gudhi_module(Persistent_cohomology) diff --git a/src/Collapse/doc/intro_edge_collapse.h b/src/Collapse/doc/intro_edge_collapse.h index 70c816f4..0691ccf6 100644 --- a/src/Collapse/doc/intro_edge_collapse.h +++ b/src/Collapse/doc/intro_edge_collapse.h @@ -24,9 +24,9 @@ namespace collapse { * \section edge_collapse_definition Edge collapse definition * * An edge \f$e\f$ in a simplicial complex \f$K\f$ is called a dominated edge if the link of \f$e\f$ in - * \f$K\f$, \f$lk_K(e)\f$ is a simplicial cone, that is, there exists a vertex \f$v^{\prime} \notin e\f$ and a subcomplex - * \f$L\f$ in \f$K\f$, such that \f$lk_K(e) = v^{\prime}L\f$. We say that the vertex \f$v^{\prime}\f$ is {dominating} - * \f$e\f$ and \f$e\f$ is {dominated} by \f$v^{\prime}\f$. + * \f$K\f$, \f$lk_K(e)\f$ is a simplicial cone, that is, there exists a vertex \f$v^{\prime} \notin e\f$ and a + * subcomplex \f$L\f$ in \f$K\f$, such that \f$lk_K(e) = v^{\prime}L\f$. We say that the vertex \f$v^{\prime}\f$ is + * {dominating} \f$e\f$ and \f$e\f$ is {dominated} by \f$v^{\prime}\f$. * An elementary egde collapse is the removal of a dominated edge \f$e\f$ from \f$K\f$, * which we denote with \f$K\f$ \f${\searrow\searrow}^1 \f$ \f$K\setminus e\f$. * The symbol \f$\mathbf{K\setminus e}\f$ (deletion of \f$e\f$ from \f$K\f$) refers to the subcomplex of \f$K\f$ which @@ -35,59 +35,62 @@ namespace collapse { * if there exists a series of elementary edge collapses from \f$K\f$ to \f$L\f$, denoted as \f$K\f$ * \f${\searrow\searrow}\f$ \f$L\f$. * - * An edge collapse is a homotopy preserving operation, and it can be further expressed as sequence of the classical elementary simple collapse. - * A complex without any dominated edge is called a $1$- minimal complex and the core \f$K^1\f$ of simplicial comlex is a - * minimal complex such that \f$K\f$ \f${\searrow\searrow}\f$ \f$K^1\f$. + * An edge collapse is a homotopy preserving operation, and it can be further expressed as sequence of the classical + * elementary simple collapse. + * A complex without any dominated edge is called a \f$1\f$- minimal complex and the core \f$K^1\f$ of simplicial + * complex is a minimal complex such that \f$K\f$ \f${\searrow\searrow}\f$ \f$K^1\f$. * Computation of a core (not unique) involves computation of dominated edges and the dominated edges can be easily * characterized as follows: * * -- For general simplicial complex: An edge \f$e \in K\f$ is dominated by another vertex \f$v^{\prime} \in K\f$, - * if and only if all the maximal simplices of \f$K\f$ that contain $e$ also contain \f$v^{\prime}\f$ + * if and only if all the maximal simplices of \f$K\f$ that contain \f$e\f$ also contain \f$v^{\prime}\f$ * * -- For a flag complex: An edge \f$e \in K\f$ is dominated by another vertex \f$v^{\prime} \in K\f$, if and only - * if all the vertices in \f$K\f$ that has an edge with both vertices of \f$e\f$ also has an edge with \f$v^{\prime}\f$. + * if
all the vertices in \f$K\f$ that has an edge with both vertices of \f$e\f$ also has an edge with + * \f$v^{\prime}\f$. - * This module implements edge collapse of a filtered flag complex, in particular it reduces a filtration of Vietoris-Rips (VR) complex from its graph - * to another smaller flag filtration with same persistence. Where a filtration is a sequence of simplicial - * (here Rips) complexes connected with inclusions. The algorithm to compute the smaller induced filtration is described in Section 5 \cite edgecollapsesocg2020. - * Edge collapse can be successfully employed to reduce any given filtration of flag complexes to a smaller induced - * filtration which preserves the persistent homology of the original filtration and is a flag complex as well. + * This module implements edge collapse of a filtered flag complex, in particular it reduces a filtration of + * Vietoris-Rips complex from its graph + * to another smaller flag filtration with same persistence. Where a filtration is a sequence of simplicial + * (here Rips) complexes connected with inclusions. The algorithm to compute the smaller induced filtration is + * described in Section 5 \cite edgecollapsesocg2020. + * Edge collapse can be successfully employed to reduce any given filtration of flag complexes to a smaller induced + * filtration which preserves the persistent homology of the original filtration and is a flag complex as well. - * The general idea is that we consider edges in the filtered graph and sort them according to their filtration value giving them a total order. - * Each edge gets a unique index denoted as \f$i\f$ in this order. To reduce the filtration, we move forward with increasing filtration value - * in the graph and check if the current edge \f$e_i\f$ is dominated in the current graph \f$G_i := \{e_1, .. e_i\} \f$ or not. - * If the edge \f$e_i\f$ is dominated we remove it from the filtration and move forward to the next edge \f$e_{i+1}\f$. - * If f$e_i\f$ is non-dominated then we keep it in the reduced filtration and then go backward in the current graph \f$G_i\f$ to look for new non-dominated edges - * that was dominated before but might become non-dominated at this point. - * If an edge \f$e_j, j < i \f$ during the backward search is found to be non-dominated, we include \f$\e_j\f$ in to the reduced filtration and we set its new filtration value to be $i$ that is the index of \f$e_i\f$. + * The general idea is that we consider edges in the filtered graph and sort them according to their filtration value + * giving them a total order. + * Each edge gets a unique index denoted as \f$i\f$ in this order. To reduce the filtration, we move forward with + * increasing filtration value + * in the graph and check if the current edge \f$e_i\f$ is dominated in the current graph \f$G_i := \{e_1, .. e_i\} \f$ + * or not. + * If the edge \f$e_i\f$ is dominated we remove it from the filtration and move forward to the next edge \f$e_{i+1}\f$. + * If \f$e_i\f$ is non-dominated then we keep it in the reduced filtration and then go backward in the current graph + * \f$G_i\f$ to look for new non-dominated edges that was dominated before but might become non-dominated at this + * point. + * If an edge \f$e_j, j < i \f$ during the backward search is found to be non-dominated, we include \f$e_j\f$ in to the + * reduced filtration and we set its new filtration value to be \f$i\f$ that is the index of \f$e_i\f$. * The precise mechanism for this reduction has been described in Section 5 \cite edgecollapsesocg2020. * Here we implement this mechanism for a filtration of Rips complex, - * After perfoming the reduction the filtration reduces to a flag-filtration with the same persistence as the original filtration. + * After perfoming the reduction the filtration reduces to a flag-filtration with the same persistence as the original + * filtration. * - - * Comment: I think it would be good if you (Vincent) check the later part according to the examples you build. - * \subsection edge_collapse_from_points_example Example from a point cloud and a distance function + * \subsection edgecollapseexample Basic edge collapse * - * This example builds the edge graph from the given points, threshold value, and distance function. - * Then it creates a `Flag_complex_edge_collapse` (exact version) with it. + * This example builds the `Flag_complex_sparse_matrix` from a proximity graph represented as a list of + * `Flag_complex_sparse_matrix::Filtered_edge`. + * Then it collapses edges and displays a new list of `Flag_complex_sparse_matrix::Filtered_edge` (with less edges) + * that will preserve the persistence homology computation. * - * Then, it is asked to display the distance matrix after the collapse operation. + * \include Collapse/edge_collapse_basic_example.cpp * - * \include Strong_collapse/strong_collapse_from_points.cpp + * When launching the example: * - * \code $> ./strong_collapse_from_points + * \code $> ./Edge_collapse_example_basic * \endcode * * the program output is: * - * \include Strong_collapse/strong_collapse_from_points_for_doc.txt - * - * A `Gudhi::rips_complex::Rips_complex` can be built from the distance matrix if you want to compute persistence on - * top of it. - - * For more information about our approach of computing edge collapses and persitent homology via edge collapses, - * we refer the users to \cite edgecollapsesocg2020 . - * + * \include Collapse/edge_collapse_example_basic.txt */ /** @} */ // end defgroup strong_collapse diff --git a/src/Collapse/example/CMakeLists.txt b/src/Collapse/example/CMakeLists.txt new file mode 100644 index 00000000..6cf3bf07 --- /dev/null +++ b/src/Collapse/example/CMakeLists.txt @@ -0,0 +1,10 @@ +project(Edge_collapse_examples) + +# Point cloud +add_executable ( Edge_collapse_example_basic edge_collapse_basic_example.cpp ) + +if (TBB_FOUND) + target_link_libraries(Edge_collapse_example_basic ${TBB_LIBRARIES}) +endif() + +add_test(NAME Edge_collapse_example_basic COMMAND $) diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp new file mode 100644 index 00000000..a154c6bb --- /dev/null +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include + +int main() { + // Type definitions + using Filtration_value = float; + using Vertex_handle = short; + using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; + using Filtered_edge = Flag_complex_sparse_matrix::Filtered_edge; + using Filtered_edge_list = std::vector; + using Edge = Flag_complex_sparse_matrix::Edge; + + // 1 2 + // o---o + // |\ /| + // | x | + // |/ \| + // o---o + // 0 3 + Filtered_edge_list graph = {{{0, 1}, 1.}, + {{1, 2}, 1.}, + {{2, 3}, 1.}, + {{3, 0}, 1.}, + {{0, 2}, 2.}, + {{1, 3}, 2.}}; + + Flag_complex_sparse_matrix flag_complex_sparse_matrix(graph); + + Filtered_edge_list collapse_edges; + // Retrieve collapse edges from the output iterator + flag_complex_sparse_matrix.filtered_edge_collapse( + [&collapse_edges](std::pair edge, Filtration_value filtration) { + collapse_edges.push_back({edge, filtration}); + }); + + for (Filtered_edge filtered_edge_from_collapse : collapse_edges) { + Edge edge_from_collapse = std::get<0>(filtered_edge_from_collapse); + std::cout << "fn[" << std::get<0>(edge_from_collapse) << ", " << std::get<1>(edge_from_collapse) << "] = " + << std::get<1>(filtered_edge_from_collapse) << std::endl; + } + + return 0; +} diff --git a/src/Collapse/example/edge_collapse_example_basic.txt b/src/Collapse/example/edge_collapse_example_basic.txt new file mode 100644 index 00000000..acecacaf --- /dev/null +++ b/src/Collapse/example/edge_collapse_example_basic.txt @@ -0,0 +1,5 @@ +fn[0, 1] = 1 +fn[1, 2] = 1 +fn[2, 3] = 1 +fn[3, 0] = 1 +fn[0, 2] = 2 diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index c92dd60b..a2f3a2a9 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -53,16 +53,16 @@ namespace collapse { template class Flag_complex_sparse_matrix { public: - // Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph + /** \brief Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph. */ using Vertex_handle = Vertex; - // Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph + /** \brief Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph. */ using Filtration_value = Filtration; - private: - // This is an ordered pair, An edge is stored with convention of the first - // element being the smaller i.e {2,3} not {3,2}. However this is at the level - // of row indices on actual vertex lables + /** \brief This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e + * {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables. + */ using Edge = std::pair; + private: // Row_index type in the sparse matrix using Row_index = std::size_t; @@ -73,9 +73,9 @@ class Flag_complex_sparse_matrix { using Row_indices_vector = std::vector; public: - // A Filtered_edge is a std::pair, Filtration_value> + /** \brief A Filtered_edge is a std::pair, `Filtration_value`>. */ using Filtered_edge = std::pair; - // Proximity_graph is a type that can be used to construct easily a Flag_complex_sparse_matrix + /** \brief Proximity_graph is a type that can be used to construct easily a Flag_complex_sparse_matrix. */ using Proximity_graph = Gudhi::Proximity_graph; private: @@ -319,10 +319,8 @@ class Flag_complex_sparse_matrix { * @param[in] filtered_edge_range Range of filtered edges. Filtered edges must be in * `Flag_complex_sparse_matrix::Filtered_edge`. * - * @pre Available if Alpha_complex_3d is not Periodic. - * * There is no need the range to be sorted, as it will be performed in - * `Flag_complex_sparse_matrix::filtered_edge_collapse. + * `Flag_complex_sparse_matrix::filtered_edge_collapse`. */ template Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) diff --git a/src/common/doc/main_page.md b/src/common/doc/main_page.md index 6ea10b88..cdea3d94 100644 --- a/src/common/doc/main_page.md +++ b/src/common/doc/main_page.md @@ -242,6 +242,36 @@ +#### Strong collapse + + + + + + + + + + +
+ \image html "edge_collapse_representation.png" + + Edge collapse is able to reduce any flag filtration to a smaller flag filtration with the same persistence, using + only the 1-skeletons of a simplicial complex. + The reduction is exact and the persistence homology of the reduced sequence is identical to the persistence + homology of the input sequence. The resulting method is simple and extremely efficient. + + Computation of edge collapse and persistent homology of a filtered flag complex via edge collapse as described in + \cite edgecollapsesocg2020. + + Author: Siddharth Pritam
+ Introduced in: GUDHI 2.4.0
+ Copyright: MIT
+ Requires: \ref eigen +
+ User manual: \ref edge_collapse +
+ ### Cover Complexes -- cgit v1.2.3 From 1508cef62980fb59ac7e1b0b30f560083ec3988a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 14 Apr 2020 11:32:25 +0200 Subject: Windows appveyor do not like not operator --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index a2f3a2a9..49c28f63 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -199,10 +199,10 @@ class Flag_complex_sparse_matrix { Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); // If idx is not critical so it should be processed, otherwise it stays in the graph - if (not critical_edge_indicator_[idx]) { + if (!critical_edge_indicator_[idx]) { // If idx is affected if (effected_indices.find(idx) != effected_indices.end()) { - if (not check_edge_domination(edge)) { + if (!check_edge_domination(edge)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES @@ -236,12 +236,12 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES - if (not domination_indicator_[rw_u]) { + if (!domination_indicator_[rw_u]) { // Iterate over the non-zero columns for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (not domination_indicator_[rw_v] and u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() and + if (!domination_indicator_[rw_v] and u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() and u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); @@ -399,7 +399,7 @@ class Flag_complex_sparse_matrix { edge_to_index_map_.emplace(std::minmax(u, v), endIdx); critical_edge_indicator_.push_back(false); - if (not check_edge_domination(edge)) { + if (!check_edge_domination(edge)) { critical_edge_indicator_[endIdx] = true; filtered_edge_insert({u, v}, filt); if (endIdx > 1) -- cgit v1.2.3 From 4fdc721bbd19bc6389d611d252ff08f8fbbeee23 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 28 Apr 2020 08:33:51 +0200 Subject: Code and doc review fix --- src/Collapse/doc/intro_edge_collapse.h | 2 +- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 10 +++++----- .../distance_matrix_edge_collapse_rips_persistence.cpp | 4 +--- src/common/doc/main_page.md | 2 +- src/common/include/gudhi/graph_simplicial_complex.h | 8 ++++++++ 5 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/doc/intro_edge_collapse.h b/src/Collapse/doc/intro_edge_collapse.h index 0691ccf6..5c126d29 100644 --- a/src/Collapse/doc/intro_edge_collapse.h +++ b/src/Collapse/doc/intro_edge_collapse.h @@ -2,7 +2,7 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Siddharth Pritam * - * Copyright (C) 2019 Inria + * Copyright (C) 2020 Inria * * Modification(s): * - YYYY/MM Author: Description of the modification diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 49c28f63..6fa4438c 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -2,7 +2,7 @@ * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. * Author(s): Siddharth Pritam * - * Copyright (C) 2018 Inria + * Copyright (C) 2020 Inria * * Modification(s): * - 2020/03 Vincent Rouvreau: integration to the gudhi library @@ -44,8 +44,8 @@ namespace collapse { * \ingroup collapse * * \details - * A class to store the vertices v/s MaxSimplices Sparse Matrix and to perform collapse operations using the N^2() - * Algorithm. + * This class stores a Flag complex + * in an Eigen sparse matrix. * * \tparam Vertex type must be a signed integer type. It admits a total order <. * \tparam Filtration type for the value of the filtration function. Must be comparable with <. @@ -73,7 +73,7 @@ class Flag_complex_sparse_matrix { using Row_indices_vector = std::vector; public: - /** \brief A Filtered_edge is a std::pair, `Filtration_value`>. */ + /** \brief Filtered_edge is a type to store an edge with its filtration value. */ using Filtered_edge = std::pair; /** \brief Proximity_graph is a type that can be used to construct easily a Flag_complex_sparse_matrix. */ using Proximity_graph = Gudhi::Proximity_graph; @@ -358,7 +358,7 @@ class Flag_complex_sparse_matrix { } } - /** \brief Performs edge collapse in a decreasing sequence of the filtration value. + /** \brief Performs edge collapse in a increasing sequence of the filtration value. * * \tparam FilteredEdgeInsertion is an output iterator that furnishes * `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` that will fill the user defined data structure. diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index f4a460ab..f39e9764 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -79,9 +79,7 @@ int main(int argc, char* argv[]) { program_options(argc, argv, csv_matrix_file, filediag, threshold, dim_max, p, min_persistence); - Distance_matrix distances; - - distances = Gudhi::read_lower_triangular_matrix_from_csv_file(csv_matrix_file); + Distance_matrix distances = Gudhi::read_lower_triangular_matrix_from_csv_file(csv_matrix_file); std::cout << "Read the distance matrix succesfully, of size: " << distances.size() << std::endl; Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(boost::irange((size_t)0, diff --git a/src/common/doc/main_page.md b/src/common/doc/main_page.md index cdea3d94..85b39be9 100644 --- a/src/common/doc/main_page.md +++ b/src/common/doc/main_page.md @@ -242,7 +242,7 @@
-#### Strong collapse +#### Edge collapse diff --git a/src/common/include/gudhi/graph_simplicial_complex.h b/src/common/include/gudhi/graph_simplicial_complex.h index b8508697..3e7720d7 100644 --- a/src/common/include/gudhi/graph_simplicial_complex.h +++ b/src/common/include/gudhi/graph_simplicial_complex.h @@ -19,6 +19,9 @@ #include // for std::tie namespace Gudhi { +/** @file + * @brief Graph simplicial complex methods + */ /* Edge tag for Boost PropertyGraph. */ struct edge_filtration_t { @@ -42,10 +45,15 @@ using Proximity_graph = typename boost::adjacency_list < boost::vecS, boost::vec , boost::property < edge_filtration_t, typename SimplicialComplexForProximityGraph::Filtration_value >>; /** \brief Computes the proximity graph of the points. + * + * \fn Gudhi::Proximity_graph compute_proximity_graph(const ForwardPointRange& + * points, typename SimplicialComplexForProximityGraph::Filtration_value threshold, Distance distance) * * If points contains n elements, the proximity graph is the graph with n vertices, and an edge [u,v] iff the * distance function between points u and v is smaller than threshold. * + * \tparam SimplicialComplexForProximityGraph furnishes `Filtration_value` and `Vertex_handle` type definitions. + * * \tparam ForwardPointRange furnishes `.begin()` and `.end()` methods. * * \tparam Distance furnishes `operator()(const Point& p1, const Point& p2)`, where -- cgit v1.2.3 From 8917c9bb7336b68744dd01f09b00b9c905a42bba Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 09:26:01 +0200 Subject: Code review: row_to_vertex_ can be a vector --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 6fa4438c..b1881a66 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -80,7 +80,7 @@ class Flag_complex_sparse_matrix { private: // Map from row index to its vertex handle - std::unordered_map row_to_vertex_; + std::vector row_to_vertex_; // Vertices stored as an unordered_set std::unordered_set vertices_; @@ -282,7 +282,7 @@ class Flag_complex_sparse_matrix { sparse_row_adjacency_matrix_.insert(rows_, rows_) = filt_val; domination_indicator_.push_back(false); vertex_to_row_.insert(std::make_pair(vertex, rows_)); - row_to_vertex_.insert(std::make_pair(rows_, vertex)); + row_to_vertex_.push_back(vertex); rows_++; } } -- cgit v1.2.3 From 2de21960a64225c7f595ce9e192bfeb84f0be220 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 09:34:41 +0200 Subject: Code review: use std::sort instead of std::stable_sort --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index b1881a66..293b22e6 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -380,7 +380,7 @@ class Flag_complex_sparse_matrix { #ifdef GUDHI_USE_TBB tbb::parallel_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #else - std::stable_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); + std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. -- cgit v1.2.3 From 9273dd8dda57ea4615f2acfa5fc255d151d584e8 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 11:01:05 +0200 Subject: Code review: Remove num_vertices and initialize sparse matrix in the constructor --- .../include/gudhi/Flag_complex_sparse_matrix.h | 28 +++++++--------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 293b22e6..4922a1a7 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -82,9 +82,6 @@ class Flag_complex_sparse_matrix { // Map from row index to its vertex handle std::vector row_to_vertex_; - // Vertices stored as an unordered_set - std::unordered_set vertices_; - // Unordered set of removed edges. (to enforce removal from the matrix) std::unordered_set> u_set_removed_edges_; @@ -326,13 +323,17 @@ class Flag_complex_sparse_matrix { Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()), rows_(0) { + // To get the number of vertices + std::unordered_set vertices; for (Filtered_edge filtered_edge : filtered_edge_range) { Vertex_handle u; Vertex_handle v; std::tie(u,v) = std::get<0>(filtered_edge); - vertices_.emplace(u); - vertices_.emplace(v); + vertices.emplace(u); + vertices.emplace(v); } + // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. + sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices.size(), vertices.size()); } /** \brief Flag_complex_sparse_matrix constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. @@ -343,11 +344,9 @@ class Flag_complex_sparse_matrix { * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` */ Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) - : rows_(0) { - // Insert all vertices_ - for (auto v_it = boost::vertices(one_skeleton_graph); v_it.first != v_it.second; ++v_it.first) { - vertices_.emplace(*(v_it.first)); - } + : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), boost::num_vertices(one_skeleton_graph)), + rows_(0) + { // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { @@ -383,9 +382,6 @@ class Flag_complex_sparse_matrix { std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif - // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. - sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices_.size(), vertices_.size()); - while (endIdx < f_edge_vector_.size()) { Filtered_edge fec = f_edge_vector_[endIdx]; Edge edge = std::get<0>(fec); @@ -409,12 +405,6 @@ class Flag_complex_sparse_matrix { } } - /** \brief Returns the number of vertices in the data structure. - * - * @return the number of vertices (which is also the number of rows in the Matrix). - */ - std::size_t num_vertices() const { return vertices_.size(); } - }; } // namespace collapse -- cgit v1.2.3 From 1fc68dcf4479cccccdac1bd66e24adae3e974386 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 11:15:49 +0200 Subject: Use C++ boolean logical operator --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 4922a1a7..8c76de96 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -140,7 +140,7 @@ class Flag_complex_sparse_matrix { return true; else for (auto rw_c : common_neighbours) { - if (rw_c != rw_u and rw_c != rw_v) { + if (rw_c != rw_u && rw_c != rw_v) { auto neighbours_c = closed_neighbours_row_index(rw_c); // If neighbours_c contains the common neighbours. if (std::includes(neighbours_c.begin(), neighbours_c.end(), common_neighbours.begin(), @@ -171,7 +171,7 @@ class Flag_complex_sparse_matrix { if (common_neighbours.size() > 2) { for (auto rw_c : common_neighbours) { - if (rw_c != rw_u and rw_c != rw_v) { + if (rw_c != rw_u && rw_c != rw_v) { auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex_[rw_c]); edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_v]); @@ -238,7 +238,7 @@ class Flag_complex_sparse_matrix { for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (!domination_indicator_[rw_v] and u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() and + if (!domination_indicator_[rw_v] && u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); -- cgit v1.2.3 From 71af68554711e82e5e8e1f495bdc25deaeb5b401 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 11:28:15 +0200 Subject: Code review: Rename insert_new_edge method --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 8c76de96..bbfd9aeb 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -285,7 +285,7 @@ class Flag_complex_sparse_matrix { } // Insert an edge in the data structure - void insert_new_edges(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) + void insert_new_edge(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); @@ -390,7 +390,7 @@ class Flag_complex_sparse_matrix { Filtration_value filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) - insert_new_edges(u, v, filt); + insert_new_edge(u, v, filt); edge_to_index_map_.emplace(std::minmax(u, v), endIdx); critical_edge_indicator_.push_back(false); -- cgit v1.2.3 From 1269de8a29bc2449f6a6454f6d336204ca5c5b9a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 14:27:33 +0200 Subject: Code review: use emplace on unordered_map in insert_vertex --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index bbfd9aeb..161069c0 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -273,12 +273,12 @@ class Flag_complex_sparse_matrix { // Insert a vertex in the data structure void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { - auto rw = vertex_to_row_.find(vertex); - if (rw == vertex_to_row_.end()) { + auto result = vertex_to_row_.emplace(std::make_pair(vertex, rows_)); + // If it was not already inserted - Value won't be updated by emplace if it is already present + if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. sparse_row_adjacency_matrix_.insert(rows_, rows_) = filt_val; domination_indicator_.push_back(false); - vertex_to_row_.insert(std::make_pair(vertex, rows_)); row_to_vertex_.push_back(vertex); rows_++; } -- cgit v1.2.3 From 55aba07cf1de81f29ebded896ac80c1da8b64f55 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 15:14:30 +0200 Subject: Code review: emplace wo std::make_pair --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 161069c0..ceb56bf1 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -273,7 +273,7 @@ class Flag_complex_sparse_matrix { // Insert a vertex in the data structure void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { - auto result = vertex_to_row_.emplace(std::make_pair(vertex, rows_)); + auto result = vertex_to_row_.emplace(vertex, rows_); // If it was not already inserted - Value won't be updated by emplace if it is already present if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. -- cgit v1.2.3 From b9e6a2d6314852797dca4c156963dbb446824d8a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 15:23:56 +0200 Subject: Code review: rows_ is not mandatory --- .../include/gudhi/Flag_complex_sparse_matrix.h | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ceb56bf1..35906216 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -103,18 +103,13 @@ class Flag_complex_sparse_matrix { Sparse_row_matrix sparse_row_adjacency_matrix_; // Stores true for dominated rows and false otherwise. - // Initialised to a vector of length equal to the value of the variable rows_ with all false values. - // Subsequent removal of dominated vertices is reflected by concerned entries changing to true - // in this vector. + // Initialised to a vector of length equal to the length of row_to_vertex_ with all values set to false. + // Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. std::vector domination_indicator_; // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. std::vector f_edge_vector_; - - //! Stores the number of vertices in the original graph (which is also the number of rows in the Matrix). - Row_index rows_; - // Edge e is the actual edge (u,v). Not the row ids in the matrixs bool check_edge_domination(const Edge& edge) const { @@ -273,14 +268,14 @@ class Flag_complex_sparse_matrix { // Insert a vertex in the data structure void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { - auto result = vertex_to_row_.emplace(vertex, rows_); + auto result = vertex_to_row_.emplace(vertex, row_to_vertex_.size()); // If it was not already inserted - Value won't be updated by emplace if it is already present if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix_.insert(rows_, rows_) = filt_val; + sparse_row_adjacency_matrix_.insert(row_to_vertex_.size(), row_to_vertex_.size()) = filt_val; domination_indicator_.push_back(false); + // Must be done after sparse_row_adjacency_matrix_ insertion row_to_vertex_.push_back(vertex); - rows_++; } } @@ -321,8 +316,7 @@ class Flag_complex_sparse_matrix { */ template Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) - : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()), - rows_(0) { + : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { // To get the number of vertices std::unordered_set vertices; for (Filtered_edge filtered_edge : filtered_edge_range) { @@ -344,9 +338,7 @@ class Flag_complex_sparse_matrix { * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` */ Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) - : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), boost::num_vertices(one_skeleton_graph)), - rows_(0) - { + : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), boost::num_vertices(one_skeleton_graph)) { // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { -- cgit v1.2.3 From 6eb48ea4e36e588c5af75040d5640e92bf02172c Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 15:33:59 +0200 Subject: Code review: rename check_edge_domination as edge_is_dominated --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 35906216..ea2c6dcc 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -111,7 +111,7 @@ class Flag_complex_sparse_matrix { std::vector f_edge_vector_; // Edge e is the actual edge (u,v). Not the row ids in the matrixs - bool check_edge_domination(const Edge& edge) const + bool edge_is_dominated(const Edge& edge) const { Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); @@ -194,7 +194,7 @@ class Flag_complex_sparse_matrix { if (!critical_edge_indicator_[idx]) { // If idx is affected if (effected_indices.find(idx) != effected_indices.end()) { - if (!check_edge_domination(edge)) { + if (!edge_is_dominated(edge)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES @@ -387,7 +387,7 @@ class Flag_complex_sparse_matrix { edge_to_index_map_.emplace(std::minmax(u, v), endIdx); critical_edge_indicator_.push_back(false); - if (!check_edge_domination(edge)) { + if (!edge_is_dominated(edge)) { critical_edge_indicator_[endIdx] = true; filtered_edge_insert({u, v}, filt); if (endIdx > 1) -- cgit v1.2.3 From 2795e009aa773f6a1ba8723abeaa98acce992a75 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 18:14:44 +0200 Subject: Code review: No need to pass an edge to closed_common_neighbours_row_index, can be 2 vertices as it simplifies the code --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ea2c6dcc..07c5b24e 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -118,11 +118,10 @@ class Flag_complex_sparse_matrix { const Row_index rw_u = vertex_to_row_.at(u); const Row_index rw_v = vertex_to_row_.at(v); - auto rw_e = std::make_pair(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; #endif // DEBUG_TRACES - auto common_neighbours = closed_common_neighbours_row_index(rw_e); + auto common_neighbours = closed_common_neighbours_row_index(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "And its common neighbours are." << std::endl; for (auto neighbour : common_neighbours) { @@ -160,9 +159,8 @@ class Flag_complex_sparse_matrix { #endif // DEBUG_TRACES auto rw_u = vertex_to_row_[u]; auto rw_v = vertex_to_row_[v]; - auto rw_critical_edge = std::make_pair(rw_u, rw_v); - Row_indices_vector common_neighbours = closed_common_neighbours_row_index(rw_critical_edge); + Row_indices_vector common_neighbours = closed_common_neighbours_row_index(rw_u, rw_v); if (common_neighbours.size() > 2) { for (auto rw_c : common_neighbours) { @@ -250,16 +248,11 @@ class Flag_complex_sparse_matrix { } // Returns the list of closed neighbours of the edge :{u,v}. - Row_indices_vector closed_common_neighbours_row_index(const std::pair& rw_edge) const + Row_indices_vector closed_common_neighbours_row_index(Row_index rw_u, Row_index rw_v) const { + Row_indices_vector non_zero_indices_u = closed_neighbours_row_index(rw_u); + Row_indices_vector non_zero_indices_v = closed_neighbours_row_index(rw_v); Row_indices_vector common; - Row_indices_vector non_zero_indices_u; - Row_indices_vector non_zero_indices_v; - Row_index rw_u = std::get<0>(rw_edge); - Row_index rw_v = std::get<1>(rw_edge); - - non_zero_indices_u = closed_neighbours_row_index(rw_u); - non_zero_indices_v = closed_neighbours_row_index(rw_v); std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), non_zero_indices_v.end(), std::inserter(common, common.begin())); -- cgit v1.2.3 From 26f396ce9dca274b66f7c518bc6f02bba918d134 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 18:20:56 +0200 Subject: Code review: Remove domination_indicator_ as it is a left over from strong collapse --- .../include/gudhi/Flag_complex_sparse_matrix.h | 30 ++++++++-------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 07c5b24e..540a47fe 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -102,11 +102,6 @@ class Flag_complex_sparse_matrix { // to elements when traversing the matrix row-wise. Sparse_row_matrix sparse_row_adjacency_matrix_; - // Stores true for dominated rows and false otherwise. - // Initialised to a vector of length equal to the length of row_to_vertex_ with all values set to false. - // Subsequent removal of dominated vertices is reflected by concerned entries changing to true in this vector. - std::vector domination_indicator_; - // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. std::vector f_edge_vector_; @@ -226,24 +221,22 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES - if (!domination_indicator_[rw_u]) { - // Iterate over the non-zero columns - for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { - Row_index rw_v = it.index(); - // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (!domination_indicator_[rw_v] && u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && - u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { - // inner index, here it is equal to it.columns() - non_zero_indices.push_back(rw_v); + // Iterate over the non-zero columns + for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { + Row_index rw_v = it.index(); + // If the vertex v is not dominated and the edge {u,v} is still in the matrix + if (u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && + u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { + // inner index, here it is equal to it.columns() + non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES - std::cout << row_to_vertex_[rw_v] << ", " ; + std::cout << row_to_vertex_[rw_v] << ", " ; #endif // DEBUG_TRACES - } } + } #ifdef DEBUG_TRACES - std::cout << std::endl; + std::cout << std::endl; #endif // DEBUG_TRACES - } return non_zero_indices; } @@ -266,7 +259,6 @@ class Flag_complex_sparse_matrix { if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. sparse_row_adjacency_matrix_.insert(row_to_vertex_.size(), row_to_vertex_.size()) = filt_val; - domination_indicator_.push_back(false); // Must be done after sparse_row_adjacency_matrix_ insertion row_to_vertex_.push_back(vertex); } -- cgit v1.2.3 From d10b2511dd0e3a6a847f6e47754703b7cab0b03f Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 18:27:29 +0200 Subject: Code review: remove effected_indices clear --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 540a47fe..bb703450 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -210,7 +210,6 @@ class Flag_complex_sparse_matrix { } } } - effected_indices.clear(); u_set_dominated_edges_.clear(); } -- cgit v1.2.3 From ac8f1911f157b801abe21aa9bf8f143a1fddcc65 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 18:53:11 +0200 Subject: Code review: add some comments on three_clique_indices --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index bb703450..e91bcc28 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -141,6 +141,7 @@ class Flag_complex_sparse_matrix { return false; } + // Returns the edges connecting u and v (extremities of crit) to their common neighbors (not themselves) std::set three_clique_indices(Row_index crit) { std::set edge_indices; -- cgit v1.2.3 From ed550043dcc5cdf4ddc08aa0fcc09e425b311922 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 19:10:03 +0200 Subject: Code review: filtered_edge_collapse is not requiring an output_iterator but a callback/functor --- .../include/gudhi/Flag_complex_sparse_matrix.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index e91bcc28..44db25b3 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -172,8 +172,8 @@ class Flag_complex_sparse_matrix { } // Detect and set all indices that are becoming critical - template - void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeInsertion filtered_edge_insert) { + template + void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeOutput filtered_edge_output) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; @@ -193,7 +193,7 @@ class Flag_complex_sparse_matrix { std::cout << "The curent index became critical " << idx << std::endl; #endif // DEBUG_TRACES critical_edge_indicator_[idx] = true; - filtered_edge_insert({u, v}, filt); + filtered_edge_output({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { if (*inr_idx < idx) effected_indices.emplace(*inr_idx); @@ -336,11 +336,11 @@ class Flag_complex_sparse_matrix { /** \brief Performs edge collapse in a increasing sequence of the filtration value. * - * \tparam FilteredEdgeInsertion is an output iterator that furnishes - * `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` that will fill the user defined data structure. + * \tparam FilteredEdgeOutput is a functor that furnishes `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` + * that will get called on the output edges, in non-decreasing order of filtration. */ - template - void filtered_edge_collapse(FilteredEdgeInsertion filtered_edge_insert) { + template + void filtered_edge_collapse(FilteredEdgeOutput filtered_edge_output) { Row_index endIdx = 0; u_set_removed_edges_.clear(); @@ -374,9 +374,9 @@ class Flag_complex_sparse_matrix { if (!edge_is_dominated(edge)) { critical_edge_indicator_[endIdx] = true; - filtered_edge_insert({u, v}, filt); + filtered_edge_output({u, v}, filt); if (endIdx > 1) - set_edge_critical(endIdx, filt, filtered_edge_insert); + set_edge_critical(endIdx, filt, filtered_edge_output); } endIdx++; } -- cgit v1.2.3 From 1ab1d498c2e44de12c2516c27b64cc9f1ba23885 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Mon, 25 May 2020 19:28:16 +0200 Subject: Code review: remove inner_effected_indcs clear as it will be done when closing the brackets --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 44db25b3..2f45ff54 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -198,7 +198,6 @@ class Flag_complex_sparse_matrix { for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { if (*inr_idx < idx) effected_indices.emplace(*inr_idx); } - inner_effected_indcs.clear(); #ifdef DEBUG_TRACES std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " << filt << std::endl; -- cgit v1.2.3 From d46d9ef653644fce78ee72f6e727f4cb4cc3e11a Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 2 Jun 2020 22:47:53 +0200 Subject: code review: Remove the clear as this function won't be called several times --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 2f45ff54..a675bd77 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -341,11 +341,6 @@ class Flag_complex_sparse_matrix { template void filtered_edge_collapse(FilteredEdgeOutput filtered_edge_output) { Row_index endIdx = 0; - - u_set_removed_edges_.clear(); - u_set_dominated_edges_.clear(); - critical_edge_indicator_.clear(); - // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { -- cgit v1.2.3 From 08ffcedc11119eba2f5a0a6f22329df197c86107 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Tue, 2 Jun 2020 22:59:11 +0200 Subject: code review: GUDHI_CHECK if u==v oninsert_edge method --- .../include/gudhi/Flag_complex_sparse_matrix.h | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index a675bd77..b53c8ab7 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -13,6 +13,7 @@ #define FLAG_COMPLEX_SPARSE_MATRIX_H_ #include +#include #include #include @@ -264,29 +265,26 @@ class Flag_complex_sparse_matrix { } // Insert an edge in the data structure + // @exception std::invalid_argument In debug mode, if u == v void insert_new_edge(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) { // The edge must not be added before, it should be a new edge. insert_vertex(u, filt_val); - if (u != v) { - insert_vertex(v, filt_val); -#ifdef DEBUG_TRACES - std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES + GUDHI_CHECK((u != v), + std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); - auto rw_u = vertex_to_row_.find(u); - auto rw_v = vertex_to_row_.find(v); + insert_vertex(v, filt_val); #ifdef DEBUG_TRACES - std::cout << "Inserting the edge " << u <<", " << v << std::endl; + std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = filt_val; - sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = filt_val; - } + + auto rw_u = vertex_to_row_.find(u); + auto rw_v = vertex_to_row_.find(v); #ifdef DEBUG_TRACES - else { - std::cout << "Already a member simplex, skipping..." << std::endl; - } + std::cout << "Inserting the edge " << u <<", " << v << std::endl; #endif // DEBUG_TRACES + sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = filt_val; + sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = filt_val; } public: -- cgit v1.2.3 From 9ae3c860517e5d8248e13df0d0e8a05fcf765262 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 4 Jun 2020 17:19:28 +0200 Subject: code review: no need to loop backward --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index b53c8ab7..3afacd0e 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -196,8 +196,8 @@ class Flag_complex_sparse_matrix { critical_edge_indicator_[idx] = true; filtered_edge_output({u, v}, filt); std::set inner_effected_indcs = three_clique_indices(idx); - for (auto inr_idx = inner_effected_indcs.rbegin(); inr_idx != inner_effected_indcs.rend(); inr_idx++) { - if (*inr_idx < idx) effected_indices.emplace(*inr_idx); + for (auto inr_idx : inner_effected_indcs) { + effected_indices.emplace(inr_idx); } #ifdef DEBUG_TRACES std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " -- cgit v1.2.3 From 85dc5c1e96c66e1505599eab2ee7e61174fd169d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 4 Jun 2020 22:06:50 +0200 Subject: code review: remove u_set_dominated_edges_ as it is redundant with critical_edge_indicator_ --- .../include/gudhi/Flag_complex_sparse_matrix.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 3afacd0e..75df52bf 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -86,9 +86,6 @@ class Flag_complex_sparse_matrix { // Unordered set of removed edges. (to enforce removal from the matrix) std::unordered_set> u_set_removed_edges_; - // Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_edges_; - // Map from edge to its index std::unordered_map> edge_to_index_map_; @@ -203,15 +200,11 @@ class Flag_complex_sparse_matrix { std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " << filt << std::endl; #endif // DEBUG_TRACES - } else - u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); - } else - // Idx is not affected hence dominated. - u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); + } + } } } } - u_set_dominated_edges_.clear(); } // Returns list of non-zero columns of a particular indx. @@ -224,9 +217,17 @@ class Flag_complex_sparse_matrix { // Iterate over the non-zero columns for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); + + bool dominated_edge_not_found = false; + try { + edge_to_index_map_.at(std::minmax(row_to_vertex_[rw_u], row_to_vertex_[rw_v])); + } catch (const std::out_of_range& oor) { + dominated_edge_not_found = true; + } + // If the vertex v is not dominated and the edge {u,v} is still in the matrix if (u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && - u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { + dominated_edge_not_found) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES -- cgit v1.2.3 From a81c5adcf4426338ff80cfb2f1973f113a17b16d Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 4 Jun 2020 22:13:46 +0200 Subject: code review: better use a for loop --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 75df52bf..67399044 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -339,7 +339,6 @@ class Flag_complex_sparse_matrix { */ template void filtered_edge_collapse(FilteredEdgeOutput filtered_edge_output) { - Row_index endIdx = 0; // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { @@ -352,7 +351,7 @@ class Flag_complex_sparse_matrix { std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif - while (endIdx < f_edge_vector_.size()) { + for (Row_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { Filtered_edge fec = f_edge_vector_[endIdx]; Edge edge = std::get<0>(fec); Vertex_handle u = std::get<0>(edge); @@ -371,7 +370,6 @@ class Flag_complex_sparse_matrix { if (endIdx > 1) set_edge_critical(endIdx, filt, filtered_edge_output); } - endIdx++; } } -- cgit v1.2.3 From df758d75a3dbb57abeb6a38a20200ee2251d8816 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 4 Jun 2020 22:36:58 +0200 Subject: rollback 85dc5c1 as the information is not quite the same in both structure --- .../include/gudhi/Flag_complex_sparse_matrix.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 67399044..ab72197d 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -86,6 +86,9 @@ class Flag_complex_sparse_matrix { // Unordered set of removed edges. (to enforce removal from the matrix) std::unordered_set> u_set_removed_edges_; + // Unordered set of dominated edges. (to inforce removal from the matrix) + std::unordered_set> u_set_dominated_edges_; + // Map from edge to its index std::unordered_map> edge_to_index_map_; @@ -200,11 +203,17 @@ class Flag_complex_sparse_matrix { std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " << filt << std::endl; #endif // DEBUG_TRACES + } else { + u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } + } else { + // Idx is not affected hence dominated. + u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); } } } } + u_set_dominated_edges_.clear(); } // Returns list of non-zero columns of a particular indx. @@ -217,17 +226,9 @@ class Flag_complex_sparse_matrix { // Iterate over the non-zero columns for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); - - bool dominated_edge_not_found = false; - try { - edge_to_index_map_.at(std::minmax(row_to_vertex_[rw_u], row_to_vertex_[rw_v])); - } catch (const std::out_of_range& oor) { - dominated_edge_not_found = true; - } - // If the vertex v is not dominated and the edge {u,v} is still in the matrix if (u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && - dominated_edge_not_found) { + u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES -- cgit v1.2.3 From 2cc817bac233681bb9a3c5492f56f48f253907e9 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 11 Jun 2020 08:43:31 +0200 Subject: Remove unused u_set_removed_edges_ --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ab72197d..bd7b9956 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -83,9 +83,6 @@ class Flag_complex_sparse_matrix { // Map from row index to its vertex handle std::vector row_to_vertex_; - // Unordered set of removed edges. (to enforce removal from the matrix) - std::unordered_set> u_set_removed_edges_; - // Unordered set of dominated edges. (to inforce removal from the matrix) std::unordered_set> u_set_dominated_edges_; @@ -227,8 +224,7 @@ class Flag_complex_sparse_matrix { for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (u_set_removed_edges_.find(std::minmax(rw_u, rw_v)) == u_set_removed_edges_.end() && - u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { + if (u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES -- cgit v1.2.3 From 26036ee427a0f9103b90114e9ed428f8c8f1d178 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 11 Jun 2020 10:16:08 +0200 Subject: Make u_set_dominated_edges_ implicit --- .../include/gudhi/Flag_complex_sparse_matrix.h | 58 +++++++++++----------- 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index bd7b9956..cf46898e 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -83,8 +83,9 @@ class Flag_complex_sparse_matrix { // Map from row index to its vertex handle std::vector row_to_vertex_; - // Unordered set of dominated edges. (to inforce removal from the matrix) - std::unordered_set> u_set_dominated_edges_; + // Index of the current edge in the backwards walk. Edges <= current_backward are part of the temporary graph, + // while edges > current_backward are removed unless critical_edge_indicator_. + Row_index current_backward = -1; // Map from edge to its index std::unordered_map> edge_to_index_map_; @@ -177,40 +178,34 @@ class Flag_complex_sparse_matrix { std::endl; #endif // DEBUG_TRACES std::set effected_indices = three_clique_indices(indx); - if (effected_indices.size() > 0) { - for (auto idx = indx - 1; idx > 0; idx--) { - Edge edge = std::get<0>(f_edge_vector_[idx]); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - // If idx is not critical so it should be processed, otherwise it stays in the graph - if (!critical_edge_indicator_[idx]) { - // If idx is affected - if (effected_indices.find(idx) != effected_indices.end()) { - if (!edge_is_dominated(edge)) { + // Cannot use boost::adaptors::reverse in such dynamic cases apparently + for (auto it = effected_indices.rbegin(); it != effected_indices.rend(); ++it) { + current_backward = *it; + Edge edge = std::get<0>(f_edge_vector_[current_backward]); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + // If current_backward is not critical so it should be processed, otherwise it stays in the graph + if (!critical_edge_indicator_[current_backward]) { + if (!edge_is_dominated(edge)) { #ifdef DEBUG_TRACES - std::cout << "The curent index became critical " << idx << std::endl; + std::cout << "The curent index became critical " << current_backward << std::endl; #endif // DEBUG_TRACES - critical_edge_indicator_[idx] = true; - filtered_edge_output({u, v}, filt); - std::set inner_effected_indcs = three_clique_indices(idx); - for (auto inr_idx : inner_effected_indcs) { - effected_indices.emplace(inr_idx); - } + critical_edge_indicator_[current_backward] = true; + filtered_edge_output({u, v}, filt); + std::set inner_effected_indcs = three_clique_indices(current_backward); + for (auto inr_idx : inner_effected_indcs) { + if(inr_idx < current_backward) // && !critical_edge_indicator_[inr_idx] + effected_indices.emplace(inr_idx); + } #ifdef DEBUG_TRACES - std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " - << filt << std::endl; + std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " + << filt << std::endl; #endif // DEBUG_TRACES - } else { - u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); - } - } else { - // Idx is not affected hence dominated. - u_set_dominated_edges_.emplace(std::minmax(vertex_to_row_[u], vertex_to_row_[v])); - } } } } - u_set_dominated_edges_.clear(); + // Clear the implicit "removed from graph" data structure + current_backward = -1; } // Returns list of non-zero columns of a particular indx. @@ -224,7 +219,10 @@ class Flag_complex_sparse_matrix { for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if (u_set_dominated_edges_.find(std::minmax(rw_u, rw_v)) == u_set_dominated_edges_.end()) { + Row_index ei; + if (rw_u == rw_v || + (ei = edge_to_index_map_.at(std::minmax(row_to_vertex_[rw_u], row_to_vertex_[rw_v]))) <= current_backward || + critical_edge_indicator_[ei]) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); #ifdef DEBUG_TRACES -- cgit v1.2.3 From b67cb5fdb8073371f051ebc4a70349d5521e11dd Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 11 Jun 2020 10:44:29 +0200 Subject: Store edge indices instead of unused filtration value, in the matrix --- .../include/gudhi/Flag_complex_sparse_matrix.h | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index cf46898e..ecac060b 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -68,7 +68,7 @@ class Flag_complex_sparse_matrix { using Row_index = std::size_t; // The sparse matrix data type - using Sparse_row_matrix = Eigen::SparseMatrix; + using Sparse_row_matrix = Eigen::SparseMatrix; // A range of row indices using Row_indices_vector = std::vector; @@ -221,7 +221,7 @@ class Flag_complex_sparse_matrix { // If the vertex v is not dominated and the edge {u,v} is still in the matrix Row_index ei; if (rw_u == rw_v || - (ei = edge_to_index_map_.at(std::minmax(row_to_vertex_[rw_u], row_to_vertex_[rw_v]))) <= current_backward || + (ei = it.value()) <= current_backward || critical_edge_indicator_[ei]) { // inner index, here it is equal to it.columns() non_zero_indices.push_back(rw_v); @@ -249,27 +249,28 @@ class Flag_complex_sparse_matrix { } // Insert a vertex in the data structure - void insert_vertex(Vertex_handle vertex, Filtration_value filt_val) { - auto result = vertex_to_row_.emplace(vertex, row_to_vertex_.size()); + void insert_vertex(Vertex_handle vertex) { + auto n = row_to_vertex_.size(); + auto result = vertex_to_row_.emplace(vertex, n); // If it was not already inserted - Value won't be updated by emplace if it is already present if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix_.insert(row_to_vertex_.size(), row_to_vertex_.size()) = filt_val; - // Must be done after sparse_row_adjacency_matrix_ insertion + sparse_row_adjacency_matrix_.insert(n, n) = -1; // not an edge + // Must be done after reading its size() row_to_vertex_.push_back(vertex); } } // Insert an edge in the data structure // @exception std::invalid_argument In debug mode, if u == v - void insert_new_edge(Vertex_handle u, Vertex_handle v, Filtration_value filt_val) + void insert_new_edge(Vertex_handle u, Vertex_handle v, Row_index idx) { // The edge must not be added before, it should be a new edge. - insert_vertex(u, filt_val); + insert_vertex(u); GUDHI_CHECK((u != v), std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); - insert_vertex(v, filt_val); + insert_vertex(v); #ifdef DEBUG_TRACES std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; #endif // DEBUG_TRACES @@ -279,8 +280,8 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "Inserting the edge " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = filt_val; - sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = filt_val; + sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = idx; + sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = idx; } public: @@ -354,7 +355,7 @@ class Flag_complex_sparse_matrix { Filtration_value filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) - insert_new_edge(u, v, filt); + insert_new_edge(u, v, endIdx); edge_to_index_map_.emplace(std::minmax(u, v), endIdx); critical_edge_indicator_.push_back(false); -- cgit v1.2.3 From 7ebe8e86834525383e9ae4506230ad48a59fc70c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 11 Jun 2020 11:37:06 +0200 Subject: Replace SparseMatrix with vector This makes insertions much faster --- src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index ecac060b..2a85c0a8 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -68,7 +68,9 @@ class Flag_complex_sparse_matrix { using Row_index = std::size_t; // The sparse matrix data type - using Sparse_row_matrix = Eigen::SparseMatrix; + // (Eigen::SparseMatrix has slow insertions) + using Sparse_vector = Eigen::SparseVector; + using Sparse_row_matrix = std::vector; // A range of row indices using Row_indices_vector = std::vector; @@ -216,7 +218,7 @@ class Flag_complex_sparse_matrix { std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES // Iterate over the non-zero columns - for (typename Sparse_row_matrix::InnerIterator it(sparse_row_adjacency_matrix_, rw_u); it; ++it) { + for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { Row_index rw_v = it.index(); // If the vertex v is not dominated and the edge {u,v} is still in the matrix Row_index ei; @@ -255,7 +257,7 @@ class Flag_complex_sparse_matrix { // If it was not already inserted - Value won't be updated by emplace if it is already present if (result.second) { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix_.insert(n, n) = -1; // not an edge + sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge // Must be done after reading its size() row_to_vertex_.push_back(vertex); } @@ -280,8 +282,8 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "Inserting the edge " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - sparse_row_adjacency_matrix_.insert(rw_u->second, rw_v->second) = idx; - sparse_row_adjacency_matrix_.insert(rw_v->second, rw_u->second) = idx; + sparse_row_adjacency_matrix_[rw_u->second].insert(rw_v->second) = idx; + sparse_row_adjacency_matrix_[rw_v->second].insert(rw_u->second) = idx; } public: @@ -306,7 +308,7 @@ class Flag_complex_sparse_matrix { vertices.emplace(v); } // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. - sparse_row_adjacency_matrix_ = Sparse_row_matrix(vertices.size(), vertices.size()); + sparse_row_adjacency_matrix_.resize(vertices.size(), Sparse_vector(vertices.size())); } /** \brief Flag_complex_sparse_matrix constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. @@ -317,7 +319,8 @@ class Flag_complex_sparse_matrix { * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` */ Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) - : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), boost::num_vertices(one_skeleton_graph)) { + : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), + Sparse_vector(boost::num_vertices(one_skeleton_graph))) { // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { -- cgit v1.2.3 From a9af62e9dfe0bf2b8bc3dd52b09de2c4bab0d799 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Thu, 11 Jun 2020 12:27:38 +0200 Subject: Make some neighborhoods open --- .../include/gudhi/Flag_complex_sparse_matrix.h | 69 ++++++++++------------ 1 file changed, 32 insertions(+), 37 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 2a85c0a8..718955c3 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -117,7 +117,7 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; #endif // DEBUG_TRACES - auto common_neighbours = closed_common_neighbours_row_index(rw_u, rw_v); + auto common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); #ifdef DEBUG_TRACES std::cout << "And its common neighbours are." << std::endl; for (auto neighbour : common_neighbours) { @@ -125,20 +125,16 @@ class Flag_complex_sparse_matrix { } std::cout<< std::endl; #endif // DEBUG_TRACES - if (common_neighbours.size() > 2) { - if (common_neighbours.size() == 3) - return true; - else - for (auto rw_c : common_neighbours) { - if (rw_c != rw_u && rw_c != rw_v) { - auto neighbours_c = closed_neighbours_row_index(rw_c); - // If neighbours_c contains the common neighbours. - if (std::includes(neighbours_c.begin(), neighbours_c.end(), common_neighbours.begin(), - common_neighbours.end())) - return true; - } - } - } + if (common_neighbours.size() == 1) + return true; + else + for (auto rw_c : common_neighbours) { + auto neighbours_c = neighbours_row_index(rw_c, true); + // If neighbours_c contains the common neighbours. + if (std::includes(neighbours_c.begin(), neighbours_c.end(), + common_neighbours.begin(), common_neighbours.end())) + return true; + } return false; } @@ -157,17 +153,13 @@ class Flag_complex_sparse_matrix { auto rw_u = vertex_to_row_[u]; auto rw_v = vertex_to_row_[v]; - Row_indices_vector common_neighbours = closed_common_neighbours_row_index(rw_u, rw_v); + Row_indices_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); - if (common_neighbours.size() > 2) { - for (auto rw_c : common_neighbours) { - if (rw_c != rw_u && rw_c != rw_v) { - auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex_[rw_c]); - edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_v]); - edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_u]); - } - } + for (auto rw_c : common_neighbours) { + auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); + auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex_[rw_c]); + edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_v]); + edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_u]); } return edge_indices; } @@ -210,23 +202,25 @@ class Flag_complex_sparse_matrix { current_backward = -1; } - // Returns list of non-zero columns of a particular indx. - Row_indices_vector closed_neighbours_row_index(Row_index rw_u) const + // Returns list of neighbors of a particular indx. + Row_indices_vector neighbours_row_index(Row_index rw_u, bool closed) const { - Row_indices_vector non_zero_indices; + Row_indices_vector neighbors; + neighbors.reserve(sparse_row_adjacency_matrix_[rw_u].nonZeros()); // too much, but who cares #ifdef DEBUG_TRACES std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES // Iterate over the non-zero columns for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { Row_index rw_v = it.index(); - // If the vertex v is not dominated and the edge {u,v} is still in the matrix + if (!closed && rw_u == rw_v) continue; Row_index ei; - if (rw_u == rw_v || + // If the vertex v is not dominated and the edge {u,v} is still in the matrix + if ((closed && rw_u == rw_v) || (ei = it.value()) <= current_backward || critical_edge_indicator_[ei]) { // inner index, here it is equal to it.columns() - non_zero_indices.push_back(rw_v); + neighbors.push_back(rw_v); #ifdef DEBUG_TRACES std::cout << row_to_vertex_[rw_v] << ", " ; #endif // DEBUG_TRACES @@ -235,17 +229,18 @@ class Flag_complex_sparse_matrix { #ifdef DEBUG_TRACES std::cout << std::endl; #endif // DEBUG_TRACES - return non_zero_indices; + return neighbors; } - // Returns the list of closed neighbours of the edge :{u,v}. - Row_indices_vector closed_common_neighbours_row_index(Row_index rw_u, Row_index rw_v) const + // Returns the list of open neighbours of the edge :{u,v}. + Row_indices_vector open_common_neighbours_row_index(Row_index rw_u, Row_index rw_v) const { - Row_indices_vector non_zero_indices_u = closed_neighbours_row_index(rw_u); - Row_indices_vector non_zero_indices_v = closed_neighbours_row_index(rw_v); + Row_indices_vector non_zero_indices_u = neighbours_row_index(rw_u, false); + Row_indices_vector non_zero_indices_v = neighbours_row_index(rw_v, false); Row_indices_vector common; + common.reserve(std::min(non_zero_indices_u.size(), non_zero_indices_v.size())); std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), - non_zero_indices_v.end(), std::inserter(common, common.begin())); + non_zero_indices_v.end(), std::back_inserter(common)); return common; } -- cgit v1.2.3 From 5e6b64501b27aec000ecd1c495e35aaa6eb92cda Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Jun 2020 18:20:58 +0200 Subject: Split Row_index into IVertex and Edge_index We can always choose other names, the main goal was being able to identify what is what from the name. --- .../include/gudhi/Flag_complex_sparse_matrix.h | 69 +++++++++++----------- .../point_cloud_edge_collapse_rips_persistence.cpp | 2 +- 2 files changed, 35 insertions(+), 36 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 718955c3..2b939285 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -64,16 +64,17 @@ class Flag_complex_sparse_matrix { using Edge = std::pair; private: - // Row_index type in the sparse matrix - using Row_index = std::size_t; + // internal numbering of vertices and edges + using IVertex = std::size_t; + using Edge_index = std::size_t; // The sparse matrix data type - // (Eigen::SparseMatrix has slow insertions) - using Sparse_vector = Eigen::SparseVector; + // (Eigen::SparseMatrix has slow insertions) + using Sparse_vector = Eigen::SparseVector; using Sparse_row_matrix = std::vector; // A range of row indices - using Row_indices_vector = std::vector; + using IVertex_vector = std::vector; public: /** \brief Filtered_edge is a type to store an edge with its filtration value. */ @@ -87,33 +88,32 @@ class Flag_complex_sparse_matrix { // Index of the current edge in the backwards walk. Edges <= current_backward are part of the temporary graph, // while edges > current_backward are removed unless critical_edge_indicator_. - Row_index current_backward = -1; + Edge_index current_backward = -1; // Map from edge to its index - std::unordered_map> edge_to_index_map_; + std::unordered_map> edge_to_index_map_; - // Boolean vector to indicate if the index is critical or not. + // Boolean vector to indicate if the edge is critical. std::vector critical_edge_indicator_; // Map from vertex handle to its row index - std::unordered_map vertex_to_row_; + std::unordered_map vertex_to_row_; // Stores the Sparse matrix of Filtration values representing the original graph. - // This is row-major version of the same sparse-matrix, to facilitate easy access - // to elements when traversing the matrix row-wise. + // The matrix rows and columns are indexed by IVertex. Sparse_row_matrix sparse_row_adjacency_matrix_; - // Vector of filtered edges, for edge-collapse, the indices of the edges are the row-indices. + // The input, a vector of filtered edges. std::vector f_edge_vector_; - // Edge e is the actual edge (u,v). Not the row ids in the matrixs + // Edge e is the actual edge (u,v), with Vertex_handle u and v, not IVertex. bool edge_is_dominated(const Edge& edge) const { Vertex_handle u = std::get<0>(edge); Vertex_handle v = std::get<1>(edge); - const Row_index rw_u = vertex_to_row_.at(u); - const Row_index rw_v = vertex_to_row_.at(v); + const IVertex rw_u = vertex_to_row_.at(u); + const IVertex rw_v = vertex_to_row_.at(v); #ifdef DEBUG_TRACES std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; #endif // DEBUG_TRACES @@ -139,8 +139,8 @@ class Flag_complex_sparse_matrix { } // Returns the edges connecting u and v (extremities of crit) to their common neighbors (not themselves) - std::set three_clique_indices(Row_index crit) { - std::set edge_indices; + std::set three_clique_indices(Edge_index crit) { + std::set edge_indices; Edge edge = std::get<0>(f_edge_vector_[crit]); Vertex_handle u = std::get<0>(edge); @@ -153,7 +153,7 @@ class Flag_complex_sparse_matrix { auto rw_u = vertex_to_row_[u]; auto rw_v = vertex_to_row_[v]; - Row_indices_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); + IVertex_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); for (auto rw_c : common_neighbours) { auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); @@ -164,14 +164,14 @@ class Flag_complex_sparse_matrix { return edge_indices; } - // Detect and set all indices that are becoming critical + // Detect and set all edges that are becoming critical template - void set_edge_critical(Row_index indx, Filtration_value filt, FilteredEdgeOutput filtered_edge_output) { + void set_edge_critical(Edge_index indx, Filtration_value filt, FilteredEdgeOutput filtered_edge_output) { #ifdef DEBUG_TRACES std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << std::endl; #endif // DEBUG_TRACES - std::set effected_indices = three_clique_indices(indx); + std::set effected_indices = three_clique_indices(indx); // Cannot use boost::adaptors::reverse in such dynamic cases apparently for (auto it = effected_indices.rbegin(); it != effected_indices.rend(); ++it) { current_backward = *it; @@ -186,7 +186,7 @@ class Flag_complex_sparse_matrix { #endif // DEBUG_TRACES critical_edge_indicator_[current_backward] = true; filtered_edge_output({u, v}, filt); - std::set inner_effected_indcs = three_clique_indices(current_backward); + std::set inner_effected_indcs = three_clique_indices(current_backward); for (auto inr_idx : inner_effected_indcs) { if(inr_idx < current_backward) // && !critical_edge_indicator_[inr_idx] effected_indices.emplace(inr_idx); @@ -202,24 +202,23 @@ class Flag_complex_sparse_matrix { current_backward = -1; } - // Returns list of neighbors of a particular indx. - Row_indices_vector neighbours_row_index(Row_index rw_u, bool closed) const + // Returns list of neighbors of a particular vertex. + IVertex_vector neighbours_row_index(IVertex rw_u, bool closed) const { - Row_indices_vector neighbors; + IVertex_vector neighbors; neighbors.reserve(sparse_row_adjacency_matrix_[rw_u].nonZeros()); // too much, but who cares #ifdef DEBUG_TRACES std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; #endif // DEBUG_TRACES - // Iterate over the non-zero columns + // Iterate over the neighbors for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { - Row_index rw_v = it.index(); + IVertex rw_v = it.index(); if (!closed && rw_u == rw_v) continue; - Row_index ei; + Edge_index ei; // If the vertex v is not dominated and the edge {u,v} is still in the matrix if ((closed && rw_u == rw_v) || (ei = it.value()) <= current_backward || critical_edge_indicator_[ei]) { - // inner index, here it is equal to it.columns() neighbors.push_back(rw_v); #ifdef DEBUG_TRACES std::cout << row_to_vertex_[rw_v] << ", " ; @@ -233,11 +232,11 @@ class Flag_complex_sparse_matrix { } // Returns the list of open neighbours of the edge :{u,v}. - Row_indices_vector open_common_neighbours_row_index(Row_index rw_u, Row_index rw_v) const + IVertex_vector open_common_neighbours_row_index(IVertex rw_u, IVertex rw_v) const { - Row_indices_vector non_zero_indices_u = neighbours_row_index(rw_u, false); - Row_indices_vector non_zero_indices_v = neighbours_row_index(rw_v, false); - Row_indices_vector common; + IVertex_vector non_zero_indices_u = neighbours_row_index(rw_u, false); + IVertex_vector non_zero_indices_v = neighbours_row_index(rw_v, false); + IVertex_vector common; common.reserve(std::min(non_zero_indices_u.size(), non_zero_indices_v.size())); std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), non_zero_indices_v.end(), std::back_inserter(common)); @@ -260,7 +259,7 @@ class Flag_complex_sparse_matrix { // Insert an edge in the data structure // @exception std::invalid_argument In debug mode, if u == v - void insert_new_edge(Vertex_handle u, Vertex_handle v, Row_index idx) + void insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) { // The edge must not be added before, it should be a new edge. insert_vertex(u); @@ -345,7 +344,7 @@ class Flag_complex_sparse_matrix { std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); #endif - for (Row_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { + for (Edge_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { Filtered_edge fec = f_edge_vector_[endIdx]; Edge edge = std::get<0>(fec); Vertex_handle u = std::get<0>(edge); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index fcda7bb7..19f083c4 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -163,4 +163,4 @@ void program_options(int argc, char* argv[], std::string& off_file_points, std:: std::cout << visible << std::endl; exit(-1); } -} \ No newline at end of file +} -- cgit v1.2.3 From 2977b097971c4bf314cf0595171c86bce81476b8 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Jun 2020 19:22:20 +0200 Subject: Expand the matrix dynamically when inserting new vertices --- .../include/gudhi/Flag_complex_sparse_matrix.h | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index 2b939285..c281b2ed 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -250,6 +250,8 @@ class Flag_complex_sparse_matrix { auto result = vertex_to_row_.emplace(vertex, n); // If it was not already inserted - Value won't be updated by emplace if it is already present if (result.second) { + // Expand the matrix. The size of rows is irrelevant. + sparse_row_adjacency_matrix_.emplace_back((std::numeric_limits::max)()); // Initializing the diagonal element of the adjency matrix corresponding to rw_b. sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge // Must be done after reading its size() @@ -291,19 +293,7 @@ class Flag_complex_sparse_matrix { */ template Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) - : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { - // To get the number of vertices - std::unordered_set vertices; - for (Filtered_edge filtered_edge : filtered_edge_range) { - Vertex_handle u; - Vertex_handle v; - std::tie(u,v) = std::get<0>(filtered_edge); - vertices.emplace(u); - vertices.emplace(v); - } - // Initializing sparse_row_adjacency_matrix_, This is a row-major sparse matrix. - sparse_row_adjacency_matrix_.resize(vertices.size(), Sparse_vector(vertices.size())); - } + : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { } /** \brief Flag_complex_sparse_matrix constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. * @@ -312,9 +302,7 @@ class Flag_complex_sparse_matrix { * * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` */ - Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) - : sparse_row_adjacency_matrix_(boost::num_vertices(one_skeleton_graph), - Sparse_vector(boost::num_vertices(one_skeleton_graph))) { + Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) { // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { -- cgit v1.2.3 From 13fa9e928582480e1a6773297293d9adf7042be6 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Jun 2020 20:09:42 +0200 Subject: Let insert_vertex return some info --- .../include/gudhi/Flag_complex_sparse_matrix.h | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index c281b2ed..a16efd67 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -245,7 +245,7 @@ class Flag_complex_sparse_matrix { } // Insert a vertex in the data structure - void insert_vertex(Vertex_handle vertex) { + IVertex insert_vertex(Vertex_handle vertex) { auto n = row_to_vertex_.size(); auto result = vertex_to_row_.emplace(vertex, n); // If it was not already inserted - Value won't be updated by emplace if it is already present @@ -257,29 +257,22 @@ class Flag_complex_sparse_matrix { // Must be done after reading its size() row_to_vertex_.push_back(vertex); } + return result.first->second; } // Insert an edge in the data structure // @exception std::invalid_argument In debug mode, if u == v void insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) { + GUDHI_CHECK((u != v), std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); // The edge must not be added before, it should be a new edge. - insert_vertex(u); - GUDHI_CHECK((u != v), - std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); - - insert_vertex(v); -#ifdef DEBUG_TRACES - std::cout << "Insertion of the edge begins " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - - auto rw_u = vertex_to_row_.find(u); - auto rw_v = vertex_to_row_.find(v); + IVertex rw_u = insert_vertex(u); + IVertex rw_v = insert_vertex(v); #ifdef DEBUG_TRACES std::cout << "Inserting the edge " << u <<", " << v << std::endl; #endif // DEBUG_TRACES - sparse_row_adjacency_matrix_[rw_u->second].insert(rw_v->second) = idx; - sparse_row_adjacency_matrix_[rw_v->second].insert(rw_u->second) = idx; + sparse_row_adjacency_matrix_[rw_u].insert(rw_v) = idx; + sparse_row_adjacency_matrix_[rw_v].insert(rw_u) = idx; } public: -- cgit v1.2.3 From 5cef9998a86f76ef1eb51ba53713cec52443cb19 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 17 Jun 2020 20:38:20 +0200 Subject: Map *internal* edges to their index --- .../include/gudhi/Flag_complex_sparse_matrix.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h index a16efd67..4402523f 100644 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h @@ -67,6 +67,7 @@ class Flag_complex_sparse_matrix { // internal numbering of vertices and edges using IVertex = std::size_t; using Edge_index = std::size_t; + using IEdge = std::pair; // The sparse matrix data type // (Eigen::SparseMatrix has slow insertions) @@ -90,8 +91,8 @@ class Flag_complex_sparse_matrix { // while edges > current_backward are removed unless critical_edge_indicator_. Edge_index current_backward = -1; - // Map from edge to its index - std::unordered_map> edge_to_index_map_; + // Map from IEdge to its index + std::unordered_map> iedge_to_index_map_; // Boolean vector to indicate if the edge is critical. std::vector critical_edge_indicator_; @@ -156,10 +157,10 @@ class Flag_complex_sparse_matrix { IVertex_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); for (auto rw_c : common_neighbours) { - auto e_with_new_nbhr_v = std::minmax(u, row_to_vertex_[rw_c]); - auto e_with_new_nbhr_u = std::minmax(v, row_to_vertex_[rw_c]); - edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_v]); - edge_indices.emplace(edge_to_index_map_[e_with_new_nbhr_u]); + IEdge e_with_new_nbhr_v = std::minmax(rw_u, rw_c); + IEdge e_with_new_nbhr_u = std::minmax(rw_v, rw_c); + edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_v]); + edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_u]); } return edge_indices; } @@ -262,7 +263,7 @@ class Flag_complex_sparse_matrix { // Insert an edge in the data structure // @exception std::invalid_argument In debug mode, if u == v - void insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) + IEdge insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) { GUDHI_CHECK((u != v), std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); // The edge must not be added before, it should be a new edge. @@ -273,6 +274,7 @@ class Flag_complex_sparse_matrix { #endif // DEBUG_TRACES sparse_row_adjacency_matrix_[rw_u].insert(rw_v) = idx; sparse_row_adjacency_matrix_[rw_v].insert(rw_u) = idx; + return std::minmax(rw_u, rw_v); } public: @@ -333,9 +335,9 @@ class Flag_complex_sparse_matrix { Filtration_value filt = std::get<1>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) - insert_new_edge(u, v, endIdx); + IEdge ie = insert_new_edge(u, v, endIdx); - edge_to_index_map_.emplace(std::minmax(u, v), endIdx); + iedge_to_index_map_.emplace(ie, endIdx); critical_edge_indicator_.push_back(false); if (!edge_is_dominated(edge)) { -- cgit v1.2.3 From fcd06dde50637028a2028adff84e5bb2b2236178 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Jun 2020 07:31:45 +0200 Subject: Code review: rename Flag_complex_sparse_matrix as edge_collapser and filtered_edge_collapse method as process_edges --- src/Collapse/doc/intro_edge_collapse.h | 6 +- .../example/edge_collapse_basic_example.cpp | 12 +- .../example/edge_collapse_conserve_persistence.cpp | 10 +- .../include/gudhi/Flag_complex_edge_collapser.h | 358 +++++++++++++++++++++ .../include/gudhi/Flag_complex_sparse_matrix.h | 358 --------------------- src/Collapse/test/collapse_unit_test.cpp | 18 +- ...tance_matrix_edge_collapse_rips_persistence.cpp | 10 +- .../point_cloud_edge_collapse_rips_persistence.cpp | 10 +- 8 files changed, 391 insertions(+), 391 deletions(-) create mode 100644 src/Collapse/include/gudhi/Flag_complex_edge_collapser.h delete mode 100644 src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h (limited to 'src/Collapse/include') diff --git a/src/Collapse/doc/intro_edge_collapse.h b/src/Collapse/doc/intro_edge_collapse.h index 15f2208c..2b272a9e 100644 --- a/src/Collapse/doc/intro_edge_collapse.h +++ b/src/Collapse/doc/intro_edge_collapse.h @@ -76,9 +76,9 @@ namespace collapse { * * \subsection edgecollapseexample Basic edge collapse * - * This example builds the `Flag_complex_sparse_matrix` from a proximity graph represented as a list of - * `Flag_complex_sparse_matrix::Filtered_edge`. - * Then it collapses edges and displays a new list of `Flag_complex_sparse_matrix::Filtered_edge` (with less edges) + * This example builds the `Flag_complex_edge_collapser` from a proximity graph represented as a list of + * `Flag_complex_edge_collapser::Filtered_edge`. + * Then it collapses edges and displays a new list of `Flag_complex_edge_collapser::Filtered_edge` (with less edges) * that will preserve the persistence homology computation. * * \include Collapse/edge_collapse_basic_example.cpp diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index a154c6bb..333bc231 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -7,10 +7,10 @@ int main() { // Type definitions using Filtration_value = float; using Vertex_handle = short; - using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; - using Filtered_edge = Flag_complex_sparse_matrix::Filtered_edge; + using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; + using Filtered_edge = Flag_complex_edge_collapser::Filtered_edge; using Filtered_edge_list = std::vector; - using Edge = Flag_complex_sparse_matrix::Edge; + using Edge = Flag_complex_edge_collapser::Edge; // 1 2 // o---o @@ -26,11 +26,11 @@ int main() { {{0, 2}, 2.}, {{1, 3}, 2.}}; - Flag_complex_sparse_matrix flag_complex_sparse_matrix(graph); + Flag_complex_edge_collapser edge_collapser(graph); Filtered_edge_list collapse_edges; // Retrieve collapse edges from the output iterator - flag_complex_sparse_matrix.filtered_edge_collapse( + edge_collapser.process_edges( [&collapse_edges](std::pair edge, Filtration_value filtration) { collapse_edges.push_back({edge, filtration}); }); diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index 9c561efc..701ea1af 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -8,7 +8,7 @@ * - YYYY/MM Author: Description of the modification */ -#include +#include #include #include #include @@ -27,8 +27,8 @@ using Vertex_handle = Simplex_tree::Vertex_handle; using Point = std::vector; using Vector_of_points = std::vector; -using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; -using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; +using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; +using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -112,14 +112,14 @@ int main(int argc, char* argv[]) { int ambient_dim = point_vector[0].size(); // ***** Simplex tree from a flag complex built after collapse ***** - Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); + Flag_complex_edge_collapser edge_collapser(proximity_graph); Simplex_tree stree_from_collapse; for (Vertex_handle vertex = 0; static_cast(vertex) < point_vector.size(); vertex++) { // insert the vertex with a 0. filtration value just like a Rips stree_from_collapse.insert_simplex({vertex}, 0.); } - mat_filt_edge_coll.filtered_edge_collapse( + edge_collapser.process_edges( [&stree_from_collapse](const std::vector& edge, Filtration_value filtration) { // insert the edge stree_from_collapse.insert_simplex(edge, filtration); diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h new file mode 100644 index 00000000..32438c3b --- /dev/null +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -0,0 +1,358 @@ +/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. + * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. + * Author(s): Siddharth Pritam + * + * Copyright (C) 2020 Inria + * + * Modification(s): + * - 2020/03 Vincent Rouvreau: integration to the gudhi library + * - YYYY/MM Author: Description of the modification + */ + +#ifndef FLAG_COMPLEX_EDGE_COLLAPSER_H_ +#define FLAG_COMPLEX_EDGE_COLLAPSER_H_ + +#include +#include + +#include +#include + +#include + +#ifdef GUDHI_USE_TBB +#include +#endif + +#include +#include // for std::pair +#include +#include +#include +#include +#include // for std::tie +#include // for std::includes +#include // for std::inserter + +namespace Gudhi { + +namespace collapse { + +/** + * \class Flag_complex_edge_collapser + * \brief Flag complex sparse matrix data structure. + * + * \ingroup collapse + * + * \details + * This class stores a Flag complex + * in an Eigen sparse matrix. + * + * \tparam Vertex type must be a signed integer type. It admits a total order <. + * \tparam Filtration type for the value of the filtration function. Must be comparable with <. + */ +template +class Flag_complex_edge_collapser { + public: + /** \brief Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph. */ + using Vertex_handle = Vertex; + /** \brief Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph. */ + using Filtration_value = Filtration; + /** \brief This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e + * {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables. + */ + using Edge = std::pair; + + private: + // internal numbering of vertices and edges + using IVertex = std::size_t; + using Edge_index = std::size_t; + using IEdge = std::pair; + + // The sparse matrix data type + // (Eigen::SparseMatrix has slow insertions) + using Sparse_vector = Eigen::SparseVector; + using Sparse_row_matrix = std::vector; + + // A range of row indices + using IVertex_vector = std::vector; + + public: + /** \brief Filtered_edge is a type to store an edge with its filtration value. */ + using Filtered_edge = std::pair; + /** \brief Proximity_graph is a type that can be used to construct easily a Flag_complex_edge_collapser. */ + using Proximity_graph = Gudhi::Proximity_graph; + + private: + // Map from row index to its vertex handle + std::vector row_to_vertex_; + + // Index of the current edge in the backwards walk. Edges <= current_backward are part of the temporary graph, + // while edges > current_backward are removed unless critical_edge_indicator_. + Edge_index current_backward = -1; + + // Map from IEdge to its index + std::unordered_map> iedge_to_index_map_; + + // Boolean vector to indicate if the edge is critical. + std::vector critical_edge_indicator_; + + // Map from vertex handle to its row index + std::unordered_map vertex_to_row_; + + // Stores the Sparse matrix of Filtration values representing the original graph. + // The matrix rows and columns are indexed by IVertex. + Sparse_row_matrix sparse_row_adjacency_matrix_; + + // The input, a vector of filtered edges. + std::vector f_edge_vector_; + + // Edge e is the actual edge (u,v), with Vertex_handle u and v, not IVertex. + bool edge_is_dominated(const Edge& edge) const + { + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + + const IVertex rw_u = vertex_to_row_.at(u); + const IVertex rw_v = vertex_to_row_.at(v); +#ifdef DEBUG_TRACES + std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; +#endif // DEBUG_TRACES + auto common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); +#ifdef DEBUG_TRACES + std::cout << "And its common neighbours are." << std::endl; + for (auto neighbour : common_neighbours) { + std::cout << row_to_vertex_[neighbour] << ", " ; + } + std::cout<< std::endl; +#endif // DEBUG_TRACES + if (common_neighbours.size() == 1) + return true; + else + for (auto rw_c : common_neighbours) { + auto neighbours_c = neighbours_row_index(rw_c, true); + // If neighbours_c contains the common neighbours. + if (std::includes(neighbours_c.begin(), neighbours_c.end(), + common_neighbours.begin(), common_neighbours.end())) + return true; + } + return false; + } + + // Returns the edges connecting u and v (extremities of crit) to their common neighbors (not themselves) + std::set three_clique_indices(Edge_index crit) { + std::set edge_indices; + + Edge edge = std::get<0>(f_edge_vector_[crit]); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + +#ifdef DEBUG_TRACES + std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v + << "} = " << std::get<1>(f_edge_vector_[crit]) << std::endl; +#endif // DEBUG_TRACES + auto rw_u = vertex_to_row_[u]; + auto rw_v = vertex_to_row_[v]; + + IVertex_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); + + for (auto rw_c : common_neighbours) { + IEdge e_with_new_nbhr_v = std::minmax(rw_u, rw_c); + IEdge e_with_new_nbhr_u = std::minmax(rw_v, rw_c); + edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_v]); + edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_u]); + } + return edge_indices; + } + + // Detect and set all edges that are becoming critical + template + void set_edge_critical(Edge_index indx, Filtration_value filt, FilteredEdgeOutput filtered_edge_output) { +#ifdef DEBUG_TRACES + std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << + std::endl; +#endif // DEBUG_TRACES + std::set effected_indices = three_clique_indices(indx); + // Cannot use boost::adaptors::reverse in such dynamic cases apparently + for (auto it = effected_indices.rbegin(); it != effected_indices.rend(); ++it) { + current_backward = *it; + Edge edge = std::get<0>(f_edge_vector_[current_backward]); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + // If current_backward is not critical so it should be processed, otherwise it stays in the graph + if (!critical_edge_indicator_[current_backward]) { + if (!edge_is_dominated(edge)) { +#ifdef DEBUG_TRACES + std::cout << "The curent index became critical " << current_backward << std::endl; +#endif // DEBUG_TRACES + critical_edge_indicator_[current_backward] = true; + filtered_edge_output({u, v}, filt); + std::set inner_effected_indcs = three_clique_indices(current_backward); + for (auto inr_idx : inner_effected_indcs) { + if(inr_idx < current_backward) // && !critical_edge_indicator_[inr_idx] + effected_indices.emplace(inr_idx); + } +#ifdef DEBUG_TRACES + std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " + << filt << std::endl; +#endif // DEBUG_TRACES + } + } + } + // Clear the implicit "removed from graph" data structure + current_backward = -1; + } + + // Returns list of neighbors of a particular vertex. + IVertex_vector neighbours_row_index(IVertex rw_u, bool closed) const + { + IVertex_vector neighbors; + neighbors.reserve(sparse_row_adjacency_matrix_[rw_u].nonZeros()); // too much, but who cares +#ifdef DEBUG_TRACES + std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; +#endif // DEBUG_TRACES + // Iterate over the neighbors + for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { + IVertex rw_v = it.index(); + if (!closed && rw_u == rw_v) continue; + Edge_index ei; + // If the vertex v is not dominated and the edge {u,v} is still in the matrix + if ((closed && rw_u == rw_v) || + (ei = it.value()) <= current_backward || + critical_edge_indicator_[ei]) { + neighbors.push_back(rw_v); +#ifdef DEBUG_TRACES + std::cout << row_to_vertex_[rw_v] << ", " ; +#endif // DEBUG_TRACES + } + } +#ifdef DEBUG_TRACES + std::cout << std::endl; +#endif // DEBUG_TRACES + return neighbors; + } + + // Returns the list of open neighbours of the edge :{u,v}. + IVertex_vector open_common_neighbours_row_index(IVertex rw_u, IVertex rw_v) const + { + IVertex_vector non_zero_indices_u = neighbours_row_index(rw_u, false); + IVertex_vector non_zero_indices_v = neighbours_row_index(rw_v, false); + IVertex_vector common; + common.reserve(std::min(non_zero_indices_u.size(), non_zero_indices_v.size())); + std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), + non_zero_indices_v.end(), std::back_inserter(common)); + + return common; + } + + // Insert a vertex in the data structure + IVertex insert_vertex(Vertex_handle vertex) { + auto n = row_to_vertex_.size(); + auto result = vertex_to_row_.emplace(vertex, n); + // If it was not already inserted - Value won't be updated by emplace if it is already present + if (result.second) { + // Expand the matrix. The size of rows is irrelevant. + sparse_row_adjacency_matrix_.emplace_back((std::numeric_limits::max)()); + // Initializing the diagonal element of the adjency matrix corresponding to rw_b. + sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge + // Must be done after reading its size() + row_to_vertex_.push_back(vertex); + } + return result.first->second; + } + + // Insert an edge in the data structure + // @exception std::invalid_argument In debug mode, if u == v + IEdge insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) + { + GUDHI_CHECK((u != v), std::invalid_argument("Flag_complex_edge_collapser::insert_new_edge with u == v")); + // The edge must not be added before, it should be a new edge. + IVertex rw_u = insert_vertex(u); + IVertex rw_v = insert_vertex(v); +#ifdef DEBUG_TRACES + std::cout << "Inserting the edge " << u <<", " << v << std::endl; +#endif // DEBUG_TRACES + sparse_row_adjacency_matrix_[rw_u].insert(rw_v) = idx; + sparse_row_adjacency_matrix_[rw_v].insert(rw_u) = idx; + return std::minmax(rw_u, rw_v); + } + + public: + /** \brief Flag_complex_edge_collapser constructor from a range of filtered edges. + * + * @param[in] filtered_edge_range Range of filtered edges. Filtered edges must be in + * `Flag_complex_edge_collapser::Filtered_edge`. + * + * There is no need the range to be sorted, as it will be performed in + * `Flag_complex_edge_collapser::process_edges`. + */ + template + Flag_complex_edge_collapser(const Filtered_edge_range& filtered_edge_range) + : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { } + + /** \brief Flag_complex_edge_collapser constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. + * + * @param[in] one_skeleton_graph The one skeleton graph. The graph must be in + * `Flag_complex_edge_collapser::Proximity_graph`. + * + * The constructor is computing and filling a vector of `Flag_complex_edge_collapser::Filtered_edge` + */ + Flag_complex_edge_collapser(const Proximity_graph& one_skeleton_graph) { + // Insert all edges + for (auto edge_it = boost::edges(one_skeleton_graph); + edge_it.first != edge_it.second; ++edge_it.first) { + auto edge = *(edge_it.first); + Vertex_handle u = source(edge, one_skeleton_graph); + Vertex_handle v = target(edge, one_skeleton_graph); + f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); + } + } + + /** \brief Performs edge collapse in a increasing sequence of the filtration value. + * + * \tparam FilteredEdgeOutput is a functor that furnishes `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` + * that will get called on the output edges, in non-decreasing order of filtration. + */ + template + void process_edges(FilteredEdgeOutput filtered_edge_output) { + // Sort edges + auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool + { + return (get<1>(edge_a) < get<1>(edge_b)); + }; + +#ifdef GUDHI_USE_TBB + tbb::parallel_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); +#else + std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); +#endif + + for (Edge_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { + Filtered_edge fec = f_edge_vector_[endIdx]; + Edge edge = std::get<0>(fec); + Vertex_handle u = std::get<0>(edge); + Vertex_handle v = std::get<1>(edge); + Filtration_value filt = std::get<1>(fec); + + // Inserts the edge in the sparse matrix to update the graph (G_i) + IEdge ie = insert_new_edge(u, v, endIdx); + + iedge_to_index_map_.emplace(ie, endIdx); + critical_edge_indicator_.push_back(false); + + if (!edge_is_dominated(edge)) { + critical_edge_indicator_[endIdx] = true; + filtered_edge_output({u, v}, filt); + if (endIdx > 1) + set_edge_critical(endIdx, filt, filtered_edge_output); + } + } + } + +}; + +} // namespace collapse + +} // namespace Gudhi + +#endif // FLAG_COMPLEX_EDGE_COLLAPSER_H_ diff --git a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h b/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h deleted file mode 100644 index 4402523f..00000000 --- a/src/Collapse/include/gudhi/Flag_complex_sparse_matrix.h +++ /dev/null @@ -1,358 +0,0 @@ -/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. - * See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. - * Author(s): Siddharth Pritam - * - * Copyright (C) 2020 Inria - * - * Modification(s): - * - 2020/03 Vincent Rouvreau: integration to the gudhi library - * - YYYY/MM Author: Description of the modification - */ - -#ifndef FLAG_COMPLEX_SPARSE_MATRIX_H_ -#define FLAG_COMPLEX_SPARSE_MATRIX_H_ - -#include -#include - -#include -#include - -#include - -#ifdef GUDHI_USE_TBB -#include -#endif - -#include -#include // for std::pair -#include -#include -#include -#include -#include // for std::tie -#include // for std::includes -#include // for std::inserter - -namespace Gudhi { - -namespace collapse { - -/** - * \class Flag_complex_sparse_matrix - * \brief Flag complex sparse matrix data structure. - * - * \ingroup collapse - * - * \details - * This class stores a Flag complex - * in an Eigen sparse matrix. - * - * \tparam Vertex type must be a signed integer type. It admits a total order <. - * \tparam Filtration type for the value of the filtration function. Must be comparable with <. - */ -template -class Flag_complex_sparse_matrix { - public: - /** \brief Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph. */ - using Vertex_handle = Vertex; - /** \brief Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph. */ - using Filtration_value = Filtration; - /** \brief This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e - * {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables. - */ - using Edge = std::pair; - - private: - // internal numbering of vertices and edges - using IVertex = std::size_t; - using Edge_index = std::size_t; - using IEdge = std::pair; - - // The sparse matrix data type - // (Eigen::SparseMatrix has slow insertions) - using Sparse_vector = Eigen::SparseVector; - using Sparse_row_matrix = std::vector; - - // A range of row indices - using IVertex_vector = std::vector; - - public: - /** \brief Filtered_edge is a type to store an edge with its filtration value. */ - using Filtered_edge = std::pair; - /** \brief Proximity_graph is a type that can be used to construct easily a Flag_complex_sparse_matrix. */ - using Proximity_graph = Gudhi::Proximity_graph; - - private: - // Map from row index to its vertex handle - std::vector row_to_vertex_; - - // Index of the current edge in the backwards walk. Edges <= current_backward are part of the temporary graph, - // while edges > current_backward are removed unless critical_edge_indicator_. - Edge_index current_backward = -1; - - // Map from IEdge to its index - std::unordered_map> iedge_to_index_map_; - - // Boolean vector to indicate if the edge is critical. - std::vector critical_edge_indicator_; - - // Map from vertex handle to its row index - std::unordered_map vertex_to_row_; - - // Stores the Sparse matrix of Filtration values representing the original graph. - // The matrix rows and columns are indexed by IVertex. - Sparse_row_matrix sparse_row_adjacency_matrix_; - - // The input, a vector of filtered edges. - std::vector f_edge_vector_; - - // Edge e is the actual edge (u,v), with Vertex_handle u and v, not IVertex. - bool edge_is_dominated(const Edge& edge) const - { - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - - const IVertex rw_u = vertex_to_row_.at(u); - const IVertex rw_v = vertex_to_row_.at(v); -#ifdef DEBUG_TRACES - std::cout << "The edge {" << u << ", " << v << "} is going for domination check." << std::endl; -#endif // DEBUG_TRACES - auto common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); -#ifdef DEBUG_TRACES - std::cout << "And its common neighbours are." << std::endl; - for (auto neighbour : common_neighbours) { - std::cout << row_to_vertex_[neighbour] << ", " ; - } - std::cout<< std::endl; -#endif // DEBUG_TRACES - if (common_neighbours.size() == 1) - return true; - else - for (auto rw_c : common_neighbours) { - auto neighbours_c = neighbours_row_index(rw_c, true); - // If neighbours_c contains the common neighbours. - if (std::includes(neighbours_c.begin(), neighbours_c.end(), - common_neighbours.begin(), common_neighbours.end())) - return true; - } - return false; - } - - // Returns the edges connecting u and v (extremities of crit) to their common neighbors (not themselves) - std::set three_clique_indices(Edge_index crit) { - std::set edge_indices; - - Edge edge = std::get<0>(f_edge_vector_[crit]); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - -#ifdef DEBUG_TRACES - std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v - << "} = " << std::get<1>(f_edge_vector_[crit]) << std::endl; -#endif // DEBUG_TRACES - auto rw_u = vertex_to_row_[u]; - auto rw_v = vertex_to_row_[v]; - - IVertex_vector common_neighbours = open_common_neighbours_row_index(rw_u, rw_v); - - for (auto rw_c : common_neighbours) { - IEdge e_with_new_nbhr_v = std::minmax(rw_u, rw_c); - IEdge e_with_new_nbhr_u = std::minmax(rw_v, rw_c); - edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_v]); - edge_indices.emplace(iedge_to_index_map_[e_with_new_nbhr_u]); - } - return edge_indices; - } - - // Detect and set all edges that are becoming critical - template - void set_edge_critical(Edge_index indx, Filtration_value filt, FilteredEdgeOutput filtered_edge_output) { -#ifdef DEBUG_TRACES - std::cout << "The curent index with filtration value " << indx << ", " << filt << " is primary critical" << - std::endl; -#endif // DEBUG_TRACES - std::set effected_indices = three_clique_indices(indx); - // Cannot use boost::adaptors::reverse in such dynamic cases apparently - for (auto it = effected_indices.rbegin(); it != effected_indices.rend(); ++it) { - current_backward = *it; - Edge edge = std::get<0>(f_edge_vector_[current_backward]); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - // If current_backward is not critical so it should be processed, otherwise it stays in the graph - if (!critical_edge_indicator_[current_backward]) { - if (!edge_is_dominated(edge)) { -#ifdef DEBUG_TRACES - std::cout << "The curent index became critical " << current_backward << std::endl; -#endif // DEBUG_TRACES - critical_edge_indicator_[current_backward] = true; - filtered_edge_output({u, v}, filt); - std::set inner_effected_indcs = three_clique_indices(current_backward); - for (auto inr_idx : inner_effected_indcs) { - if(inr_idx < current_backward) // && !critical_edge_indicator_[inr_idx] - effected_indices.emplace(inr_idx); - } -#ifdef DEBUG_TRACES - std::cout << "The following edge is critical with filt value: {" << u << "," << v << "}; " - << filt << std::endl; -#endif // DEBUG_TRACES - } - } - } - // Clear the implicit "removed from graph" data structure - current_backward = -1; - } - - // Returns list of neighbors of a particular vertex. - IVertex_vector neighbours_row_index(IVertex rw_u, bool closed) const - { - IVertex_vector neighbors; - neighbors.reserve(sparse_row_adjacency_matrix_[rw_u].nonZeros()); // too much, but who cares -#ifdef DEBUG_TRACES - std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; -#endif // DEBUG_TRACES - // Iterate over the neighbors - for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { - IVertex rw_v = it.index(); - if (!closed && rw_u == rw_v) continue; - Edge_index ei; - // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if ((closed && rw_u == rw_v) || - (ei = it.value()) <= current_backward || - critical_edge_indicator_[ei]) { - neighbors.push_back(rw_v); -#ifdef DEBUG_TRACES - std::cout << row_to_vertex_[rw_v] << ", " ; -#endif // DEBUG_TRACES - } - } -#ifdef DEBUG_TRACES - std::cout << std::endl; -#endif // DEBUG_TRACES - return neighbors; - } - - // Returns the list of open neighbours of the edge :{u,v}. - IVertex_vector open_common_neighbours_row_index(IVertex rw_u, IVertex rw_v) const - { - IVertex_vector non_zero_indices_u = neighbours_row_index(rw_u, false); - IVertex_vector non_zero_indices_v = neighbours_row_index(rw_v, false); - IVertex_vector common; - common.reserve(std::min(non_zero_indices_u.size(), non_zero_indices_v.size())); - std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), - non_zero_indices_v.end(), std::back_inserter(common)); - - return common; - } - - // Insert a vertex in the data structure - IVertex insert_vertex(Vertex_handle vertex) { - auto n = row_to_vertex_.size(); - auto result = vertex_to_row_.emplace(vertex, n); - // If it was not already inserted - Value won't be updated by emplace if it is already present - if (result.second) { - // Expand the matrix. The size of rows is irrelevant. - sparse_row_adjacency_matrix_.emplace_back((std::numeric_limits::max)()); - // Initializing the diagonal element of the adjency matrix corresponding to rw_b. - sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge - // Must be done after reading its size() - row_to_vertex_.push_back(vertex); - } - return result.first->second; - } - - // Insert an edge in the data structure - // @exception std::invalid_argument In debug mode, if u == v - IEdge insert_new_edge(Vertex_handle u, Vertex_handle v, Edge_index idx) - { - GUDHI_CHECK((u != v), std::invalid_argument("Flag_complex_sparse_matrix::insert_new_edge with u == v")); - // The edge must not be added before, it should be a new edge. - IVertex rw_u = insert_vertex(u); - IVertex rw_v = insert_vertex(v); -#ifdef DEBUG_TRACES - std::cout << "Inserting the edge " << u <<", " << v << std::endl; -#endif // DEBUG_TRACES - sparse_row_adjacency_matrix_[rw_u].insert(rw_v) = idx; - sparse_row_adjacency_matrix_[rw_v].insert(rw_u) = idx; - return std::minmax(rw_u, rw_v); - } - - public: - /** \brief Flag_complex_sparse_matrix constructor from a range of filtered edges. - * - * @param[in] filtered_edge_range Range of filtered edges. Filtered edges must be in - * `Flag_complex_sparse_matrix::Filtered_edge`. - * - * There is no need the range to be sorted, as it will be performed in - * `Flag_complex_sparse_matrix::filtered_edge_collapse`. - */ - template - Flag_complex_sparse_matrix(const Filtered_edge_range& filtered_edge_range) - : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { } - - /** \brief Flag_complex_sparse_matrix constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. - * - * @param[in] one_skeleton_graph The one skeleton graph. The graph must be in - * `Flag_complex_sparse_matrix::Proximity_graph`. - * - * The constructor is computing and filling a vector of `Flag_complex_sparse_matrix::Filtered_edge` - */ - Flag_complex_sparse_matrix(const Proximity_graph& one_skeleton_graph) { - // Insert all edges - for (auto edge_it = boost::edges(one_skeleton_graph); - edge_it.first != edge_it.second; ++edge_it.first) { - auto edge = *(edge_it.first); - Vertex_handle u = source(edge, one_skeleton_graph); - Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); - } - } - - /** \brief Performs edge collapse in a increasing sequence of the filtration value. - * - * \tparam FilteredEdgeOutput is a functor that furnishes `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` - * that will get called on the output edges, in non-decreasing order of filtration. - */ - template - void filtered_edge_collapse(FilteredEdgeOutput filtered_edge_output) { - // Sort edges - auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool - { - return (get<1>(edge_a) < get<1>(edge_b)); - }; - -#ifdef GUDHI_USE_TBB - tbb::parallel_sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); -#else - std::sort(f_edge_vector_.begin(), f_edge_vector_.end(), sort_by_filtration); -#endif - - for (Edge_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { - Filtered_edge fec = f_edge_vector_[endIdx]; - Edge edge = std::get<0>(fec); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - Filtration_value filt = std::get<1>(fec); - - // Inserts the edge in the sparse matrix to update the graph (G_i) - IEdge ie = insert_new_edge(u, v, endIdx); - - iedge_to_index_map_.emplace(ie, endIdx); - critical_edge_indicator_.push_back(false); - - if (!edge_is_dominated(edge)) { - critical_edge_indicator_[endIdx] = true; - filtered_edge_output({u, v}, filt); - if (endIdx > 1) - set_edge_critical(endIdx, filt, filtered_edge_output); - } - } - } - -}; - -} // namespace collapse - -} // namespace Gudhi - -#endif // FLAG_COMPLEX_SPARSE_MATRIX_H_ diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 1bec3810..e45dc339 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -26,8 +26,8 @@ using Filtration_value = float; using Vertex_handle = short; -using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; -using Filtered_edge = Flag_complex_sparse_matrix::Filtered_edge; +using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; +using Filtered_edge = Flag_complex_edge_collapser::Filtered_edge; using Filtered_edge_list = std::vector; template @@ -49,9 +49,9 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F } std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_sparse_matrix flag_complex_sparse_matrix(filtered_edges); + Flag_complex_edge_collapser edge_collapser(filtered_edges); Filtered_edge_list collapse_edges; - flag_complex_sparse_matrix.filtered_edge_collapse( + edge_collapser.process_edges( [&collapse_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; collapse_edges.push_back({edge, filtration}); @@ -164,13 +164,13 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { {1., 1.} }; Filtration_value threshold = std::numeric_limits::infinity(); - using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; - Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(point_cloud, + using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; + Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(point_cloud, threshold, Gudhi::Euclidean_distance()); - Flag_complex_sparse_matrix flag_complex_sparse_matrix(proximity_graph); + Flag_complex_edge_collapser edge_collapser(proximity_graph); Filtered_edge_list collapse_edges; - flag_complex_sparse_matrix.filtered_edge_collapse( + edge_collapser.process_edges( [&collapse_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; collapse_edges.push_back({edge, filtration}); diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 7201a6b4..ae9ff32b 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -8,7 +8,7 @@ * - YYYY/MM Author: Description of the modification */ -#include +#include #include #include #include @@ -20,8 +20,8 @@ using Simplex_tree = Gudhi::Simplex_tree; -using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; +using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; +using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -90,14 +90,14 @@ int main(int argc, char* argv[]) { }); // Now we will perform filtered edge collapse to sparsify the edge list edge_t. - Flag_complex_sparse_matrix flag_complex(proximity_graph); + Flag_complex_edge_collapser edge_collapser(proximity_graph); Simplex_tree stree; for (Vertex_handle vertex = 0; static_cast(vertex) < distances.size(); vertex++) { // insert the vertex with a 0. filtration value just like a Rips stree.insert_simplex({vertex}, 0.); } - flag_complex.filtered_edge_collapse( + edge_collapser.process_edges( [&stree](std::vector edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index 19f083c4..d2d31013 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -8,7 +8,7 @@ * - YYYY/MM Author: Description of the modification */ -#include +#include #include #include #include @@ -28,8 +28,8 @@ using Vertex_handle = Simplex_tree::Vertex_handle; using Point = std::vector; using Vector_of_points = std::vector; -using Flag_complex_sparse_matrix = Gudhi::collapse::Flag_complex_sparse_matrix; -using Proximity_graph = Flag_complex_sparse_matrix::Proximity_graph; +using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; +using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; @@ -77,14 +77,14 @@ int main(int argc, char* argv[]) { exit(-1); } - Flag_complex_sparse_matrix mat_filt_edge_coll(proximity_graph); + Flag_complex_edge_collapser edge_collapser(proximity_graph); Simplex_tree stree; for (Vertex_handle vertex = 0; static_cast(vertex) < point_vector.size(); vertex++) { // insert the vertex with a 0. filtration value just like a Rips stree.insert_simplex({vertex}, 0.); } - mat_filt_edge_coll.filtered_edge_collapse( + edge_collapser.process_edges( [&stree](const std::vector& edge, Filtration_value filtration) { // insert the 2 vertices with a 0. filtration value just like a Rips stree.insert_simplex({edge[0]}, 0.); -- cgit v1.2.3 From b525bb68fa0980d4f54d20b7b719a7ec8891afe9 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Jun 2020 10:06:24 +0200 Subject: code review: graph not hardcoded. Implies ctor from filtered edges to be modified --- .../example/edge_collapse_basic_example.cpp | 2 +- .../example/edge_collapse_conserve_persistence.cpp | 2 +- .../include/gudhi/Flag_complex_edge_collapser.h | 41 +++++++++++++++------- src/Collapse/test/collapse_unit_test.cpp | 4 +-- ...tance_matrix_edge_collapse_rips_persistence.cpp | 2 +- .../point_cloud_edge_collapse_rips_persistence.cpp | 2 +- 6 files changed, 34 insertions(+), 19 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index 333bc231..568115f5 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -26,7 +26,7 @@ int main() { {{0, 2}, 2.}, {{1, 3}, 2.}}; - Flag_complex_edge_collapser edge_collapser(graph); + Flag_complex_edge_collapser edge_collapser(graph.begin(), graph.end()); Filtered_edge_list collapse_edges; // Retrieve collapse edges from the output iterator diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index 701ea1af..b28af456 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -28,7 +28,7 @@ using Point = std::vector; using Vector_of_points = std::vector; using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; -using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; +using Proximity_graph = Gudhi::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 32438c3b..6afeaefc 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -54,9 +54,9 @@ namespace collapse { template class Flag_complex_edge_collapser { public: - /** \brief Re-define Vertex as Vertex_handle type to ease the interface with compute_proximity_graph. */ + /** \brief Re-define Vertex as Vertex_handle type to ease the interface with `Gudhi::Proximity_graph`. */ using Vertex_handle = Vertex; - /** \brief Re-define Filtration as Filtration_value type to ease the interface with compute_proximity_graph. */ + /** \brief Re-define Filtration as Filtration_value type to ease the interface with `Gudhi::Proximity_graph`. */ using Filtration_value = Filtration; /** \brief This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e * {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables. @@ -80,8 +80,6 @@ class Flag_complex_edge_collapser { public: /** \brief Filtered_edge is a type to store an edge with its filtration value. */ using Filtered_edge = std::pair; - /** \brief Proximity_graph is a type that can be used to construct easily a Flag_complex_edge_collapser. */ - using Proximity_graph = Gudhi::Proximity_graph; private: // Map from row index to its vertex handle @@ -280,24 +278,41 @@ class Flag_complex_edge_collapser { public: /** \brief Flag_complex_edge_collapser constructor from a range of filtered edges. * - * @param[in] filtered_edge_range Range of filtered edges. Filtered edges must be in + * @param[in] begin Iterator on the first element of a filtered edges range. Filtered edges must be in + * `Flag_complex_edge_collapser::Filtered_edge`. + * + * @param[in] end Iterator on the last element of a filtered edges range. Filtered edges must be in * `Flag_complex_edge_collapser::Filtered_edge`. * * There is no need the range to be sorted, as it will be performed in * `Flag_complex_edge_collapser::process_edges`. */ - template - Flag_complex_edge_collapser(const Filtered_edge_range& filtered_edge_range) - : f_edge_vector_(filtered_edge_range.begin(), filtered_edge_range.end()) { } + template + Flag_complex_edge_collapser(Filtered_edge_iterator begin, Filtered_edge_iterator end) + : f_edge_vector_(begin, end) { } - /** \brief Flag_complex_edge_collapser constructor from a proximity graph, cf. `Gudhi::compute_proximity_graph`. + /** \brief Inserts all edges given by a OneSkeletonGraph into a vector of + * `Flag_complex_edge_collapser::Filtered_edge`. + * OneSkeletonGraph must be a model of + * boost::EdgeListGraph + * and boost::PropertyGraph. + * + * The edge filtration value is accessible through the property tag + * edge_filtration_t. * - * @param[in] one_skeleton_graph The one skeleton graph. The graph must be in - * `Flag_complex_edge_collapser::Proximity_graph`. + * boost::graph_traits::vertex_descriptor + * must be Vertex_handle. + * boost::graph_traits::directed_category + * can be directed_tag (the fastest, the least RAM use), undirected_tag or even + * bidirected_tag. * - * The constructor is computing and filling a vector of `Flag_complex_edge_collapser::Filtered_edge` + * If an edge appears with multiplicity, the function will arbitrarily pick one representative to read the filtration + * value. + * + * `Gudhi::Proximity_graph` is a good candidate for OneSkeletonGraph. */ - Flag_complex_edge_collapser(const Proximity_graph& one_skeleton_graph) { + template + Flag_complex_edge_collapser(const OneSkeletonGraph& one_skeleton_graph) { // Insert all edges for (auto edge_it = boost::edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index e45dc339..3733ba13 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -49,7 +49,7 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F } std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_edge_collapser edge_collapser(filtered_edges); + Flag_complex_edge_collapser edge_collapser(filtered_edges.begin(), filtered_edges.end()); Filtered_edge_list collapse_edges; edge_collapser.process_edges( [&collapse_edges](std::pair edge, Filtration_value filtration) { @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { {1., 1.} }; Filtration_value threshold = std::numeric_limits::infinity(); - using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; + using Proximity_graph = Gudhi::Proximity_graph; Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(point_cloud, threshold, Gudhi::Euclidean_distance()); diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index ae9ff32b..378d64e6 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -21,7 +21,7 @@ using Filtration_value = Simplex_tree::Filtration_value; using Vertex_handle = Simplex_tree::Vertex_handle; using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; -using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; +using Proximity_graph = Gudhi::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index d2d31013..fcf858a0 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -29,7 +29,7 @@ using Point = std::vector; using Vector_of_points = std::vector; using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; -using Proximity_graph = Flag_complex_edge_collapser::Proximity_graph; +using Proximity_graph = Gudhi::Proximity_graph; using Field_Zp = Gudhi::persistent_cohomology::Field_Zp; using Persistent_cohomology = Gudhi::persistent_cohomology::Persistent_cohomology; -- cgit v1.2.3 From 08307b231e8fe2b044ade409b924f56b3eb7ebfe Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Jun 2020 14:35:44 +0200 Subject: Code review: replace push_back with emplace_back --- .../example/edge_collapse_basic_example.cpp | 2 +- .../example/edge_collapse_conserve_persistence.cpp | 6 +++--- .../include/gudhi/Flag_complex_edge_collapser.h | 8 ++++---- src/Collapse/test/collapse_unit_test.cpp | 22 +++++++++++----------- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index 17ed04a2..ac21e96f 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -32,7 +32,7 @@ int main() { // Retrieve collapse edges from the output iterator edge_collapser.process_edges( [&remaining_edges](std::pair edge, Filtration_value filtration) { - remaining_edges.push_back({edge, filtration}); + remaining_edges.emplace_back(Filtered_edge(edge, filtration)); }); for (Filtered_edge filtered_edge_from_collapse : remaining_edges) { diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index b28af456..8e03fa86 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -71,9 +71,9 @@ std::vector get_persistence_pairs(Simplex_tree& st, int ambien auto persistent_pairs = pcoh.get_persistent_pairs(); std::sort(std::begin(persistent_pairs), std::end(persistent_pairs), cmp); for (auto pair : persistent_pairs) { - ppairs.push_back({st.dimension(get<0>(pair)), - st.filtration(get<0>(pair)), - st.filtration(get<1>(pair)) }); + ppairs.emplace_back(Persistence_pair(st.dimension(get<0>(pair)), + st.filtration(get<0>(pair)), + st.filtration(get<1>(pair)) )); } return ppairs; } diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 6afeaefc..02460efb 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -218,7 +218,7 @@ class Flag_complex_edge_collapser { if ((closed && rw_u == rw_v) || (ei = it.value()) <= current_backward || critical_edge_indicator_[ei]) { - neighbors.push_back(rw_v); + neighbors.emplace_back(rw_v); #ifdef DEBUG_TRACES std::cout << row_to_vertex_[rw_v] << ", " ; #endif // DEBUG_TRACES @@ -254,7 +254,7 @@ class Flag_complex_edge_collapser { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge // Must be done after reading its size() - row_to_vertex_.push_back(vertex); + row_to_vertex_.emplace_back(vertex); } return result.first->second; } @@ -319,7 +319,7 @@ class Flag_complex_edge_collapser { auto edge = *(edge_it.first); Vertex_handle u = source(edge, one_skeleton_graph); Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.push_back({{u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)}); + f_edge_vector_.emplace_back(Filtered_edge({u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); } } @@ -353,7 +353,7 @@ class Flag_complex_edge_collapser { IEdge ie = insert_new_edge(u, v, endIdx); iedge_to_index_map_.emplace(ie, endIdx); - critical_edge_indicator_.push_back(false); + critical_edge_indicator_.emplace_back(false); if (!edge_is_dominated(edge)) { critical_edge_indicator_[endIdx] = true; diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 6ca49299..a6d3ca1c 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -54,7 +54,7 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F edge_collapser.process_edges( [&remaining_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - remaining_edges.push_back({edge, filtration}); + remaining_edges.emplace_back(Filtered_edge(edge, filtration)); }); std::cout << "AFTER COLLAPSE - Total number of edges: " << remaining_edges.size() << std::endl; BOOST_CHECK(remaining_edges.size() <= filtered_edges.size()); @@ -96,8 +96,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| // o---o // 0 3 - edges.push_back({{0, 2}, 2.}); - edges.push_back({{1, 3}, 2.}); + edges.emplace_back(Filtered_edge({0, 2}, 2.)); + edges.emplace_back(Filtered_edge({1, 3}, 2.)); trace_and_check_collapse(edges, {{{1, 3}, 2.}}); // 1 2 4 @@ -107,9 +107,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| | // o---o---o // 0 3 5 - edges.push_back({{2, 4}, 3.}); - edges.push_back({{4, 5}, 3.}); - edges.push_back({{5, 3}, 3.}); + edges.emplace_back(Filtered_edge({2, 4}, 3.)); + edges.emplace_back(Filtered_edge({4, 5}, 3.)); + edges.emplace_back(Filtered_edge({5, 3}, 3.)); trace_and_check_collapse(edges, {{{1, 3}, 2.}}); // 1 2 4 @@ -119,8 +119,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.push_back({{2, 5}, 4.}); - edges.push_back({{4, 3}, 4.}); + edges.emplace_back(Filtered_edge({2, 5}, 4.)); + edges.emplace_back(Filtered_edge({4, 3}, 4.)); trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}}); // 1 2 4 @@ -130,8 +130,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.push_back({{1, 5}, 5.}); - edges.push_back({{0, 4}, 5.}); + edges.emplace_back(Filtered_edge({1, 5}, 5.)); + edges.emplace_back(Filtered_edge({0, 4}, 5.)); trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}, {{0, 4}, 5.}}); } @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { edge_collapser.process_edges( [&remaining_edges](std::pair edge, Filtration_value filtration) { std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - remaining_edges.push_back({edge, filtration}); + remaining_edges.emplace_back(Filtered_edge(edge, filtration)); }); BOOST_CHECK(remaining_edges.size() == 5); -- cgit v1.2.3 From 7e92bb3aeddd0cdd32a867ca7a827ed3ed93dbb4 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Jun 2020 22:56:43 +0200 Subject: Code review: Use a flat (u, v, filt) instead of (pair(u, v), filt) --- .../example/edge_collapse_basic_example.cpp | 22 ++++--- .../example/edge_collapse_conserve_persistence.cpp | 4 +- .../include/gudhi/Flag_complex_edge_collapser.h | 49 +++++++-------- src/Collapse/test/collapse_unit_test.cpp | 70 ++++++++++++---------- ...tance_matrix_edge_collapse_rips_persistence.cpp | 7 +-- .../point_cloud_edge_collapse_rips_persistence.cpp | 7 +-- 6 files changed, 74 insertions(+), 85 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index ac21e96f..d374fef2 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -10,7 +10,6 @@ int main() { using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; using Filtered_edge = Flag_complex_edge_collapser::Filtered_edge; using Filtered_edge_list = std::vector; - using Edge = Flag_complex_edge_collapser::Edge; // 1 2 // o---o @@ -19,26 +18,25 @@ int main() { // |/ \| // o---o // 0 3 - Filtered_edge_list graph = {{{0, 1}, 1.}, - {{1, 2}, 1.}, - {{2, 3}, 1.}, - {{3, 0}, 1.}, - {{0, 2}, 2.}, - {{1, 3}, 2.}}; + Filtered_edge_list graph = {{0, 1, 1.}, + {1, 2, 1.}, + {2, 3, 1.}, + {3, 0, 1.}, + {0, 2, 2.}, + {1, 3, 2.}}; Flag_complex_edge_collapser edge_collapser(graph.begin(), graph.end()); Filtered_edge_list remaining_edges; // Retrieve collapse edges from the output iterator edge_collapser.process_edges( - [&remaining_edges](std::pair edge, Filtration_value filtration) { - remaining_edges.emplace_back(Filtered_edge(edge, filtration)); + [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { + remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); }); for (Filtered_edge filtered_edge_from_collapse : remaining_edges) { - Edge edge_from_collapse = std::get<0>(filtered_edge_from_collapse); - std::cout << "fn[" << std::get<0>(edge_from_collapse) << ", " << std::get<1>(edge_from_collapse) << "] = " - << std::get<1>(filtered_edge_from_collapse) << std::endl; + std::cout << "fn[" << std::get<0>(filtered_edge_from_collapse) << ", " << std::get<1>(filtered_edge_from_collapse) + << "] = " << std::get<2>(filtered_edge_from_collapse) << std::endl; } return 0; diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index 0a5d9241..69755fc9 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -117,9 +117,9 @@ int main(int argc, char* argv[]) { stree_from_collapse.insert_simplex({vertex}, 0.); } edge_collapser.process_edges( - [&stree_from_collapse](const std::vector& edge, Filtration_value filtration) { + [&stree_from_collapse](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { // insert the edge - stree_from_collapse.insert_simplex(edge, filtration); + stree_from_collapse.insert_simplex({u, v}, filtration); }); std::vector persistence_intervals_from_collapse = get_persistence_intervals(stree_from_collapse, ambient_dim); diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 02460efb..9fa2d7c9 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -58,10 +58,6 @@ class Flag_complex_edge_collapser { using Vertex_handle = Vertex; /** \brief Re-define Filtration as Filtration_value type to ease the interface with `Gudhi::Proximity_graph`. */ using Filtration_value = Filtration; - /** \brief This is an ordered pair, An edge is stored with convention of the first element being the smaller i.e - * {2,3} not {3,2}. However this is at the level of row indices on actual vertex lables. - */ - using Edge = std::pair; private: // internal numbering of vertices and edges @@ -79,7 +75,7 @@ class Flag_complex_edge_collapser { public: /** \brief Filtered_edge is a type to store an edge with its filtration value. */ - using Filtered_edge = std::pair; + using Filtered_edge = std::tuple; private: // Map from row index to its vertex handle @@ -105,12 +101,9 @@ class Flag_complex_edge_collapser { // The input, a vector of filtered edges. std::vector f_edge_vector_; - // Edge e is the actual edge (u,v), with Vertex_handle u and v, not IVertex. - bool edge_is_dominated(const Edge& edge) const + // Edge is the actual edge (u,v), with Vertex_handle u and v, not IVertex. + bool edge_is_dominated(Vertex_handle u, Vertex_handle v) const { - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - const IVertex rw_u = vertex_to_row_.at(u); const IVertex rw_v = vertex_to_row_.at(v); #ifdef DEBUG_TRACES @@ -141,13 +134,12 @@ class Flag_complex_edge_collapser { std::set three_clique_indices(Edge_index crit) { std::set edge_indices; - Edge edge = std::get<0>(f_edge_vector_[crit]); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); + Vertex_handle u = std::get<0>(f_edge_vector_[crit]); + Vertex_handle v = std::get<1>(f_edge_vector_[crit]); #ifdef DEBUG_TRACES std::cout << "The current critical edge to re-check criticality with filt value is : f {" << u << "," << v - << "} = " << std::get<1>(f_edge_vector_[crit]) << std::endl; + << "} = " << std::get<2>(f_edge_vector_[crit]) << std::endl; #endif // DEBUG_TRACES auto rw_u = vertex_to_row_[u]; auto rw_v = vertex_to_row_[v]; @@ -174,17 +166,16 @@ class Flag_complex_edge_collapser { // Cannot use boost::adaptors::reverse in such dynamic cases apparently for (auto it = effected_indices.rbegin(); it != effected_indices.rend(); ++it) { current_backward = *it; - Edge edge = std::get<0>(f_edge_vector_[current_backward]); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); + Vertex_handle u = std::get<0>(f_edge_vector_[current_backward]); + Vertex_handle v = std::get<1>(f_edge_vector_[current_backward]); // If current_backward is not critical so it should be processed, otherwise it stays in the graph if (!critical_edge_indicator_[current_backward]) { - if (!edge_is_dominated(edge)) { + if (!edge_is_dominated(u, v)) { #ifdef DEBUG_TRACES std::cout << "The curent index became critical " << current_backward << std::endl; #endif // DEBUG_TRACES critical_edge_indicator_[current_backward] = true; - filtered_edge_output({u, v}, filt); + filtered_edge_output(u, v, filt); std::set inner_effected_indcs = three_clique_indices(current_backward); for (auto inr_idx : inner_effected_indcs) { if(inr_idx < current_backward) // && !critical_edge_indicator_[inr_idx] @@ -319,21 +310,22 @@ class Flag_complex_edge_collapser { auto edge = *(edge_it.first); Vertex_handle u = source(edge, one_skeleton_graph); Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.emplace_back(Filtered_edge({u, v}, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); + f_edge_vector_.emplace_back(Filtered_edge(u, v, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); } } /** \brief Performs edge collapse in a increasing sequence of the filtration value. * - * \tparam FilteredEdgeOutput is a functor that furnishes `({Vertex_handle u, Vertex_handle v}, Filtration_value f)` - * that will get called on the output edges, in non-decreasing order of filtration. + * \tparam filtered_edge_output is a functor that is called on the output edges, in non-decreasing order of + * filtration, as filtered_edge_output(u, v, f) where u and v are Vertex_handle representing the extremities of the + * edge, and f is its new Filtration_value. */ template void process_edges(FilteredEdgeOutput filtered_edge_output) { // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { - return (get<1>(edge_a) < get<1>(edge_b)); + return (get<2>(edge_a) < get<2>(edge_b)); }; #ifdef GUDHI_USE_TBB @@ -344,10 +336,9 @@ class Flag_complex_edge_collapser { for (Edge_index endIdx = 0; endIdx < f_edge_vector_.size(); endIdx++) { Filtered_edge fec = f_edge_vector_[endIdx]; - Edge edge = std::get<0>(fec); - Vertex_handle u = std::get<0>(edge); - Vertex_handle v = std::get<1>(edge); - Filtration_value filt = std::get<1>(fec); + Vertex_handle u = std::get<0>(fec); + Vertex_handle v = std::get<1>(fec); + Filtration_value filt = std::get<2>(fec); // Inserts the edge in the sparse matrix to update the graph (G_i) IEdge ie = insert_new_edge(u, v, endIdx); @@ -355,9 +346,9 @@ class Flag_complex_edge_collapser { iedge_to_index_map_.emplace(ie, endIdx); critical_edge_indicator_.emplace_back(false); - if (!edge_is_dominated(edge)) { + if (!edge_is_dominated(u, v)) { critical_edge_indicator_[endIdx] = true; - filtered_edge_output({u, v}, filt); + filtered_edge_output(u, v, filt); if (endIdx > 1) set_edge_critical(endIdx, filt, filtered_edge_output); } diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index a6d3ca1c..67f1a732 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -44,33 +44,31 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F std::cout << "BEFORE COLLAPSE - Total number of edges: " << filtered_edges.size() << std::endl; BOOST_CHECK(filtered_edges.size() > 0); for (auto filtered_edge : filtered_edges) { - auto edge = std::get<0>(filtered_edge); - std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << std::get<1>(filtered_edge) << std::endl; + std::cout << "f[" << std::get<0>(filtered_edge) << ", " << std::get<1>(filtered_edge) << "] = " + << std::get<2>(filtered_edge) << std::endl; } std::cout << "COLLAPSE - keep edges: " << std::endl; Flag_complex_edge_collapser edge_collapser(filtered_edges.begin(), filtered_edges.end()); Filtered_edge_list remaining_edges; edge_collapser.process_edges( - [&remaining_edges](std::pair edge, Filtration_value filtration) { - std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - remaining_edges.emplace_back(Filtered_edge(edge, filtration)); + [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { + std::cout << "f[" << u << ", " << v << "] = " << filtration << std::endl; + remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); }); std::cout << "AFTER COLLAPSE - Total number of edges: " << remaining_edges.size() << std::endl; BOOST_CHECK(remaining_edges.size() <= filtered_edges.size()); for (auto filtered_edge_from_collapse : remaining_edges) { - auto edge_from_collapse = std::get<0>(filtered_edge_from_collapse); - std::cout << "f[" << std::get<0>(edge_from_collapse) << ", " << std::get<1>(edge_from_collapse) << "] = " - << std::get<1>(filtered_edge_from_collapse) << std::endl; + std::cout << "f[" << std::get<0>(filtered_edge_from_collapse) << ", " << std::get<1>(filtered_edge_from_collapse) + << "] = " << std::get<2>(filtered_edge_from_collapse) << std::endl; // Check each edge from collapse is in the input BOOST_CHECK(find_edge_in_list(filtered_edge_from_collapse, filtered_edges)); } std::cout << "CHECK COLLAPSE - Total number of removed edges: " << removed_edges.size() << std::endl; for (auto removed_filtered_edge : removed_edges) { - auto removed_edge = std::get<0>(removed_filtered_edge); - std::cout << "f[" << std::get<0>(removed_edge) << ", " << std::get<1>(removed_edge) << "] = " - << std::get<1>(removed_filtered_edge) << std::endl; + std::cout << "f[" << std::get<0>(removed_filtered_edge) << ", " << std::get<1>(removed_filtered_edge) << "] = " + << std::get<2>(removed_filtered_edge) << std::endl; // Check each removed edge from collapse is in the input BOOST_CHECK(!find_edge_in_list(removed_filtered_edge, remaining_edges)); } @@ -86,7 +84,10 @@ BOOST_AUTO_TEST_CASE(collapse) { // | | // o---o // 0 3 - Filtered_edge_list edges {{{0, 1}, 1.}, {{1, 2}, 1.}, {{2, 3}, 1.}, {{3, 0}, 1.}}; + Filtered_edge_list edges {{0, 1, 1.}, + {1, 2, 1.}, + {2, 3, 1.}, + {3, 0, 1.}}; trace_and_check_collapse(edges, {}); // 1 2 @@ -96,9 +97,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| // o---o // 0 3 - edges.emplace_back(Filtered_edge({0, 2}, 2.)); - edges.emplace_back(Filtered_edge({1, 3}, 2.)); - trace_and_check_collapse(edges, {{{1, 3}, 2.}}); + edges.emplace_back(Filtered_edge(0, 2, 2.)); + edges.emplace_back(Filtered_edge(1, 3, 2.)); + trace_and_check_collapse(edges, {{1, 3, 2.}}); // 1 2 4 // o---o---o @@ -107,10 +108,10 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| | // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge({2, 4}, 3.)); - edges.emplace_back(Filtered_edge({4, 5}, 3.)); - edges.emplace_back(Filtered_edge({5, 3}, 3.)); - trace_and_check_collapse(edges, {{{1, 3}, 2.}}); + edges.emplace_back(Filtered_edge(2, 4, 3.)); + edges.emplace_back(Filtered_edge(4, 5, 3.)); + edges.emplace_back(Filtered_edge(5, 3, 3.)); + trace_and_check_collapse(edges, {{1, 3, 2.}}); // 1 2 4 // o---o---o @@ -119,9 +120,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge({2, 5}, 4.)); - edges.emplace_back(Filtered_edge({4, 3}, 4.)); - trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}}); + edges.emplace_back(Filtered_edge(2, 5, 4.)); + edges.emplace_back(Filtered_edge(4, 3, 4.)); + trace_and_check_collapse(edges, {{1, 3, 2.}, {4, 3, 4.}}); // 1 2 4 // o---o---o @@ -130,9 +131,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge({1, 5}, 5.)); - edges.emplace_back(Filtered_edge({0, 4}, 5.)); - trace_and_check_collapse(edges, {{{1, 3}, 2.}, {{4, 3}, 4.}, {{0, 4}, 5.}}); + edges.emplace_back(Filtered_edge(1, 5, 5.)); + edges.emplace_back(Filtered_edge(0, 4, 5.)); + trace_and_check_collapse(edges, {{1, 3, 2.}, {4, 3, 4.}, {0, 4, 5.}}); } BOOST_AUTO_TEST_CASE(collapse_from_array) { @@ -144,8 +145,13 @@ BOOST_AUTO_TEST_CASE(collapse_from_array) { // |/ \| // o---o // 0 3 - std::array f_edge_array = {{{{0, 1}, 1.}, {{1, 2}, 1.}, {{2, 3}, 1.}, {{3, 0}, 1.}, {{0, 2}, 2.}, {{1, 3}, 2.}}}; - trace_and_check_collapse(f_edge_array, {{{1, 3}, 2.}}); + std::array f_edge_array = {{{0, 1, 1.}, + {1, 2, 1.}, + {2, 3, 1.}, + {3, 0, 1.}, + {0, 2, 2.}, + {1, 3, 2.}}}; + trace_and_check_collapse(f_edge_array, {{1, 3, 2.}}); } @@ -171,9 +177,9 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { Flag_complex_edge_collapser edge_collapser(proximity_graph); Filtered_edge_list remaining_edges; edge_collapser.process_edges( - [&remaining_edges](std::pair edge, Filtration_value filtration) { - std::cout << "f[" << std::get<0>(edge) << ", " << std::get<1>(edge) << "] = " << filtration << std::endl; - remaining_edges.emplace_back(Filtered_edge(edge, filtration)); + [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { + std::cout << "f[" << u << ", " << v << "] = " << filtration << std::endl; + remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); }); BOOST_CHECK(remaining_edges.size() == 5); @@ -181,9 +187,9 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { std::size_t filtration_is_diagonal_length_nb = 0; float epsilon = std::numeric_limits::epsilon(); for (auto filtered_edge : remaining_edges) { - if (std::get<1>(filtered_edge) == 1.) + if (std::get<2>(filtered_edge) == 1.) filtration_is_edge_length_nb++; - if (std::fabs(std::get<1>(filtered_edge) - std::sqrt(2.)) <= epsilon) + if (std::fabs(std::get<2>(filtered_edge) - std::sqrt(2.)) <= epsilon) filtration_is_diagonal_length_nb++; } BOOST_CHECK(filtration_is_edge_length_nb == 4); diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 378d64e6..88cd7b54 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -98,12 +98,9 @@ int main(int argc, char* argv[]) { stree.insert_simplex({vertex}, 0.); } edge_collapser.process_edges( - [&stree](std::vector edge, Filtration_value filtration) { - // insert the 2 vertices with a 0. filtration value just like a Rips - stree.insert_simplex({edge[0]}, 0.); - stree.insert_simplex({edge[1]}, 0.); + [&stree](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { // insert the edge - stree.insert_simplex(edge, filtration); + stree.insert_simplex({u, v}, filtration); }); stree.expansion(dim_max); diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index fcf858a0..69e83597 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -85,12 +85,9 @@ int main(int argc, char* argv[]) { stree.insert_simplex({vertex}, 0.); } edge_collapser.process_edges( - [&stree](const std::vector& edge, Filtration_value filtration) { - // insert the 2 vertices with a 0. filtration value just like a Rips - stree.insert_simplex({edge[0]}, 0.); - stree.insert_simplex({edge[1]}, 0.); + [&stree](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { // insert the edge - stree.insert_simplex(edge, filtration); + stree.insert_simplex({u, v}, filtration); }); stree.expansion(dim_max); -- cgit v1.2.3 From 716085ac81cd90e3a0f51d2ad416e50b6a5e6fe7 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 18 Jun 2020 23:16:12 +0200 Subject: Code review: modify last element with final aka. std::end --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 9fa2d7c9..220330a7 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -269,11 +269,11 @@ class Flag_complex_edge_collapser { public: /** \brief Flag_complex_edge_collapser constructor from a range of filtered edges. * - * @param[in] begin Iterator on the first element of a filtered edges range. Filtered edges must be in - * `Flag_complex_edge_collapser::Filtered_edge`. + * @param[in] begin Iterator on the first element of a filtered edges range, aka. `std::begin`. Filtered edges must + * be in `Flag_complex_edge_collapser::Filtered_edge`. * - * @param[in] end Iterator on the last element of a filtered edges range. Filtered edges must be in - * `Flag_complex_edge_collapser::Filtered_edge`. + * @param[in] end Iterator on the final element of a filtered edges range, aka. `std::end`. Filtered edges must be + * in `Flag_complex_edge_collapser::Filtered_edge`. * * There is no need the range to be sorted, as it will be performed in * `Flag_complex_edge_collapser::process_edges`. -- cgit v1.2.3 From 1fdaa406b6b0b85e409bd97090098ed5846c078c Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 22 Jun 2020 23:17:58 +0200 Subject: Don't explicitly copy the neighbors to a vector each time --- .../include/gudhi/Flag_complex_edge_collapser.h | 78 ++++++++++++++-------- 1 file changed, 49 insertions(+), 29 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 220330a7..09986d08 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -17,6 +17,7 @@ #include #include +#include #include @@ -70,6 +71,48 @@ class Flag_complex_edge_collapser { using Sparse_vector = Eigen::SparseVector; using Sparse_row_matrix = std::vector; + // Range of neighbors of a vertex + template + struct Neighbours { + class iterator : public boost::iterator_facade + { + public: + iterator():ptr(nullptr){} + iterator(Neighbours const*p):ptr(p){find_valid();} + private: + friend class boost::iterator_core_access; + Neighbours const*ptr; + void increment(){ + ++ptr->it; + find_valid(); + } + void find_valid(){ + auto& it = ptr->it; + do { + if(!it) { ptr=nullptr; break; } + if(IVertex(it.index()) == ptr->u) { + if(closed) break; + else continue; + } + Edge_index e = it.value(); + if(e <= ptr->ec->current_backward || ptr->ec->critical_edge_indicator_[e]) break; + } while(++it, true); + } + bool equal(iterator const& other) const { return ptr == other.ptr; } + IVertex dereference() const { return ptr->it.index(); } + }; + typedef iterator const_iterator; + mutable typename Sparse_vector::InnerIterator it; + Flag_complex_edge_collapser const*ec; + IVertex u; + iterator begin() const { return this; } + iterator end() const { return {}; } + explicit Neighbours(Flag_complex_edge_collapser const*p,IVertex u):it(p->sparse_row_adjacency_matrix_[u]),ec(p),u(u){} + }; + // A range of row indices using IVertex_vector = std::vector; @@ -121,7 +164,7 @@ class Flag_complex_edge_collapser { return true; else for (auto rw_c : common_neighbours) { - auto neighbours_c = neighbours_row_index(rw_c, true); + auto neighbours_c = neighbours_row_index(rw_c); // If neighbours_c contains the common neighbours. if (std::includes(neighbours_c.begin(), neighbours_c.end(), common_neighbours.begin(), common_neighbours.end())) @@ -193,41 +236,18 @@ class Flag_complex_edge_collapser { } // Returns list of neighbors of a particular vertex. - IVertex_vector neighbours_row_index(IVertex rw_u, bool closed) const + template + auto neighbours_row_index(IVertex rw_u) const { - IVertex_vector neighbors; - neighbors.reserve(sparse_row_adjacency_matrix_[rw_u].nonZeros()); // too much, but who cares -#ifdef DEBUG_TRACES - std::cout << "The neighbours of the vertex: " << row_to_vertex_[rw_u] << " are. " << std::endl; -#endif // DEBUG_TRACES - // Iterate over the neighbors - for (typename Sparse_vector::InnerIterator it(sparse_row_adjacency_matrix_[rw_u]); it; ++it) { - IVertex rw_v = it.index(); - if (!closed && rw_u == rw_v) continue; - Edge_index ei; - // If the vertex v is not dominated and the edge {u,v} is still in the matrix - if ((closed && rw_u == rw_v) || - (ei = it.value()) <= current_backward || - critical_edge_indicator_[ei]) { - neighbors.emplace_back(rw_v); -#ifdef DEBUG_TRACES - std::cout << row_to_vertex_[rw_v] << ", " ; -#endif // DEBUG_TRACES - } - } -#ifdef DEBUG_TRACES - std::cout << std::endl; -#endif // DEBUG_TRACES - return neighbors; + return Neighbours(this, rw_u); } // Returns the list of open neighbours of the edge :{u,v}. IVertex_vector open_common_neighbours_row_index(IVertex rw_u, IVertex rw_v) const { - IVertex_vector non_zero_indices_u = neighbours_row_index(rw_u, false); - IVertex_vector non_zero_indices_v = neighbours_row_index(rw_v, false); + auto non_zero_indices_u = neighbours_row_index(rw_u); + auto non_zero_indices_v = neighbours_row_index(rw_v); IVertex_vector common; - common.reserve(std::min(non_zero_indices_u.size(), non_zero_indices_v.size())); std::set_intersection(non_zero_indices_u.begin(), non_zero_indices_u.end(), non_zero_indices_v.begin(), non_zero_indices_v.end(), std::back_inserter(common)); -- cgit v1.2.3 From e4e55054945ec25bba613bf9051b9dde0b09357e Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Tue, 23 Jun 2020 00:00:58 +0200 Subject: Fix uses of emplace_back --- .../example/edge_collapse_basic_example.cpp | 2 +- .../example/edge_collapse_conserve_persistence.cpp | 6 +++--- .../include/gudhi/Flag_complex_edge_collapser.h | 6 +++--- src/Collapse/test/collapse_unit_test.cpp | 24 +++++++++++----------- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index d374fef2..8e7ca3b1 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -31,7 +31,7 @@ int main() { // Retrieve collapse edges from the output iterator edge_collapser.process_edges( [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { - remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); + remaining_edges.emplace_back(u, v, filtration); }); for (Filtered_edge filtered_edge_from_collapse : remaining_edges) { diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index 69755fc9..d78a4d54 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -68,9 +68,9 @@ std::vector get_persistence_intervals(Simplex_tree& st, in auto persistent_pairs = pcoh.get_persistent_pairs(); std::sort(std::begin(persistent_pairs), std::end(persistent_pairs), cmp); for (auto pair : persistent_pairs) { - persistence_intervals.emplace_back(Persistence_interval(st.dimension(get<0>(pair)), - st.filtration(get<0>(pair)), - st.filtration(get<1>(pair)) )); + persistence_intervals.emplace_back(st.dimension(get<0>(pair)), + st.filtration(get<0>(pair)), + st.filtration(get<1>(pair))); } return persistence_intervals; } diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 09986d08..29850382 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -265,7 +265,7 @@ class Flag_complex_edge_collapser { // Initializing the diagonal element of the adjency matrix corresponding to rw_b. sparse_row_adjacency_matrix_[n].insert(n) = -1; // not an edge // Must be done after reading its size() - row_to_vertex_.emplace_back(vertex); + row_to_vertex_.push_back(vertex); } return result.first->second; } @@ -330,7 +330,7 @@ class Flag_complex_edge_collapser { auto edge = *(edge_it.first); Vertex_handle u = source(edge, one_skeleton_graph); Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.emplace_back(Filtered_edge(u, v, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); + f_edge_vector_.emplace_back(u, v, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)); } } @@ -364,7 +364,7 @@ class Flag_complex_edge_collapser { IEdge ie = insert_new_edge(u, v, endIdx); iedge_to_index_map_.emplace(ie, endIdx); - critical_edge_indicator_.emplace_back(false); + critical_edge_indicator_.push_back(false); if (!edge_is_dominated(u, v)) { critical_edge_indicator_[endIdx] = true; diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 67f1a732..108f77e4 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -54,7 +54,7 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F edge_collapser.process_edges( [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { std::cout << "f[" << u << ", " << v << "] = " << filtration << std::endl; - remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); + remaining_edges.emplace_back(u, v, filtration); }); std::cout << "AFTER COLLAPSE - Total number of edges: " << remaining_edges.size() << std::endl; BOOST_CHECK(remaining_edges.size() <= filtered_edges.size()); @@ -97,8 +97,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| // o---o // 0 3 - edges.emplace_back(Filtered_edge(0, 2, 2.)); - edges.emplace_back(Filtered_edge(1, 3, 2.)); + edges.emplace_back(0, 2, 2.); + edges.emplace_back(1, 3, 2.); trace_and_check_collapse(edges, {{1, 3, 2.}}); // 1 2 4 @@ -108,9 +108,9 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \| | // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge(2, 4, 3.)); - edges.emplace_back(Filtered_edge(4, 5, 3.)); - edges.emplace_back(Filtered_edge(5, 3, 3.)); + edges.emplace_back(2, 4, 3.); + edges.emplace_back(4, 5, 3.); + edges.emplace_back(5, 3, 3.); trace_and_check_collapse(edges, {{1, 3, 2.}}); // 1 2 4 @@ -120,8 +120,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge(2, 5, 4.)); - edges.emplace_back(Filtered_edge(4, 3, 4.)); + edges.emplace_back(2, 5, 4.); + edges.emplace_back(4, 3, 4.); trace_and_check_collapse(edges, {{1, 3, 2.}, {4, 3, 4.}}); // 1 2 4 @@ -131,8 +131,8 @@ BOOST_AUTO_TEST_CASE(collapse) { // |/ \|/ \| // o---o---o // 0 3 5 - edges.emplace_back(Filtered_edge(1, 5, 5.)); - edges.emplace_back(Filtered_edge(0, 4, 5.)); + edges.emplace_back(1, 5, 5.); + edges.emplace_back(0, 4, 5.); trace_and_check_collapse(edges, {{1, 3, 2.}, {4, 3, 4.}, {0, 4, 5.}}); } @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { edge_collapser.process_edges( [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { std::cout << "f[" << u << ", " << v << "] = " << filtration << std::endl; - remaining_edges.emplace_back(Filtered_edge(u, v, filtration)); + remaining_edges.emplace_back(u, v, filtration); }); BOOST_CHECK(remaining_edges.size() == 5); @@ -194,4 +194,4 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { } BOOST_CHECK(filtration_is_edge_length_nb == 4); BOOST_CHECK(filtration_is_diagonal_length_nb == 1); -} \ No newline at end of file +} -- cgit v1.2.3 From ddd12a6caab2040d7e8e6573c71f9da4a90bb346 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 25 Jun 2020 11:11:22 +0200 Subject: Code review: remove 'boost::' in front of edges and get method --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 220330a7..331a82f9 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -305,12 +305,12 @@ class Flag_complex_edge_collapser { template Flag_complex_edge_collapser(const OneSkeletonGraph& one_skeleton_graph) { // Insert all edges - for (auto edge_it = boost::edges(one_skeleton_graph); + for (auto edge_it = edges(one_skeleton_graph); edge_it.first != edge_it.second; ++edge_it.first) { auto edge = *(edge_it.first); Vertex_handle u = source(edge, one_skeleton_graph); Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.emplace_back(Filtered_edge(u, v, boost::get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); + f_edge_vector_.emplace_back(Filtered_edge(u, v, get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge))); } } -- cgit v1.2.3 From 12ff6eda212250a55492338b2a53ef774dd1829b Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 25 Jun 2020 11:24:05 +0200 Subject: Doc review: link on recent boost doc --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index bf23d8f8..61932427 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -305,8 +305,8 @@ class Flag_complex_edge_collapser { /** \brief Inserts all edges given by a OneSkeletonGraph into a vector of * `Flag_complex_edge_collapser::Filtered_edge`. * OneSkeletonGraph must be a model of - * boost::EdgeListGraph - * and boost::PropertyGraph. + * boost::EdgeListGraph + * and boost::PropertyGraph. * * The edge filtration value is accessible through the property tag * edge_filtration_t. -- cgit v1.2.3 From 2610ce8092a3935e228065884bcbd70d910b40cd Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 25 Jun 2020 11:27:20 +0200 Subject: Doc review: no duplicated edges --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 61932427..44190997 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -317,8 +317,7 @@ class Flag_complex_edge_collapser { * can be directed_tag (the fastest, the least RAM use), undirected_tag or even * bidirected_tag. * - * If an edge appears with multiplicity, the function will arbitrarily pick one representative to read the filtration - * value. + * It is required to have no duplicated edges in the graph. * * `Gudhi::Proximity_graph` is a good candidate for OneSkeletonGraph. */ -- cgit v1.2.3 From b522b330b10d11f0da640b8bba7ee689dea774d7 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Thu, 25 Jun 2020 17:10:36 +0200 Subject: Remove interface with boost graphs and use boost transform for data from graphs --- .../example/edge_collapse_basic_example.cpp | 2 +- .../example/edge_collapse_conserve_persistence.cpp | 10 ++++- .../include/gudhi/Flag_complex_edge_collapser.h | 46 +++------------------- src/Collapse/test/collapse_unit_test.cpp | 13 +++++- ...tance_matrix_edge_collapse_rips_persistence.cpp | 9 ++++- .../point_cloud_edge_collapse_rips_persistence.cpp | 9 ++++- 6 files changed, 43 insertions(+), 46 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index 8e7ca3b1..69ce329e 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -25,7 +25,7 @@ int main() { {0, 2, 2.}, {1, 3, 2.}}; - Flag_complex_edge_collapser edge_collapser(graph.begin(), graph.end()); + Flag_complex_edge_collapser edge_collapser(graph); Filtered_edge_list remaining_edges; // Retrieve collapse edges from the output iterator diff --git a/src/Collapse/example/edge_collapse_conserve_persistence.cpp b/src/Collapse/example/edge_collapse_conserve_persistence.cpp index d78a4d54..e6672d25 100644 --- a/src/Collapse/example/edge_collapse_conserve_persistence.cpp +++ b/src/Collapse/example/edge_collapse_conserve_persistence.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include // for std::pair #include #include @@ -109,7 +111,13 @@ int main(int argc, char* argv[]) { int ambient_dim = point_vector[0].size(); // ***** Simplex tree from a flag complex built after collapse ***** - Flag_complex_edge_collapser edge_collapser(proximity_graph); + Flag_complex_edge_collapser edge_collapser( + boost::adaptors::transform(edges(proximity_graph), [&](auto&&edge){ + return std::make_tuple(source(edge, proximity_graph), + target(edge, proximity_graph), + get(Gudhi::edge_filtration_t(), proximity_graph, edge)); + }) + ); Simplex_tree stree_from_collapse; for (Vertex_handle vertex = 0; static_cast(vertex) < point_vector.size(); vertex++) { diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 44190997..9cd57d7e 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -289,49 +289,15 @@ class Flag_complex_edge_collapser { public: /** \brief Flag_complex_edge_collapser constructor from a range of filtered edges. * - * @param[in] begin Iterator on the first element of a filtered edges range, aka. `std::begin`. Filtered edges must - * be in `Flag_complex_edge_collapser::Filtered_edge`. - * - * @param[in] end Iterator on the final element of a filtered edges range, aka. `std::end`. Filtered edges must be - * in `Flag_complex_edge_collapser::Filtered_edge`. - * - * There is no need the range to be sorted, as it will be performed in + * @param[in] edges Range of Filtered edges range.There is no need the range to be sorted, as it will be performed in * `Flag_complex_edge_collapser::process_edges`. - */ - template - Flag_complex_edge_collapser(Filtered_edge_iterator begin, Filtered_edge_iterator end) - : f_edge_vector_(begin, end) { } - - /** \brief Inserts all edges given by a OneSkeletonGraph into a vector of - * `Flag_complex_edge_collapser::Filtered_edge`. - * OneSkeletonGraph must be a model of - * boost::EdgeListGraph - * and boost::PropertyGraph. * - * The edge filtration value is accessible through the property tag - * edge_filtration_t. - * - * boost::graph_traits::vertex_descriptor - * must be Vertex_handle. - * boost::graph_traits::directed_category - * can be directed_tag (the fastest, the least RAM use), undirected_tag or even - * bidirected_tag. - * - * It is required to have no duplicated edges in the graph. - * - * `Gudhi::Proximity_graph` is a good candidate for OneSkeletonGraph. + * \tparam FilteredEdgeRange must be a range for which std::begin and std::end return iterators on a + * `Flag_complex_edge_collapser::Filtered_edge`. */ - template - Flag_complex_edge_collapser(const OneSkeletonGraph& one_skeleton_graph) { - // Insert all edges - for (auto edge_it = edges(one_skeleton_graph); - edge_it.first != edge_it.second; ++edge_it.first) { - auto edge = *(edge_it.first); - Vertex_handle u = source(edge, one_skeleton_graph); - Vertex_handle v = target(edge, one_skeleton_graph); - f_edge_vector_.emplace_back(u, v, get(Gudhi::edge_filtration_t(), one_skeleton_graph, edge)); - } - } + template + Flag_complex_edge_collapser(FilteredEdgeRange edges) + : f_edge_vector_(std::begin(edges), std::end(edges)) { } /** \brief Performs edge collapse in a increasing sequence of the filtration value. * diff --git a/src/Collapse/test/collapse_unit_test.cpp b/src/Collapse/test/collapse_unit_test.cpp index 108f77e4..b5ad09c5 100644 --- a/src/Collapse/test/collapse_unit_test.cpp +++ b/src/Collapse/test/collapse_unit_test.cpp @@ -13,6 +13,7 @@ #define BOOST_TEST_MODULE "collapse" #include #include +#include #include #include @@ -49,7 +50,7 @@ void trace_and_check_collapse(const Filtered_edge_range& filtered_edges, const F } std::cout << "COLLAPSE - keep edges: " << std::endl; - Flag_complex_edge_collapser edge_collapser(filtered_edges.begin(), filtered_edges.end()); + Flag_complex_edge_collapser edge_collapser(filtered_edges); Filtered_edge_list remaining_edges; edge_collapser.process_edges( [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { @@ -174,7 +175,15 @@ BOOST_AUTO_TEST_CASE(collapse_from_proximity_graph) { Proximity_graph proximity_graph = Gudhi::compute_proximity_graph(point_cloud, threshold, Gudhi::Euclidean_distance()); - Flag_complex_edge_collapser edge_collapser(proximity_graph); + + Flag_complex_edge_collapser edge_collapser( + boost::adaptors::transform(edges(proximity_graph), [&](auto&&edge){ + return std::make_tuple(source(edge, proximity_graph), + target(edge, proximity_graph), + get(Gudhi::edge_filtration_t(), proximity_graph, edge)); + }) + ); + Filtered_edge_list remaining_edges; edge_collapser.process_edges( [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { diff --git a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp index 88cd7b54..bd9c0152 100644 --- a/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/distance_matrix_edge_collapse_rips_persistence.cpp @@ -15,6 +15,7 @@ #include #include +#include using Simplex_tree = Gudhi::Simplex_tree; using Filtration_value = Simplex_tree::Filtration_value; @@ -90,7 +91,13 @@ int main(int argc, char* argv[]) { }); // Now we will perform filtered edge collapse to sparsify the edge list edge_t. - Flag_complex_edge_collapser edge_collapser(proximity_graph); + Flag_complex_edge_collapser edge_collapser( + boost::adaptors::transform(edges(proximity_graph), [&](auto&&edge){ + return std::make_tuple(source(edge, proximity_graph), + target(edge, proximity_graph), + get(Gudhi::edge_filtration_t(), proximity_graph, edge)); + }) + ); Simplex_tree stree; for (Vertex_handle vertex = 0; static_cast(vertex) < distances.size(); vertex++) { diff --git a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp index 69e83597..4e14d7a8 100644 --- a/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp +++ b/src/Collapse/utilities/point_cloud_edge_collapse_rips_persistence.cpp @@ -16,6 +16,7 @@ #include #include +#include #include // for std::pair #include @@ -77,7 +78,13 @@ int main(int argc, char* argv[]) { exit(-1); } - Flag_complex_edge_collapser edge_collapser(proximity_graph); + Flag_complex_edge_collapser edge_collapser( + boost::adaptors::transform(edges(proximity_graph), [&](auto&&edge){ + return std::make_tuple(source(edge, proximity_graph), + target(edge, proximity_graph), + get(Gudhi::edge_filtration_t(), proximity_graph, edge)); + }) + ); Simplex_tree stree; for (Vertex_handle vertex = 0; static_cast(vertex) < point_vector.size(); vertex++) { -- cgit v1.2.3 From 945c7a6ccd23abd0c854777eebda762dea450490 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Fri, 26 Jun 2020 12:08:32 +0200 Subject: Free function, doc and basic example --- src/Collapse/doc/intro_edge_collapse.h | 6 ++-- .../example/edge_collapse_basic_example.cpp | 15 +++----- .../include/gudhi/Flag_complex_edge_collapser.h | 40 ++++++++++++++++++---- 3 files changed, 40 insertions(+), 21 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/doc/intro_edge_collapse.h b/src/Collapse/doc/intro_edge_collapse.h index 2b272a9e..81edd79f 100644 --- a/src/Collapse/doc/intro_edge_collapse.h +++ b/src/Collapse/doc/intro_edge_collapse.h @@ -76,9 +76,9 @@ namespace collapse { * * \subsection edgecollapseexample Basic edge collapse * - * This example builds the `Flag_complex_edge_collapser` from a proximity graph represented as a list of - * `Flag_complex_edge_collapser::Filtered_edge`. - * Then it collapses edges and displays a new list of `Flag_complex_edge_collapser::Filtered_edge` (with less edges) + * This example calls `Gudhi::collapse::flag_complex_collapse_edges()` from a proximity graph represented as a list of + * `Filtered_edge`. + * Then it collapses edges and displays a new list of `Filtered_edge` (with less edges) * that will preserve the persistence homology computation. * * \include Collapse/edge_collapse_basic_example.cpp diff --git a/src/Collapse/example/edge_collapse_basic_example.cpp b/src/Collapse/example/edge_collapse_basic_example.cpp index 69ce329e..1b3dc1b5 100644 --- a/src/Collapse/example/edge_collapse_basic_example.cpp +++ b/src/Collapse/example/edge_collapse_basic_example.cpp @@ -2,13 +2,13 @@ #include #include +#include int main() { // Type definitions using Filtration_value = float; using Vertex_handle = short; - using Flag_complex_edge_collapser = Gudhi::collapse::Flag_complex_edge_collapser; - using Filtered_edge = Flag_complex_edge_collapser::Filtered_edge; + using Filtered_edge = std::tuple; using Filtered_edge_list = std::vector; // 1 2 @@ -25,16 +25,9 @@ int main() { {0, 2, 2.}, {1, 3, 2.}}; - Flag_complex_edge_collapser edge_collapser(graph); + auto remaining_edges = Gudhi::collapse::flag_complex_collapse_edges(graph); - Filtered_edge_list remaining_edges; - // Retrieve collapse edges from the output iterator - edge_collapser.process_edges( - [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { - remaining_edges.emplace_back(u, v, filtration); - }); - - for (Filtered_edge filtered_edge_from_collapse : remaining_edges) { + for (auto filtered_edge_from_collapse : remaining_edges) { std::cout << "fn[" << std::get<0>(filtered_edge_from_collapse) << ", " << std::get<1>(filtered_edge_from_collapse) << "] = " << std::get<2>(filtered_edge_from_collapse) << std::endl; } diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 9cd57d7e..981ec88d 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -12,11 +12,9 @@ #ifndef FLAG_COMPLEX_EDGE_COLLAPSER_H_ #define FLAG_COMPLEX_EDGE_COLLAPSER_H_ -#include #include #include -#include #include #include @@ -39,12 +37,11 @@ namespace Gudhi { namespace collapse { -/** +/** \private + * * \class Flag_complex_edge_collapser * \brief Flag complex sparse matrix data structure. * - * \ingroup collapse - * * \details * This class stores a Flag complex * in an Eigen sparse matrix. @@ -296,7 +293,7 @@ class Flag_complex_edge_collapser { * `Flag_complex_edge_collapser::Filtered_edge`. */ template - Flag_complex_edge_collapser(FilteredEdgeRange edges) + Flag_complex_edge_collapser(const FilteredEdgeRange& edges) : f_edge_vector_(std::begin(edges), std::end(edges)) { } /** \brief Performs edge collapse in a increasing sequence of the filtration value. @@ -310,7 +307,7 @@ class Flag_complex_edge_collapser { // Sort edges auto sort_by_filtration = [](const Filtered_edge& edge_a, const Filtered_edge& edge_b) -> bool { - return (get<2>(edge_a) < get<2>(edge_b)); + return (std::get<2>(edge_a) < std::get<2>(edge_b)); }; #ifdef GUDHI_USE_TBB @@ -342,6 +339,35 @@ class Flag_complex_edge_collapser { }; +/** \brief Constructs a Flag complex from edges as an input, collapse edges and returns remaining edges. + * + * \fn auto Gudhi::collapse::flag_complex_collapse_edges(FilteredEdgeRange const& edges) + * + * \tparam FilteredEdgeRange furnishes `std::begin` and `std::end` methods and returns an iterator on a + * FilteredEdge of type `std::tuple` + * + * \ingroup edge_collapse + * + */ +template auto flag_complex_collapse_edges(const FilteredEdgeRange& edges) { + auto first_edge_itr = std::begin(edges); + auto first_vertex = std::get<0>(*first_edge_itr); + auto first_filt = std::get<2>(*first_edge_itr); + using Vertex_handle = decltype(first_vertex); + using Filtration_value = decltype(first_filt); + using Edge_collapser = Flag_complex_edge_collapser; + std::vector remaining_edges; + if (first_edge_itr != std::end(edges)) { + Edge_collapser edge_collapser(edges); + edge_collapser.process_edges( + [&remaining_edges](Vertex_handle u, Vertex_handle v, Filtration_value filtration) { + // insert the edge + remaining_edges.emplace_back(u, v, filtration); + }); + } + return remaining_edges; +} + } // namespace collapse } // namespace Gudhi -- cgit v1.2.3 From 230bbe960ef51496acae94451a269d8e1fd32817 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 08:06:39 +0200 Subject: Code review: use of std::decay --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 981ec88d..860b7aa5 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -32,6 +32,7 @@ #include // for std::tie #include // for std::includes #include // for std::inserter +#include // for std::decay namespace Gudhi { @@ -351,10 +352,8 @@ class Flag_complex_edge_collapser { */ template auto flag_complex_collapse_edges(const FilteredEdgeRange& edges) { auto first_edge_itr = std::begin(edges); - auto first_vertex = std::get<0>(*first_edge_itr); - auto first_filt = std::get<2>(*first_edge_itr); - using Vertex_handle = decltype(first_vertex); - using Filtration_value = decltype(first_filt); + using Vertex_handle = std::decay_t(*first_edge_itr))>; + using Filtration_value = std::decay_t(*first_edge_itr))>; using Edge_collapser = Flag_complex_edge_collapser; std::vector remaining_edges; if (first_edge_itr != std::end(edges)) { -- cgit v1.2.3 From 589a086317070c8a873051a5ca45cc56815ff53e Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Tue, 30 Jun 2020 23:09:17 -0700 Subject: Doc review: commit suggestion Co-authored-by: Marc Glisse --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 860b7aa5..e26f32f7 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -340,7 +340,7 @@ class Flag_complex_edge_collapser { }; -/** \brief Constructs a Flag complex from edges as an input, collapse edges and returns remaining edges. +/** \brief Implicitly constructs a flag complex from edges as an input, collapses edges while preserving the persistent homology and returns the remaining edges as a range. * * \fn auto Gudhi::collapse::flag_complex_collapse_edges(FilteredEdgeRange const& edges) * -- cgit v1.2.3 From 3bce2a71ab4a0fabb96fce56f32b605def0897a6 Mon Sep 17 00:00:00 2001 From: Vincent Rouvreau <10407034+VincentRouvreau@users.noreply.github.com> Date: Tue, 30 Jun 2020 23:10:29 -0700 Subject: Doc review: commit suggestion Co-authored-by: Marc Glisse --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index e26f32f7..60d75211 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -345,7 +345,7 @@ class Flag_complex_edge_collapser { * \fn auto Gudhi::collapse::flag_complex_collapse_edges(FilteredEdgeRange const& edges) * * \tparam FilteredEdgeRange furnishes `std::begin` and `std::end` methods and returns an iterator on a - * FilteredEdge of type `std::tuple` + * FilteredEdge of type `std::tuple` where Vertex_handle is the index of a vertex. * * \ingroup edge_collapse * -- cgit v1.2.3 From d8c5a1b263b5c008b7f41dc7f1cd18e185cd92ea Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 10:34:54 +0200 Subject: Doc review: Add some documentation for the free function --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 60d75211..07575b3b 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -340,13 +340,20 @@ class Flag_complex_edge_collapser { }; -/** \brief Implicitly constructs a flag complex from edges as an input, collapses edges while preserving the persistent homology and returns the remaining edges as a range. +/** \brief Implicitly constructs a flag complex from edges as an input, collapses edges while preserving the persistent + * homology and returns the remaining edges as a range. * * \fn auto Gudhi::collapse::flag_complex_collapse_edges(FilteredEdgeRange const& edges) + * + * \param[in] edges Range of Filtered edges.There is no need the range to be sorted, as it will be performed. * * \tparam FilteredEdgeRange furnishes `std::begin` and `std::end` methods and returns an iterator on a - * FilteredEdge of type `std::tuple` where Vertex_handle is the index of a vertex. + * FilteredEdge of type `std::tuple` where `Vertex_handle` is the type + * of a vertex index and `Filtration_value` is the type of an edge filtration value. * + * \return Remaining edges after collapse of type + * `std::vector>`. + * * \ingroup edge_collapse * */ -- cgit v1.2.3 From cf5deb9997ee0da5253d40cc2d2382fa2ca758ec Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 10:37:14 +0200 Subject: Remove Flag_complex_edge_collapser documentation. Only use the free function one --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 07575b3b..01be8f03 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -40,7 +40,6 @@ namespace collapse { /** \private * - * \class Flag_complex_edge_collapser * \brief Flag complex sparse matrix data structure. * * \details -- cgit v1.2.3 From f7876ea08e810c57f90e0233fffbd91d57f6d037 Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 22:09:58 +0200 Subject: doc review: fix some errors --- biblio/bibliography.bib | 28 +++++++++++++--------- .../include/gudhi/Flag_complex_edge_collapser.h | 6 ++--- src/common/doc/main_page.md | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) (limited to 'src/Collapse/include') diff --git a/biblio/bibliography.bib b/biblio/bibliography.bib index 4e716986..ad8ce50a 100644 --- a/biblio/bibliography.bib +++ b/biblio/bibliography.bib @@ -1279,15 +1279,21 @@ year = "2011" bibsource = {dblp computer science bibliography, https://dblp.org} } -@unpublished{edgecollapsesocg2020, - title = {{Edge Collapse and Persistence of Flag Complexes}}, - author = {Boissonnat, Jean-Daniel and Pritam, Siddharth}, - url = {https://hal.inria.fr/hal-02395227}, - note = {working paper or preprint}, - year = {2019}, - month = Dec, - keywords = {Persistent homology ; Strong Collapse ; Computational geometry ; Topological Data Analysis ; Computational Topology}, - pdf = {https://hal.inria.fr/hal-02395227/file/socg2020_paper_152.pdf}, - hal_id = {hal-02395227}, - hal_version = {v1}, +@InProceedings{edgecollapsesocg2020, + author = {Jean-Daniel Boissonnat and Siddharth Pritam}, + title = {{Edge Collapse and Persistence of Flag Complexes}}, + booktitle = {36th International Symposium on Computational Geometry (SoCG 2020)}, + pages = {19:1--19:15}, + series = {Leibniz International Proceedings in Informatics (LIPIcs)}, + ISBN = {978-3-95977-143-6}, + ISSN = {1868-8969}, + year = {2020}, + volume = {164}, + editor = {Sergio Cabello and Danny Z. Chen}, + publisher = {Schloss Dagstuhl--Leibniz-Zentrum f{\"u}r Informatik}, + address = {Dagstuhl, Germany}, + URL = {https://drops.dagstuhl.de/opus/volltexte/2020/12177}, + URN = {urn:nbn:de:0030-drops-121777}, + doi = {10.4230/LIPIcs.SoCG.2020.19}, + annote = {Keywords: Computational Topology, Topological Data Analysis, Edge Collapse, Simple Collapse, Persistent homology} } diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index 01be8f03..d1a47b75 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -342,16 +342,14 @@ class Flag_complex_edge_collapser { /** \brief Implicitly constructs a flag complex from edges as an input, collapses edges while preserving the persistent * homology and returns the remaining edges as a range. * - * \fn auto Gudhi::collapse::flag_complex_collapse_edges(FilteredEdgeRange const& edges) - * * \param[in] edges Range of Filtered edges.There is no need the range to be sorted, as it will be performed. * * \tparam FilteredEdgeRange furnishes `std::begin` and `std::end` methods and returns an iterator on a * FilteredEdge of type `std::tuple` where `Vertex_handle` is the type * of a vertex index and `Filtration_value` is the type of an edge filtration value. * - * \return Remaining edges after collapse of type - * `std::vector>`. + * \return Remaining edges after collapse as a range of + * ``. * * \ingroup edge_collapse * diff --git a/src/common/doc/main_page.md b/src/common/doc/main_page.md index 740a3e52..e19af537 100644 --- a/src/common/doc/main_page.md +++ b/src/common/doc/main_page.md @@ -235,7 +235,7 @@ -- cgit v1.2.3 From eedb34f25d76cb3dc7ccb6b59a60217a26eedfcd Mon Sep 17 00:00:00 2001 From: ROUVREAU Vincent Date: Wed, 1 Jul 2020 22:18:54 +0200 Subject: Bad fix --- src/Collapse/include/gudhi/Flag_complex_edge_collapser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Collapse/include') diff --git a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h index d1a47b75..b6b7f7c1 100644 --- a/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h +++ b/src/Collapse/include/gudhi/Flag_complex_edge_collapser.h @@ -349,7 +349,7 @@ class Flag_complex_edge_collapser { * of a vertex index and `Filtration_value` is the type of an edge filtration value. * * \return Remaining edges after collapse as a range of - * ``. + * `std::tuple`. * * \ingroup edge_collapse * -- cgit v1.2.3
Author: Siddharth Pritam
- Introduced in: GUDHI 2.4.0
+ Introduced in: GUDHI 3.3.0
Copyright: MIT
Requires: \ref eigen