From 425b462d361286822ee0ed7b5fe00881ba312ea3 Mon Sep 17 00:00:00 2001 From: vrouvrea Date: Fri, 5 Dec 2014 13:32:54 +0000 Subject: Moved into trunk git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/trunk@341 636b058d-ea47-450e-bf9e-a15bfbe3eedb --- src/common/doc/main_page.h | 52 +++++ src/common/include/gudhi/Clock.h | 67 ++++++ src/common/include/gudhi/Off_reader.h | 177 ++++++++++++++++ src/common/include/gudhi/Test.h | 85 ++++++++ src/common/include/gudhi/Utils.h | 34 +++ src/common/include/gudhi/distance_functions.h | 37 ++++ .../include/gudhi/graph_simplicial_complex.h | 96 +++++++++ src/common/include/gudhi/iofile.h | 236 +++++++++++++++++++++ src/common/include/gudhi/reader_utils.h | 181 ++++++++++++++++ 9 files changed, 965 insertions(+) create mode 100644 src/common/doc/main_page.h create mode 100644 src/common/include/gudhi/Clock.h create mode 100644 src/common/include/gudhi/Off_reader.h create mode 100644 src/common/include/gudhi/Test.h create mode 100644 src/common/include/gudhi/Utils.h create mode 100644 src/common/include/gudhi/distance_functions.h create mode 100644 src/common/include/gudhi/graph_simplicial_complex.h create mode 100644 src/common/include/gudhi/iofile.h create mode 100644 src/common/include/gudhi/reader_utils.h (limited to 'src/common') diff --git a/src/common/doc/main_page.h b/src/common/doc/main_page.h new file mode 100644 index 00000000..4e36066f --- /dev/null +++ b/src/common/doc/main_page.h @@ -0,0 +1,52 @@ +/** +\mainpage + +The Gudhi library (Geometric Understanding in Higher Dimensions) is a generic C++ library for +computational topology. Its goal is to provide robust, efficient, flexible and easy to use +implementations of +state-of-the-art algorithms and data structures for computational topology. We refer to +\cite gudhilibrary_ICMS14 +for a detailed description of the design of the library. + +The current release of the library allows the user to construct representations of simplicial complexes -- +simplex tree or Hasse diagram -- from a point +cloud (Rips complex) or +a list of simplices, and to compute their persistent homology with coefficients in a field +\f$\mathbb{Z}/p\mathbb{Z}\f$ (for an arbitrary prime \f$p\f$), or simultaneously with coefficients +in a family of fields (multi-field persistent homology). + + +To build the library, run the following in a terminal: + +\verbatim +cd /path-to-gudhi/ +mkdir build +cd build/ +cmake -DCMAKE_BUILD_TYPE=Release .. +make +\endverbatim + +The library has dependencies with Boost 1.48.0 or more recent (required): http://www.boost.org/ +and with GMP: https://gmplib.org/ The dependency with GMP is optional, and is used only for the +multi-field persistent homology algorithm. + + +We provide example files: run these examples with -h for details on their use, and read the README file. + +\li rips_persistence.cpp computes the Rips complex of a point cloud and its persistence diagram. + +\li rips_multifield_persistence.cpp computes the Rips complex of a point cloud and its persistence diagram +with a family of field coefficients. + +\li performance_rips_persistence.cpp provides timings for the construction of the Rips complex on a set of +points sampling a Klein bottle in \f$\mathbb{R}^5\f$ with a simplex tree, its conversion to a +Hasse diagram and the computation of persistent homology and multi-field persistent homology for the +different representations. + + +\details + +\copyright GNU General Public License v3. +\verbatim Contact: Clément Maria, clement.maria@inria.fr \endverbatim + +*/ \ No newline at end of file diff --git a/src/common/include/gudhi/Clock.h b/src/common/include/gudhi/Clock.h new file mode 100644 index 00000000..ea21659e --- /dev/null +++ b/src/common/include/gudhi/Clock.h @@ -0,0 +1,67 @@ +/* + * Clock.h + * + * Created on: Jun 17, 2014 + * Author: dsalinas + */ + +#ifndef GUDHI_CLOCK_H_ +#define GUDHI_CLOCK_H_ + + +#include + +class Clock{ + +public: + Clock():end_called(false){ + startTime = boost::posix_time::microsec_clock::local_time( ); + } + + Clock(const std::string& msg_){ + end_called = false; + begin(); + msg = msg_; + } + + + void begin() const{ + end_called = false; + startTime = boost::posix_time::microsec_clock::local_time( ); + } + + void end() const{ + end_called = true; + endTime = boost::posix_time::microsec_clock::local_time( ); + } + + void print() const{ + std::cout << *this << std::endl; + } + + friend std::ostream& operator<< (std::ostream& stream,const Clock& clock){ + if(!clock.end_called) + clock.end(); + + if(!clock.end_called) stream << "end not called"; + else{ + stream << clock.msg <<":"<. + * + */ + + +#ifndef GUDHI_OFF_READER_H_ +#define GUDHI_OFF_READER_H_ + + +#include +#include +#include + + +namespace Gudhi { + +/** + * Read an off file and calls a visitor methods while reading it. + * An off file must have its first/snd line in this format : + * OFF + * num_vert num_faces num_edges + * + * A noff file must have its first/snd line in this format : + * nOFF + * dim num_vert num_faces num_edges + * + * The number of edges num_edges is optional and can be left to zero. + */ +class Off_reader{ +public: + Off_reader(std::ifstream& stream):stream_(stream){ + } +// Off_reader(const std::string& name):stream_(name){ +// if(!stream_.is_open()) +// std::cerr <<"could not open file \n"; +// } + + ~Off_reader(){ + stream_.close(); + } + + /** + * read an off file and calls the following methods : + * void init(int dim,int num_vertices,int num_faces,int num_edges); //num_edges may not be set + * void point(const std::vector& point); + * void maximal_face(const std::list& face); + * void done(); + * of the visitor when reading a point or a maximal face. + */ + template + bool read(OffVisitor& off_visitor){ + bool success_read_off_preambule = read_off_preambule(off_visitor); + if(!success_read_off_preambule) { + std::cerr <<"could not read off preambule\n"; + return false; + } + + bool success_read_off_points = read_off_points(off_visitor); + if(!success_read_off_points) { + std::cerr <<"could not read off points\n"; + return false; + } + + bool success_read_off_faces = read_off_faces(off_visitor); + if(!success_read_off_faces) { + std::cerr <<"could not read off faces\n"; + return false; + } + + off_visitor.done(); + return success_read_off_preambule && success_read_off_points && success_read_off_faces; + } + +private: + std::ifstream& stream_; + + struct Off_info{ + int dim; + int num_vertices; + int num_edges; + int num_faces; + }; + + Off_info off_info_; + + template + bool read_off_preambule(OffVisitor& off_visitor){ + std::string line; + if(!goto_next_uncomment_line(line)) return false; + + bool is_off_file = (line.find("OFF") != std::string::npos); + bool is_noff_file = (line.find("nOFF") != std::string::npos); + + if(!is_off_file && !is_noff_file) return false; + + if(!goto_next_uncomment_line(line)) return false; + std::istringstream iss(line); + if(is_off_file){ + off_info_.dim = 3; + if(!(iss >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) + return false; + } + else + if(!(iss >> off_info_.dim >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) + return false; + off_visitor.init(off_info_.dim,off_info_.num_vertices,off_info_.num_faces,off_info_.num_edges); + + return true; + } + + bool goto_next_uncomment_line(std::string& uncomment_line){ + uncomment_line.clear(); + do + std::getline(stream_, uncomment_line); + while(uncomment_line[0] == '%'); + return (uncomment_line.size()>0 && uncomment_line[0] != '%'); + } + + + template + bool read_off_points(OffVisitor& visitor){ + int num_vertices_to_read = off_info_.num_vertices; + while(num_vertices_to_read--){ + std::string line; + if(!goto_next_uncomment_line(line)) return false; + std::vector point; + std::istringstream iss(line); + point.assign(std::istream_iterator(iss),std::istream_iterator()); +// if(point.size() != off_info_.dim) return false; + visitor.point(point); + } + return true; + } + + template + bool read_off_faces(OffVisitor& visitor){ + std::string line; + while(goto_next_uncomment_line(line)){ + std::istringstream iss(line); + int num_face_vertices; + iss >> num_face_vertices; + std::vector face; + face.assign(std::istream_iterator(iss),std::istream_iterator()); + if(!face.size() == off_info_.num_vertices) return false; + visitor.maximal_face(face); + } + return true; + } +}; + + +} // namespace Gudhi + + +#endif /* GUDHI_OFF_READER_H_ */ diff --git a/src/common/include/gudhi/Test.h b/src/common/include/gudhi/Test.h new file mode 100644 index 00000000..18b7ca82 --- /dev/null +++ b/src/common/include/gudhi/Test.h @@ -0,0 +1,85 @@ +#ifndef __TEST_H +#define __TEST_H + +#include +#include +#include +#include +#include + + +#define TEST(a) std::cout << "TEST: " << (a)< tests; + +public: + void add(std::string name_,bool (*test_)()){ + Test test(name_,test_); + tests.push_back(test); + } + bool run(){ + bool tests_succesful(true); + std::vector res; + for (Test test : tests){ + res.push_back(test.run()); + } + std::cout << "\n\n results of tests : "< "; + if (res[i++]) std::cout << "OK"< "; for(auto x:a) std::cerr<< x << ","; std::cerr<. + */ + +/* Compute the Euclidean distance between two Points given + * by a range of coordinates. The points are assumed to have + * the same dimension. */ +template< typename Point > +double euclidean_distance( Point &p1, Point &p2) +{ + double dist = 0.; + auto it1 = p1.begin(); auto it2 = p2.begin(); + for(; it1 != p1.end(); ++it1, ++it2) + { + double tmp = *it1 - *it2; + dist += tmp*tmp; + } + return sqrt(dist); +} diff --git a/src/common/include/gudhi/graph_simplicial_complex.h b/src/common/include/gudhi/graph_simplicial_complex.h new file mode 100644 index 00000000..e7a8cfe9 --- /dev/null +++ b/src/common/include/gudhi/graph_simplicial_complex.h @@ -0,0 +1,96 @@ + /* 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 + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (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 . + */ + +#ifndef GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H +#define GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H + +#include + +/* Edge tag for Boost PropertyGraph. */ +struct edge_filtration_t { + typedef boost::edge_property_tag kind; +}; +/* Vertex tag for Boost PropertyGraph. */ +struct vertex_filtration_t { + typedef boost::vertex_property_tag kind; +}; + +typedef int Vertex_handle; +typedef double Filtration_value; +typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS + , boost::property < vertex_filtration_t, Filtration_value > + , boost::property < edge_filtration_t, Filtration_value > + > Graph_t; +typedef std::pair< Vertex_handle, Vertex_handle > Edge_t; + +/** \brief Output 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. + * + * The type PointCloud furnishes .begin() and .end() methods, that return + * iterators with value_type Point. + */ +template< typename PointCloud + , typename Point > +Graph_t compute_proximity_graph( PointCloud &points + , Filtration_value threshold + , Filtration_value distance(Point p1, Point p2) ) +{ + std::vector< Edge_t > edges; + std::vector< Filtration_value > edges_fil; + std::map< Vertex_handle, Filtration_value > vertices; + + Vertex_handle idx_u, idx_v; + Filtration_value fil; + idx_u = 0; + for(auto it_u = points.begin(); it_u != points.end(); ++it_u) + { + idx_v = idx_u+1; + for(auto it_v = it_u+1; it_v != points.end(); ++it_v, ++idx_v) + { + fil = distance(*it_u,*it_v); + if(fil <= threshold) { + edges.emplace_back(idx_u,idx_v); + edges_fil.push_back(fil); + } + } + ++idx_u; + } + + Graph_t skel_graph( edges.begin() + , edges.end() + , edges_fil.begin() + , idx_u); //number of points labeled from 0 to idx_u-1 + + auto vertex_prop = boost::get(vertex_filtration_t(),skel_graph); + + boost::graph_traits::vertex_iterator vi, vi_end; + for ( tie(vi, vi_end) = boost::vertices(skel_graph); + vi != vi_end; ++vi ) + { boost::put(vertex_prop, *vi, 0.); } + + return skel_graph; +} + +#endif // GUDHI_GRAPH_SIMPLICIAL_COMPLEX_FILTRATION_TAG_H diff --git a/src/common/include/gudhi/iofile.h b/src/common/include/gudhi/iofile.h new file mode 100644 index 00000000..b939d45b --- /dev/null +++ b/src/common/include/gudhi/iofile.h @@ -0,0 +1,236 @@ +//todo remove and use off_reader instead + +#ifndef GUDHI_IOFILE_H_ +#define GUDHI_IOFILE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + + + +//todo use my new visitor based off instead +/** + * @brief OFF reader, save the content of the file (vertices and maximal faces) in 'complex'. + * The class Complex has to handle the following operations: + * - void add_vertex(double[dim],int dim) + * - void add_face(int dimension ,int[dimension] vertices) + * Source from : http://www.holmes3d.net/graphics/offfiles/OFFLoading.txt + * + * @todo todo ignore comments in the file -> # comment + */ +template inline +bool general_read_off_file(const std::string & file_name, Complex& complex){ + // Declare temporary variables to read data into. + // If the read goes well, we'll copy these into + // our class variables, overwriting what used to + // be there. If it doesn't, we won't have messed up + // our previous data structures. + int tempNumPoints = 0; // Number of x,y,z coordinate triples + int tempNumFaces = 0; // Number of polygon sets + int tempNumEdges = 0; // Unused, except for reading. + int tempDimPoints = 0; + double** tempPoints = NULL; // An array of x,y,z coordinates. + int** tempFaces = NULL; // An array of arrays of point + // pointers. Each entry in this + // is an array of integers. Each + // integer in that array is the + // index of the x, y, and z + // coordinates in the corresponding + // arrays. + int* tempFaceSizes = NULL; // An array of polygon point counts. + // Each of the arrays in the tempFaces + // array may be of different lengths. + // This array corresponds to that + // array, and gives their lengths. + int i; // Generic loop variable. + bool goodLoad = true; // Set to false if the file appears + // not to be a valid OFF file. + char tempBuf[128]; // A buffer for reading strings + // from the file. + + // Create an input file stream for the file the CArchive + // is connected to. This allows use of the overloaded + // extraction operator for conversion from string + // data to doubles and ints. + std::ifstream ifs (file_name.c_str(), std::ios::in); + if(!ifs.is_open()) { + std::cerr << "Unable to open file " << file_name << std::endl; + return false; + } + + // Grab the first string. If it's "OFF", we think this + // is an OFF file and continue. Otherwise we give up. + ifs >> tempBuf; + if (strcmp(tempBuf, "OFF") != 0) { + goodLoad = false; + std::cerr << "No OFF preambule\n"; + } + + // Read the sizes for our two arrays, and the third + // int on the line. If the important two are zero + // sized, this is a messed up OFF file. Otherwise, + // we setup our temporary arrays. + if (goodLoad) { + ifs >> tempNumPoints >> tempNumFaces >> tempNumEdges; + if (tempNumPoints < 1 || tempNumFaces < 0) { + // If either of these were negative, we make + // sure that both are set to zero. This is + // important for later deleting our temporary + // storage. + goodLoad = false; + std::cerr << "tempNumPoints < 1 || tempNumFaces < 0\n"; + tempNumPoints = 0; + tempNumFaces = 0; + } else { + tempPoints = new double*[tempNumPoints]; + tempFaces = new int*[tempNumFaces]; + tempFaceSizes = new int[tempNumFaces]; + } + } + + if (goodLoad) { + // Load all of the points. + + // we start by loading the first one + // the case is difference because then we dont know the dimension by advance + // we discover the point dimension by reading the first line + std::string lineFirstPoint; + std::getline(ifs, lineFirstPoint); + while(lineFirstPoint.size()<3){ + std::getline(ifs, lineFirstPoint); + } + + // we store the first point in a temporary list + std::istringstream lineFirstPointStream(lineFirstPoint); + std::list firstTempPoint; + double coord; + while(lineFirstPointStream>>coord){ + firstTempPoint.push_back(coord); + ++tempDimPoints; + } + // we store the point in our points array + tempPoints[0]=new double[tempDimPoints]; + for( int j = 0 ; j>tempPoints[i][j]; + } + } + + // Load all of the faces. + for (i = 0; i < tempNumFaces; i++) { + // This tells us how many points make up + // this face. + ifs >> tempFaceSizes[i]; + // So we declare a new array of that size + tempFaces[i] = new int[tempFaceSizes[i]]; + // And load its elements with the vertex indices. + for (int j = 0; j < tempFaceSizes[i]; j++) { + ifs >> tempFaces[i][j]; + } + // Clear out any face color data by reading up to + // the newline. 128 is probably considerably more + // space than necessary, but better safe than + // sorry. + ifs.getline(tempBuf, 128); + } + } + + // Here is where we copy the data from the temp + // structures into our permanent structures. We + // probably will do some more processing on the + // data at the same time. This code you must fill + // in on your own. + if (goodLoad) { + // we save vertices first in the complex + for (i = 0; i < tempNumPoints; i++) + complex.add_vertex(tempPoints[i],tempDimPoints); + + // we save faces + for (i = 0; i < tempNumFaces; i++) { + for (int j = 0; j < tempFaceSizes[i]; j++) + complex.add_face(tempFaceSizes[i],tempFaces[i]); + } + } + + // Now that we're done, we have to make sure we + // free our dynamic memory. + for (i = 0; i < tempNumPoints; i++) { + delete []tempPoints[i]; + } + delete []tempPoints; + + for (i = 0; i < tempNumFaces; i++) { + delete tempFaces[i]; + } + delete []tempFaces; + delete []tempFaceSizes; + + // Clean up our ifstream. The MFC framework will + // take care of the CArchive. + ifs.close(); + + return goodLoad; +} + + +template +class Geometric_flag_complex_wrapper{ + Complex& complex_; + typedef typename Complex::Vertex_handle Vertex_handle; + typedef typename Complex::Point Point; + + const bool load_only_points_; + +public: + Geometric_flag_complex_wrapper(Complex& complex,bool load_only_points = false): + complex_(complex), + load_only_points_(load_only_points) +{} + + + void add_vertex(double* xyz,int dim){ + Point p(dim); + for(int i=0;i +bool read_off_file(std::string file_name,Complex &complex,bool load_only_points = false){ + complex.clear(); + Geometric_flag_complex_wrapper complex_wrapper(complex,load_only_points); + return general_read_off_file(file_name,complex_wrapper); + +} + + +#endif diff --git a/src/common/include/gudhi/reader_utils.h b/src/common/include/gudhi/reader_utils.h new file mode 100644 index 00000000..5c8cbeb7 --- /dev/null +++ b/src/common/include/gudhi/reader_utils.h @@ -0,0 +1,181 @@ + /* 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 + * + * Copyright (C) 2014 INRIA Sophia Antipolis-Méditerranée (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 . + */ + +#ifndef GUDHI_READER_UTILS_H +#define GUDHI_READER_UTILS_H + +#include +#include +#include +#include "gudhi/graph_simplicial_complex.h" + +/** + * \brief Read a set of points to turn it + * into a vector< vector > by filling points + * + * File format: 1 point per line + * X11 X12 ... X1d + * X21 X22 ... X2d + * etc + */ +inline void +read_points ( std::string file_name + , std::vector< std::vector< double > > & points) +{ + std::ifstream in_file (file_name.c_str(),std::ios::in); + if(!in_file.is_open()) { + std::cerr << "Unable to open file " << file_name << std::endl; + return;} + + std::string line; + double x; + while( getline ( in_file , line ) ) + { + std::vector< double > point; + std::istringstream iss( line ); + while(iss >> x) { point.push_back(x); } + points.push_back(point); + } + in_file.close(); +} + +/** + * \brief Read a graph from a file. + * + * File format: 1 simplex per line + * Dim1 X11 X12 ... X1d Fil1 + * Dim2 X21 X22 ... X2d Fil2 + * etc + * + * The vertices must be labeled from 0 to n-1. + * Every simplex must appear exactly once. + * Simplices of dimension more than 1 are ignored. + */ +inline Graph_t +read_graph ( std::string file_name ) +{ + std::ifstream in_ (file_name.c_str(),std::ios::in); + if(!in_.is_open()) { std::cerr << "Unable to open file " << file_name << std::endl; } + + std::vector< Edge_t > edges; + std::vector< Filtration_value > edges_fil; + std::map< Vertex_handle, Filtration_value > vertices; + + std::string line; + int dim; + Vertex_handle u,v,max_h = -1; + Filtration_value fil; + while( getline ( in_ , line ) ) + { + std::istringstream iss( line ); + while(iss >> dim) { + switch ( dim ) { + case 0 : { + iss >> u; iss >> fil; + vertices[u] = fil; + if(max_h < u) { max_h = u; } + break; + } + case 1 : { + iss >> u; iss >> v; iss >> fil; + edges.push_back(Edge_t(u,v)); + edges_fil.push_back(fil); + break; + } + default: {break;} + } + } + } + in_.close(); + + if((size_t)(max_h+1) != vertices.size()) + { std::cerr << "Error: vertices must be labeled from 0 to n-1 \n"; } + + Graph_t skel_graph(edges.begin(),edges.end(),edges_fil.begin(),vertices.size()); + auto vertex_prop = boost::get(vertex_filtration_t(),skel_graph); + + boost::graph_traits::vertex_iterator vi, vi_end; + auto v_it = vertices.begin(); + for (tie(vi, vi_end) = boost::vertices(skel_graph); vi != vi_end; ++vi,++v_it) + { boost::put(vertex_prop, *vi, v_it->second); } + + return skel_graph; +} + +/** + * \brief Read a face from a file. + * + * File format: 1 simplex per line + * Dim1 X11 X12 ... X1d Fil1 + * Dim2 X21 X22 ... X2d Fil2 + * etc + * + * The vertices must be labeled from 0 to n-1. + * Every simplex must appear exactly once. + * Simplices of dimension more than 1 are ignored. + */ +template< typename Vertex_handle + , typename Filtration_value > +bool read_simplex ( std::istream & in_ + , std::vector< Vertex_handle > & simplex + , Filtration_value & fil ) +{ + int dim=0; + if(!(in_ >> dim)) return false; + Vertex_handle v; + for(int i=0; i> v; simplex.push_back(v); } + in_ >> fil; + in_.ignore(std::numeric_limits::max(), '\n'); // ignore until the carriage return + return true; +} + +/** + * \brief Read a hasse simplex from a file. + * + * File format: 1 simplex per line + * Dim1 k11 k12 ... k1Dim1 Fil1 + * Dim2 k21 k22 ... k2Dim2 Fil2 + * etc + * + * The key of a simplex is its position in the filtration order + * and also the number of its row in the file. + * Dimi ki1 ki2 ... kiDimi Fili means that the ith simplex in the + * filtration has dimension Dimi, filtration value fil1 and simplices with + * key ki1 ... kiDimi in its boundary.*/ +template< typename Simplex_key + , typename Filtration_value > +bool read_hasse_simplex ( std::istream & in_ + , std::vector< Simplex_key > & boundary + , Filtration_value & fil ) +{ + int dim; + if(!(in_ >> dim)) return false; + if(dim == 0) {in_ >> fil; return true;} + Simplex_key key; + for(int i=0; i> key; boundary.push_back(key); } + in_ >> fil; + return true; +} + +#endif // GUDHI_READER_UTILS_H -- cgit v1.2.3