diff options
author | vrouvrea <vrouvrea@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2014-12-05 13:32:54 +0000 |
---|---|---|
committer | vrouvrea <vrouvrea@636b058d-ea47-450e-bf9e-a15bfbe3eedb> | 2014-12-05 13:32:54 +0000 |
commit | 425b462d361286822ee0ed7b5fe00881ba312ea3 (patch) | |
tree | e8f641a8604418882b916573cf32c87b78d33472 /src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h | |
parent | 952b77f3b1e2415602d5d9ffc2fb7ff45cc3edc4 (diff) |
Moved into trunk
git-svn-id: svn+ssh://scm.gforge.inria.fr/svnroot/gudhi/trunk@341 636b058d-ea47-450e-bf9e-a15bfbe3eedb
Diffstat (limited to 'src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h')
-rw-r--r-- | src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h | 1422 |
1 files changed, 1422 insertions, 0 deletions
diff --git a/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h new file mode 100644 index 00000000..b4c1cd9e --- /dev/null +++ b/src/Skeleton_blocker/include/gudhi/Skeleton_blocker_complex.h @@ -0,0 +1,1422 @@ +/* + * Skeleton_blocker_complex.h + * + * Created on: Jan, 2014 + * Author: dsalinas + */ + +#ifndef GUDHI_SKELETON_BLOCKER_COMPLEX_H +#define GUDHI_SKELETON_BLOCKER_COMPLEX_H + + +#include <map> +#include <list> +#include <set> +#include <vector> +#include <iostream> +#include <string> +#include <fstream> +#include <sstream> +#include <memory> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/range/adaptor/map.hpp> + +#include "gudhi/Skeleton_blocker/iterators/Skeleton_blockers_iterators.h" +#include "gudhi/Skeleton_blocker_link_complex.h" +#include "gudhi/Skeleton_blocker/Skeleton_blocker_link_superior.h" +#include "gudhi/Skeleton_blocker/Skeleton_blocker_sub_complex.h" +#include "gudhi/Skeleton_blocker/Skeleton_blocker_simplex.h" + +#include "gudhi/Skeleton_blocker/Skeleton_blocker_complex_visitor.h" +#include "gudhi/Skeleton_blocker/internal/Top_faces.h" +#include "gudhi/Utils.h" + + +namespace Gudhi { + +namespace skbl { + + +/** + *@class Skeleton_blocker_complex + *@brief Abstract Simplicial Complex represented with a skeleton/blockers pair. + * + * A simplicial complex is completely defined by : + * - the graph of its 1-skeleton; + * - its set of blockers. + * + * The graph is a boost graph templated with SkeletonBlockerDS::Graph_vertex and SkeletonBlockerDS::Graph_edge. + * + * One can accesses to vertices via SkeletonBlockerDS::Vertex_handle, to edges via Skeleton_blocker_complex::Edge_handle and + * simplices via Skeleton_blocker_simplex<Vertex_handle>. + * + * The SkeletonBlockerDS::Root_vertex_handle serves in the case of a subcomplex (see class Skeleton_blocker_sub_complex) + * to access to the address of one vertex in the parent complex. + * + * @todo TODO Simplex_handle are not classic handle + * + */ +template<class SkeletonBlockerDS> +class Skeleton_blocker_complex +{ + template<class ComplexType> friend class Complex_vertex_iterator; + template<class ComplexType> friend class Complex_neighbors_vertices_iterator; + template<class ComplexType> friend class Complex_edge_iterator; + template<class ComplexType> friend class Complex_edge_around_vertex_iterator; + + + template<class ComplexType> friend class Skeleton_blocker_link_complex; + template<class ComplexType> friend class Skeleton_blocker_link_superior; + template<class ComplexType> friend class Skeleton_blocker_sub_complex; + +public: + + + typedef typename SkeletonBlockerDS::Graph_vertex Graph_vertex; + typedef typename SkeletonBlockerDS::Graph_edge Graph_edge; + + typedef typename SkeletonBlockerDS::Root_vertex_handle Root_vertex_handle; + typedef typename SkeletonBlockerDS::Vertex_handle Vertex_handle; + typedef typename Root_vertex_handle::boost_vertex_handle boost_vertex_handle; + + + typedef Skeleton_blocker_simplex<Vertex_handle> Simplex_handle; + typedef Skeleton_blocker_simplex<Root_vertex_handle> Root_simplex_handle; + + + typedef Simplex_handle* Blocker_handle; + + + + typedef typename Root_simplex_handle::Simplex_vertex_const_iterator Root_simplex_iterator; + typedef typename Simplex_handle::Simplex_vertex_const_iterator Simplex_handle_iterator; + + +protected: + + typedef typename boost::adjacency_list + < boost::setS, //edges + boost::vecS, // vertices + boost::undirectedS, + Graph_vertex, + Graph_edge + > Graph; + //todo/remark : edges are not sorted, it heavily penalizes computation for SuperiorLink + // (eg Link with greater vertices) + // that burdens simplex iteration / complex initialization via list of simplices. + // to avoid that, one should modify the graph by storing two lists of adjacency for every + // vertex, the one with superior and the one with lower vertices, that way there is + // no more extra cost for computation of SuperiorLink + typedef typename boost::graph_traits<Graph>::vertex_iterator boost_vertex_iterator; + typedef typename boost::graph_traits<Graph>::edge_iterator boost_edge_iterator; + +protected: + typedef typename boost::graph_traits<Graph>::adjacency_iterator boost_adjacency_iterator; + +public: + /** + * Handle to an edge of the complex. + */ + typedef typename boost::graph_traits<Graph>::edge_descriptor Edge_handle; + + + + typedef std::multimap<Vertex_handle,Simplex_handle *> BlockerMap; + typedef typename std::multimap<Vertex_handle,Simplex_handle *>::value_type BlockerPair; + typedef typename std::multimap<Vertex_handle,Simplex_handle *>::iterator BlockerMapIterator; + typedef typename std::multimap<Vertex_handle,Simplex_handle *>::const_iterator BlockerMapConstIterator; + +protected: + int num_vertices_; + int num_blockers_; + + typedef Skeleton_blocker_complex_visitor<Vertex_handle> Visitor; + // typedef Visitor* Visitor_ptr; + Visitor* visitor; + + /** + * @details If 'x' is a Vertex_handle of a vertex in the complex then degree[x] = d is its degree. + * + * This quantity is updated when adding/removing edge. + * + * This is useful because the operation + * list.size() is done in linear time. + */ + std::vector<boost_vertex_handle> degree_; + Graph skeleton; /** 1-skeleton of the simplicial complex. */ + + + //todo remove!!! +public: + + /** Each vertex can access to the blockers passing through it. */ + BlockerMap blocker_map_; + + + + +public: + + + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Constructors / Destructors / Initialization + */ + //@{ + Skeleton_blocker_complex(int num_vertices_ = 0,Visitor* visitor_=NULL):visitor(visitor_){ + clear(); + for (int i=0; i<num_vertices_; ++i){ + add_vertex(); + } + } + +private: + + /** + * this nested class is used for the next constructor that takes as an input a list of simplices. + * It stores a vector where the ith cell contains a set of i-simplices + * + */ + class Simplices_sets_from_list{ + private: + typedef std::set< Simplex_handle> Container_simplices; + typedef typename Container_simplices::iterator Simplices_iterator; + int dimension_; + std::vector<Container_simplices > simplices_; + + public: + Simplices_sets_from_list(std::list<Simplex_handle>& simplices): + dimension_(-1){ + assert(!simplices.empty()); + + for(auto simplex = simplices.begin() ; simplex != simplices.end(); ++simplex ){ + dimension_ = std::max(dimension_,(int)simplex->dimension()); + } + simplices_ = std::vector<Container_simplices >(dimension_+1); + + // compute k-simplices + for(auto simplex = simplices.begin() ; simplex != simplices.end(); ++simplex ){ + simplices_[simplex->dimension()].insert(*simplex); + } + } + + Simplices_iterator begin(int k){ + assert(0<= k && k<= dimension_); + return simplices_[k].begin(); + } + + Simplices_iterator end(int k){ + assert(0<= k && k<= dimension_); + return simplices_[k].end(); + } + + + Container_simplices& simplices(int k){ + return simplices_[k]; + } + + int dimension(){ + return dimension_; + } + + bool contains(const Simplex_handle& simplex) const{ + if(simplex.dimension()>dimension_) + return false; + else + return simplices_[simplex.dimension()].find(simplex)!= simplices_[simplex.dimension()].end(); + } + + void print(){ + for(int i = 0; i < dimension_; ++i){ + std::cout << i<<"-simplices"<<std::endl; + auto l = simplices_[i]; + for(auto s : l){ + std::cout << s<<std::endl; + } + } + } + }; + + + void compute_next_expand( + Simplices_sets_from_list& simplices, + int dim, + std::list<Simplex_handle>& next_expand) + { + next_expand.clear(); + + // high_resolution_clock::time_point tbeginfor = high_resolution_clock::now(); + // auto durationlooplink = std::chrono::duration_cast<std::chrono::microseconds>( tbeginfor - tbeginfor ).count(); + + for(auto sigma = simplices.begin(dim); sigma != simplices.end(dim); ++sigma){ + // high_resolution_clock::time_point tbeg = high_resolution_clock::now(); + Simplex_handle t(*sigma); + Skeleton_blocker_link_superior<Skeleton_blocker_complex> link(*this,t); + // xxx all time here, most likely because accessing superior edges needs passing through lower one + // currently + + // durationlooplink += std::chrono::duration_cast<std::chrono::microseconds>( high_resolution_clock::now() - tbeg ).count(); + + for(auto v : link.vertex_range()){ + Vertex_handle v_in_complex(*this->get_address( link.get_id(v)) ); + t.add_vertex(v_in_complex); + next_expand.push_back(t); + t.remove_vertex(v_in_complex); + } + } + // high_resolution_clock::time_point t2 = high_resolution_clock::now(); + // auto durationlooptotal = std::chrono::duration_cast<std::chrono::microseconds>( t2 - tbeginfor ).count(); + // DBGVALUE(durationlooptotal); + // DBGVALUE(durationlooplink); + } + + + +public: + /** + * @brief Constructor with a list of simplices + * @details The list of simplices must be the list + * of simplices of a simplicial complex. + *todo rewrite as iterators + */ + Skeleton_blocker_complex(std::list<Simplex_handle>& simplices,Visitor* visitor_=NULL): + num_vertices_(0),num_blockers_(0), + visitor(visitor_){ + Simplices_sets_from_list set_simplices(simplices); + + int dim = set_simplices.dimension(); + + + // add 1-skeleton to the complex + for(auto v_it = set_simplices.begin(0); v_it != set_simplices.end(0); ++v_it) + add_vertex(); + + for(auto e_it = set_simplices.begin(1); e_it != set_simplices.end(1); ++e_it){ + Vertex_handle a = e_it->first_vertex(); + Vertex_handle b = e_it->last_vertex(); + assert(contains_vertex(a) && contains_vertex(b)); + add_edge(a,b); + } + + // then add blockers + for(int current_dim = 1 ; current_dim <=dim ; ++current_dim){ + std::list<Simplex_handle> expansion_simplices; + compute_next_expand(set_simplices,current_dim,expansion_simplices); + + for(const auto &simplex : expansion_simplices) { + if(!set_simplices.contains(simplex)){ + add_blocker(simplex); + } + } + } + } + + + + // We cannot use the default copy constructor since we need + // to make a copy of each of the blockers + Skeleton_blocker_complex(const Skeleton_blocker_complex& copy){ + visitor = NULL; + degree_ = copy.degree_; + skeleton = Graph(copy.skeleton); + num_vertices_ = copy.num_vertices_; + + num_blockers_ = 0; + // we copy the blockers + for (auto blocker : copy.const_blocker_range()){ + add_blocker(*blocker); + } + } + + Skeleton_blocker_complex& operator=(const Skeleton_blocker_complex& copy){ + clear(); + visitor = NULL; + degree_ = copy.degree_; + skeleton = Graph(copy.skeleton); + num_vertices_ = copy.num_vertices_; + + num_blockers_ = 0; + // we copy the blockers + for (auto blocker : copy.const_blocker_range()) + add_blocker(*blocker); + return *this; + } + + + /** + * The destructor delete all blockers allocated. + */ + virtual ~Skeleton_blocker_complex(){ + clear(); + } + + /** + * Clears the simplicial complex. After a call to this function, + * blockers are destroyed. The 1-skeleton and the set of blockers + * are both empty. + */ + virtual void clear(){ + // xxx for now the responsabilty of freeing the visitor is for + // the user + visitor = NULL; + + degree_.clear(); + num_vertices_ =0; + + remove_blockers(); + + skeleton.clear(); + } + + void set_visitor(Visitor* other_visitor){ + visitor = other_visitor; + } + + //@} + + + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Vertices operations + */ + //@{ + +public: + + /** + * @brief Return a local Vertex_handle of a vertex given a global one. + * @remark Assume that the vertex is present in the complex. + */ + Vertex_handle operator[](Root_vertex_handle global) const{ + auto local(get_address(global)); + assert(local); + return *local; + } + + Graph_vertex& operator[](Vertex_handle address){ + assert(0<=address.vertex && address.vertex< boost::num_vertices(skeleton)); + return skeleton[address.vertex]; + } + + const Graph_vertex& operator[](Vertex_handle address) const{ + assert(0<=address.vertex && address.vertex< boost::num_vertices(skeleton)); + return skeleton[address.vertex]; + } + + /** + * @brief Adds a vertex to the simplicial complex and returns its Vertex_handle. + */ + Vertex_handle add_vertex(){ + Vertex_handle address(boost::add_vertex(skeleton)); + num_vertices_++; + (*this)[address].activate(); + // safe since we now that we are in the root complex and the field 'address' and 'id' + // are identical for every vertices + (*this)[address].set_id(Root_vertex_handle(address.vertex)); + degree_.push_back(0); + if (visitor) visitor->on_add_vertex(address); + return address; + } + + + /** + * @brief Remove a vertex from the simplicial complex + * @remark In fact, it just deactivates the vertex. + */ + void remove_vertex(Vertex_handle address){ + assert(contains_vertex(address)); + // We remove b + boost::clear_vertex(address.vertex,skeleton); + (*this)[address].deactivate(); + num_vertices_--; + degree_[address.vertex]=-1; + if (visitor) visitor->on_remove_vertex(address); + } + + /** + * @return true iff the simplicial complex contains the vertex u + */ + bool contains_vertex(Vertex_handle u) const{ + if (u.vertex<0 || u.vertex>=boost::num_vertices(skeleton)) return false; + return (*this)[u].is_active(); + } + + /** + * @return true iff the simplicial complex contains the vertex u + */ + bool contains_vertex(Root_vertex_handle u) const{ + boost::optional<Vertex_handle> address = get_address(u); + return address && (*this)[*address].is_active(); + } + + + /** + * @return true iff the simplicial complex contains all vertices + * of simplex sigma + */ + bool contains_vertices(const Simplex_handle & sigma) const{ + for (auto vertex : sigma) + if(!contains_vertex(vertex)) return false; + return true; + } + + /** + * Given an Id return the address of the vertex having this Id in the complex. + * For a simplicial complex, the address is the id but it may not be the case for a SubComplex. + * + */ + virtual boost::optional<Vertex_handle> get_address(Root_vertex_handle id) const{ + boost::optional<Vertex_handle> res; + if ( id.vertex< boost::num_vertices(skeleton) ) res = Vertex_handle(id.vertex);//xxx + return res; + } + + + + /** + * return the id of a vertex of adress local present in the graph + */ + Root_vertex_handle get_id(Vertex_handle local) const{ + assert(0<=local.vertex && local.vertex< boost::num_vertices(skeleton)); + return (*this)[local].get_id(); + } + + + /** + * If the current complex is a sub (or sup) complex of 'other', it converts + * the address of a vertex v expressed in 'other' to the address of the vertex + * v in the current one. + * @remark this methods uses Root_vertex_handle to identify the vertex + */ + Vertex_handle convert_handle_from_another_complex( + const Skeleton_blocker_complex& other,Vertex_handle vh_in_other) const{ + auto vh_in_current_complex = get_address(other.get_id(vh_in_other)); + assert(vh_in_current_complex); + return *vh_in_current_complex; + } + + + int degree(Vertex_handle local) const{ + assert(0<=local.vertex && local.vertex< boost::num_vertices(skeleton)); + return degree_[local.vertex]; + } + + //@} + + ///////////////////////////////////////////////////////////////////////////// + /** @name Edges operations + */ + //@{ + +public: + + /** + * @brief return an edge handle if the two vertices forms + * an edge in the complex + */ + boost::optional<Edge_handle> operator[](const std::pair<Vertex_handle,Vertex_handle>& ab) const{ + boost::optional<Edge_handle> res; + std::pair<Edge_handle,bool> edge_pair(boost::edge(ab.first.vertex,ab.second.vertex,skeleton)); + if (edge_pair.second) + res = edge_pair.first; + return res; + } + + Graph_edge& operator[](Edge_handle edge_handle){ + return skeleton[edge_handle]; + } + + const Graph_edge& operator[](Edge_handle edge_handle) const{ + return skeleton[edge_handle]; + } + + Vertex_handle first_vertex(Edge_handle edge_handle) const{ + return source(edge_handle,skeleton); + } + + Vertex_handle second_vertex(Edge_handle edge_handle) const{ + return target(edge_handle,skeleton); + } + + /** + * @brief returns the simplex made with the two vertices of the edge + */ + Simplex_handle get_vertices(Edge_handle edge_handle) const{ + auto edge((*this)[edge_handle]); + return Simplex_handle((*this)[edge.first()],(*this)[edge.second()]); + } + + /** + * @brief Adds an edge between vertices a and b + */ + Edge_handle add_edge(Vertex_handle a, Vertex_handle b){ + assert(contains_vertex(a) && contains_vertex(b)); + assert(a!=b); + + auto edge_handle((*this)[std::make_pair(a,b)]); + // std::pair<Edge_handle,bool> pair_descr_bool = (*this)[std::make_pair(a,b)]; + // Edge_handle edge_descr; + // bool edge_present = pair_descr_bool.second; + if (!edge_handle) + { + edge_handle = boost::add_edge(a.vertex,b.vertex,skeleton).first; + (*this)[*edge_handle].setId(get_id(a),get_id(b)); + degree_[a.vertex]++; + degree_[b.vertex]++; + if (visitor) visitor->on_add_edge(a,b); + } + return *edge_handle; + } + + /** + * @brief Adds all edges of simplex sigma to the simplicial complex. + */ + void add_edges(const Simplex_handle & sigma){ + Simplex_handle_iterator i, j; + for (i = sigma.begin() ; i != sigma.end() ; ++i) + for (j = i, j++ ; j != sigma.end() ; ++j) + add_edge(*i,*j); + } + + /** + * @brief Removes edge ab from the simplicial complex. + */ + virtual Edge_handle remove_edge(Vertex_handle a, Vertex_handle b){ + bool found; + Edge_handle edge; + tie(edge,found) = boost::edge(a.vertex,b.vertex,skeleton); + if (found) + { + if (visitor) visitor->on_remove_edge(a,b); + // if (heapCollapse.Contains(edge)) heapCollapse.Delete(edge); + boost::remove_edge(a.vertex,b.vertex,skeleton); + degree_[a.vertex]--; + degree_[b.vertex]--; + } + return edge; + } + + + /** + * @brief Removes edge from the simplicial complex. + */ + void remove_edge(Edge_handle edge){ + assert(contains_vertex(first_vertex(edge))); + assert(contains_vertex(second_vertex(edge))); + remove_edge(first_vertex(edge),second_vertex(edge)); + } + + + /** + * @brief The complex is reduced to its set of vertices. + * All the edges and blockers are removed. + */ + void keep_only_vertices(){ + remove_blockers(); + + for(auto u : vertex_range()){ + while (this->degree(u)> 0) + { + Vertex_handle v(*(adjacent_vertices(u.vertex, this->skeleton).first)); + this->remove_edge(u,v); + } + } + } + + + /** + * @return true iff the simplicial complex contains an edge between + * vertices a and b + */ + bool contains_edge(Vertex_handle a, Vertex_handle b) const{ + //if (a.vertex<0 || b.vertex <0) return false; + return boost::edge(a.vertex,b.vertex,skeleton).second; + } + + + /** + * @return true iff the simplicial complex contains all vertices + * and all edges of simplex sigma + */ + bool contains_edges(const Simplex_handle & sigma) const{ + for (auto i = sigma.begin() ; i != sigma.end() ; ++i){ + if(!contains_vertex(*i)) return false; + for (auto j=i; ++j != sigma.end() ; ){ + if (!contains_edge(*i,*j)) + return false; + } + } + return true; + } + //@} + + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Blockers operations + */ + //@{ + /** + * Adds the 2-blocker abc + */ + void add_blocker(Vertex_handle a, Vertex_handle b, Vertex_handle c){ + add_blocker(Simplex_handle(a,b,c)); + } + + /** + * Adds the 3-blocker abcd + */ + void add_blocker(Vertex_handle a, Vertex_handle b, Vertex_handle c, Vertex_handle d){ + add_blocker(Simplex_handle(a,b,c,d)); + } + + /** + * Adds the simplex blocker_pt to the set of blockers and + * returns a Blocker_handle toward it if was not present before. + */ + Blocker_handle add_blocker(const Simplex_handle& blocker){ + if (contains_blocker(blocker)) + { + //std::cerr << "ATTEMPT TO ADD A BLOCKER ALREADY THERE ---> BLOCKER IGNORED" << endl; + return 0; + } + else{ + if (visitor) visitor->on_add_blocker(blocker); + Blocker_handle blocker_pt = new Simplex_handle(blocker); + num_blockers_++; + auto vertex = blocker_pt->begin(); + while(vertex != blocker_pt->end()) + { + blocker_map_.insert(BlockerPair(*vertex,blocker_pt)); + ++vertex; + } + return blocker_pt; + } + } + +protected: + /** + * Adds the simplex s to the set of blockers + */ + void add_blocker(Blocker_handle blocker){ + if (contains_blocker(*blocker)) + { + //std::cerr << "ATTEMPT TO ADD A BLOCKER ALREADY THERE ---> BLOCKER IGNORED" << endl; + return; + } + else{ + if (visitor) visitor->on_add_blocker(*blocker); + num_blockers_++; + auto vertex = blocker->begin(); + while(vertex != blocker->end()) + { + blocker_map_.insert(BlockerPair(*vertex,blocker)); + ++vertex; + } + } + } + + +protected: + /** + * Removes sigma from the blocker map of vertex v + */ + void remove_blocker(const Blocker_handle sigma, Vertex_handle v){ + Complex_blocker_around_vertex_iterator blocker; + for (blocker = blocker_range(v).begin(); + blocker != blocker_range(v).end(); + ++blocker + ){ + if (*blocker == sigma) break; + } + if (*blocker != sigma){ + std::cerr << "bug ((*blocker).second == sigma) ie try to remove a blocker not present\n"; + assert(false); + } + else{ + blocker_map_.erase(blocker.current_position()); + } + } + +public: + /** + * Removes the simplex sigma from the set of blockers. + * sigma has to belongs to the set of blockers + */ + void remove_blocker(const Blocker_handle sigma){ + for (auto vertex : *sigma){ + remove_blocker(sigma,vertex); + } + num_blockers_--; + } + + + + + /** + * Remove all blockers, in other words, it expand the simplicial + * complex to the smallest flag complex that contains it. + */ + void remove_blockers(){ + // Desallocate the blockers + while (!blocker_map_.empty()){ + delete_blocker(blocker_map_.begin()->second); + } + num_blockers_ = 0; + blocker_map_.clear(); + } + +protected: + /** + * Removes the simplex sigma from the set of blockers. + * sigma has to belongs to the set of blockers + * + * @remark contrarily to delete_blockers does not call the destructor + */ + void remove_blocker(const Simplex_handle& sigma){ + assert(contains_blocker(sigma)); + for (auto vertex : sigma) + remove_blocker(sigma,vertex); + num_blockers_--; + } + + + + +public: + /** + * Removes the simplex s from the set of blockers + * and desallocate s. + */ + void delete_blocker(Blocker_handle sigma){ + if (visitor) visitor->on_delete_blocker(sigma); + remove_blocker(sigma); + delete sigma; + } + + + /** + * @return true iff s is a blocker of the simplicial complex + */ + bool contains_blocker(const Blocker_handle s) const{ + if (s->dimension()<2) + return false; + + Vertex_handle a = s->first_vertex(); + + for (auto blocker : const_blocker_range(a)){ + if ( s == *blocker ) + return true; + } + return false; + } + + /** + * @return true iff s is a blocker of the simplicial complex + */ + bool contains_blocker(const Simplex_handle & s) const{ + if (s.dimension()<2) + return false; + + Vertex_handle a = s.first_vertex(); + + for (auto blocker : const_blocker_range(a)){ + if ( s == *blocker ) + return true; + } + return false; + } + + +private: + /** + * @return true iff a blocker of the simplicial complex + * is a face of sigma. + */ + bool blocks(const Simplex_handle & sigma) const{ + + for(auto blocker : const_blocker_range()){ + if ( sigma.contains(*blocker) ) + return true; + } + return false; + } + + //@} + + + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Neighbourhood access + */ + //@{ + +public: + /** + * @brief Adds to simplex n the neighbours of v: + * \f$ n \leftarrow n \cup N(v) \f$. + * + * If keep_only_superior is true then only vertices that are greater than v are added. + */ + virtual void add_neighbours(Vertex_handle v, Simplex_handle & n,bool keep_only_superior=false) const{ + boost_adjacency_iterator ai, ai_end; + for (tie(ai, ai_end) = adjacent_vertices(v.vertex, skeleton); ai != ai_end; ++ai){ + if (keep_only_superior){ + if (*ai>v.vertex) + n.add_vertex(Vertex_handle(*ai)); + } + else + n.add_vertex(Vertex_handle(*ai)); + } + } + + /** + * @brief Add to simplex res all vertices which are + * neighbours of alpha: ie \f$ res \leftarrow res \cup N(alpha) \f$. + * + * If 'keep_only_superior' is true then only vertices that are greater than alpha are added. + * + * todo revoir + * + */ + virtual void add_neighbours(const Simplex_handle &alpha, Simplex_handle & res,bool keep_only_superior=false) const{ + res.clear(); + // ---------------------------- + // Compute vertices in the link + // we compute the intersection of N(alpha_i) and store it in n + // ---------------------------- + auto alpha_vertex = alpha.begin(); + add_neighbours(*alpha_vertex,res,keep_only_superior); + for (alpha_vertex = (alpha.begin())++ ; alpha_vertex != alpha.end() ; ++alpha_vertex) + { + keep_neighbours(*alpha_vertex,res,keep_only_superior); + } + } + + /** + * @brief Eliminates from simplex n all vertices which are + * not neighbours of v: \f$ res \leftarrow res \cap N(v) \f$. + * + * If 'keep_only_superior' is true then only vertices that are greater than v are keeped. + * + */ + virtual void keep_neighbours(Vertex_handle v, Simplex_handle& res,bool keep_only_superior=false) const{ + Simplex_handle nv; + add_neighbours(v,nv,keep_only_superior); + res.intersection(nv); + } + + /** + * @brief Eliminates from simplex n all vertices which are + * neighbours of v: \f$ res \leftarrow res \setminus N(v) \f$. + * + * If 'keep_only_superior' is true then only vertices that are greater than v are added. + * + */ + virtual void remove_neighbours(Vertex_handle v, Simplex_handle & res,bool keep_only_superior=false) const{ + Simplex_handle nv; + add_neighbours(v,nv,keep_only_superior); + res.difference(nv); + } + //@} + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Operations on the simplicial complex + */ + //@{ +public: + + /** + * @brief Compute the local vertices of 's' in the current complex + * If one of them is not present in the complex then the return value is uninitialized. + * + * xxx rename get_address et place un using dans sub_complex + */ + boost::optional<Simplex_handle> get_simplex_address(const Root_simplex_handle& s) const + { + boost::optional<Simplex_handle> res; + + Simplex_handle s_address; + //Root_simplex_const_iterator i; + for (auto i = s.begin() ; i != s.end() ; ++i) + { + boost::optional<Vertex_handle> address = get_address(*i); + if (!address) + return res; + else + s_address.add_vertex(*address); + } + res = s_address; + return res; + } + + /** + * @brief returns a simplex with vertices which are the id of vertices of the + * argument. + */ + Root_simplex_handle get_id(const Simplex_handle& local_simplex) const{ + Root_simplex_handle global_simplex; + for (auto x = local_simplex.begin(); x!= local_simplex.end();++x){ + global_simplex.add_vertex(get_id(*x)); + + } + return global_simplex; + + } + + + /** + * @brief returns true iff the simplex s belongs to the simplicial + * complex. + */ + virtual bool contains(const Simplex_handle & s) const{ + if (s.dimension() == -1 ) return false; + else + if (s.dimension() ==0 ){ + return contains_vertex(s.first_vertex()); + } + else + return ( contains_edges(s) && !blocks(s) ); + } + + /* + * @brief returnrs true iff the complex is empty. + */ + bool empty() const{ + return num_vertices()==0; + } + + /* + * @brief returns the number of vertices in the complex. + */ + int num_vertices() const{ + //remark boost::num_vertices(skeleton) counts deactivated vertices + return num_vertices_; + } + + /* + * @brief returns the number of edges in the complex. + * todo in O(n), cache the value + */ + int num_edges() const{ + return boost::num_edges(skeleton); + } + + /* + * @brief returns the number of blockers in the complex. + */ + int num_blockers() const{ + return num_blockers_; + } + + /* + * @brief returns true iff the graph of the 1-skeleton of the complex is complete. + */ + bool complete() const{ + return (num_vertices()*(num_vertices()-1))/2 == num_edges(); + } + + /** + * @brief returns the number of connected components in the graph of the 1-skeleton. + */ + int num_connected_components() const{ + int num_vert_collapsed = skeleton.vertex_set().size() - num_vertices(); + std::vector<int> component(skeleton.vertex_set().size()); + return boost::connected_components(this->skeleton,&component[0]) - num_vert_collapsed; + } + + + //todo remove + // do + void keep_only_largest_cc(){ + std::vector<unsigned> component(skeleton.vertex_set().size()); + boost::connected_components(this->skeleton,&component[0]); + auto maxCC = min_element(component.begin(),component.end()); + for (unsigned i = 0; i != component.size(); ++i){ + if(component[i]!=*maxCC){ + if(this->contains_vertex(Vertex_handle(i))) + this->remove_vertex(Vertex_handle(i)); + } + } + } + + + /** + * @brief %Test if the complex is a cone. + * @details Runs in O(n) where n is the number of vertices. + */ + bool is_cone() const{ + if (num_vertices()==0) return false; + if (num_vertices()==1) return true; + for(auto vi : vertex_range()){ + //xxx todo faire une methode bool is_in_blocker(Vertex_handle) + if (blocker_map_.find(vi)==blocker_map_.end()){ + // no blocker passes through the vertex, we just need to + // check if the current vertex is linked to all others vertices of the complex + if (degree_[vi.vertex] == num_vertices()-1) + return true; + } + } + return false; + } + + //@} + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Vertex iterators + */ + //@{ + + typedef Complex_vertex_iterator<Skeleton_blocker_complex> CVI; //todo rename + + // /** + // * @brief Range over the vertices of the simplicial complex. + // * Methods .begin() and .end() return a Complex_vertex_iterator. + // */ + typedef boost::iterator_range < Complex_vertex_iterator<Skeleton_blocker_complex> > Complex_vertex_range; + + /** + * @brief Returns a Complex_vertex_range over all vertices of the complex + */ + Complex_vertex_range vertex_range() const + { + auto begin = Complex_vertex_iterator<Skeleton_blocker_complex>(this); + auto end = Complex_vertex_iterator<Skeleton_blocker_complex>(this,0); + return Complex_vertex_range(begin,end); + } + + typedef boost::iterator_range < Complex_neighbors_vertices_iterator<Skeleton_blocker_complex> > Complex_neighbors_vertices_range; + + /** + * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes trough v + */ + Complex_neighbors_vertices_range vertex_range(Vertex_handle v) const + { + auto begin = Complex_neighbors_vertices_iterator<Skeleton_blocker_complex>(this,v); + auto end = Complex_neighbors_vertices_iterator<Skeleton_blocker_complex>(this,v,0); + return Complex_neighbors_vertices_range(begin,end); + } + + //@} + + + /** @name Edge iterators + */ + //@{ + + + typedef boost::iterator_range <Complex_edge_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>> + Complex_edge_range; + + /** + * @brief Returns a Complex_edge_range over all edges of the simplicial complex + */ + Complex_edge_range edge_range() const + { + auto begin = Complex_edge_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>(this); + auto end = Complex_edge_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>(this,0); + return Complex_edge_range(begin,end); + } + + + + typedef boost::iterator_range <Complex_edge_around_vertex_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>> + Complex_edge_around_vertex_range; + /** + * @brief Returns a Complex_edge_range over all edges of the simplicial complex that passes + * through 'v' + */ + Complex_edge_around_vertex_range edge_range(Vertex_handle v) const + { + auto begin = Complex_edge_around_vertex_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>(this,v); + auto end = Complex_edge_around_vertex_iterator<Skeleton_blocker_complex<SkeletonBlockerDS>>(this,v,0); + return Complex_edge_around_vertex_range(begin,end); + } + + + + //@} + + + /** @name Triangles iterators + */ + //@{ +private: + typedef Skeleton_blocker_link_complex<Skeleton_blocker_complex<SkeletonBlockerDS> > Link; + typedef Skeleton_blocker_link_superior<Skeleton_blocker_complex<SkeletonBlockerDS> > Superior_link; +public: + typedef Triangle_around_vertex_iterator<Skeleton_blocker_complex,Superior_link> Superior_triangle_around_vertex_iterator; + + typedef boost::iterator_range < Triangle_around_vertex_iterator<Skeleton_blocker_complex,Link> > Complex_triangle_around_vertex_range; + + /** + * @brief Range over triangles around a vertex of the simplicial complex. + * Methods .begin() and .end() return a Triangle_around_vertex_iterator. + * + */ + Complex_triangle_around_vertex_range triangle_range(Vertex_handle v) const + { + auto begin = Triangle_around_vertex_iterator<Skeleton_blocker_complex,Link>(this,v); + auto end = Triangle_around_vertex_iterator<Skeleton_blocker_complex,Link>(this,v,0); + return Complex_triangle_around_vertex_range(begin,end); + } + + + typedef boost::iterator_range<Triangle_iterator<Skeleton_blocker_complex> > Complex_triangle_range; + + /** + * @brief Range over triangles of the simplicial complex. + * Methods .begin() and .end() return a Triangle_around_vertex_iterator. + * + */ + Complex_triangle_range triangle_range() const + { + auto end = Triangle_iterator<Skeleton_blocker_complex>(this,0); + if(empty()){ + return Complex_triangle_range(end,end); + } + else{ + auto begin = Triangle_iterator<Skeleton_blocker_complex>(this); + return Complex_triangle_range(begin,end); + } + + } + + + //@} + + + + /** @name Simplices iterators + */ + //@{ + typedef Simplex_around_vertex_iterator<Skeleton_blocker_complex,Link> Complex_simplex_around_vertex_iterator; + + /** + * @brief Range over the simplices of the simplicial complex around a vertex. + * Methods .begin() and .end() return a Complex_simplex_around_vertex_iterator. + */ + typedef boost::iterator_range < Complex_simplex_around_vertex_iterator > Complex_simplex_around_vertex_range; + + /** + * @brief Returns a Complex_simplex_around_vertex_range over all the simplices around a vertex of the complex + */ + Complex_simplex_around_vertex_range simplex_range(Vertex_handle v) const + { + assert(contains_vertex(v)); + return Complex_simplex_around_vertex_range( + Complex_simplex_around_vertex_iterator(this,v), + Complex_simplex_around_vertex_iterator(this,v,true) + ); + } + + // typedef Simplex_iterator<Skeleton_blocker_complex,Superior_link> Complex_simplex_iterator; + typedef Simplex_iterator<Skeleton_blocker_complex> Complex_simplex_iterator; + + typedef boost::iterator_range < Complex_simplex_iterator > Complex_simplex_range; + + Complex_simplex_range simplex_range() const + { + Complex_simplex_iterator end(this,true); + if(empty()){ + return Complex_simplex_range(end,end); + } + else{ + Complex_simplex_iterator begin(this); + return Complex_simplex_range(begin,end); + } + } + + + //@} + + + /** @name Blockers iterators + */ + //@{ +private: + /** + * @brief Iterator over the blockers adjacent to a vertex + */ + typedef Blocker_iterator_around_vertex_internal< + typename std::multimap<Vertex_handle,Simplex_handle *>::iterator, + Blocker_handle> + Complex_blocker_around_vertex_iterator; + + /** + * @brief Iterator over (constant) blockers adjacent to a vertex + */ + typedef Blocker_iterator_around_vertex_internal< + typename std::multimap<Vertex_handle,Simplex_handle *>::const_iterator, + const Blocker_handle> + Const_complex_blocker_around_vertex_iterator; + + typedef boost::iterator_range <Complex_blocker_around_vertex_iterator> Complex_blocker_around_vertex_range; + typedef boost::iterator_range <Const_complex_blocker_around_vertex_iterator> Const_complex_blocker_around_vertex_range; + +public: + + + + Complex_blocker_around_vertex_range blocker_range(Vertex_handle v) + { + auto begin = Complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v)); + auto end = Complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v)); + return Complex_blocker_around_vertex_range(begin,end); + } + + /** + * @brief Returns a Complex_blocker_around_vertex_range over all blockers of the complex adjacent to the vertex v. + */ + Const_complex_blocker_around_vertex_range const_blocker_range(Vertex_handle v) const + { + auto begin = Const_complex_blocker_around_vertex_iterator(blocker_map_.lower_bound(v)); + auto end = Const_complex_blocker_around_vertex_iterator(blocker_map_.upper_bound(v)); + return Const_complex_blocker_around_vertex_range(begin,end); + } + + + + +private: + + /** + * @brief Iterator over the blockers. + */ + typedef Blocker_iterator_internal< + typename std::multimap<Vertex_handle,Simplex_handle *>::iterator, + Blocker_handle> + Complex_blocker_iterator; + + /** + * @brief Iterator over the (constant) blockers. + */ + typedef Blocker_iterator_internal< + typename std::multimap<Vertex_handle,Simplex_handle *>::const_iterator, + const Blocker_handle> + Const_complex_blocker_iterator; + + typedef boost::iterator_range <Complex_blocker_iterator> Complex_blocker_range; + typedef boost::iterator_range <Const_complex_blocker_iterator> Const_complex_blocker_range; + + +public: + + + Complex_blocker_range blocker_range() + { + auto begin = Complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end() ); + auto end = Complex_blocker_iterator(blocker_map_.end() , blocker_map_.end() ); + return Complex_blocker_range(begin,end); + } + + + Const_complex_blocker_range const_blocker_range() const + { + auto begin = Const_complex_blocker_iterator(blocker_map_.begin(), blocker_map_.end() ); + auto end = Const_complex_blocker_iterator(blocker_map_.end() , blocker_map_.end() ); + return Const_complex_blocker_range(begin,end); + } + + + + + //@} + + + + + + ///////////////////////////////////////////////////////////////////////////// + /** @name Print and IO methods + */ + //@{ +public: + std::string to_string() const{ + std::ostringstream stream; + stream<<num_vertices()<<" vertices:\n"<<vertices_to_string()<<std::endl; + stream<<num_edges()<<" edges:\n"<<edges_to_string()<<std::endl; + stream<<num_blockers()<<" blockers:\n"<<blockers_to_string()<<std::endl; + return stream.str(); + } + + std::string vertices_to_string() const{ + std::ostringstream stream; + for(auto vertex : vertex_range()) + stream << "("<<(*this)[vertex].get_id()<<"),"; + stream<< std::endl; + return stream.str(); + } + + std::string edges_to_string() const{ + std::ostringstream stream; + for(auto edge : edge_range()) + stream << "("<< (*this)[edge].first()<<","<< (*this)[edge].second() << ")"<<" id = "<< (*this)[edge].index()<< std::endl; + stream<< std::endl; + return stream.str(); + } + + + std::string blockers_to_string() const{ + std::ostringstream stream; + for (auto bl:blocker_map_){ + stream << bl.first << " => " << bl.second << ":"<<*bl.second <<"\n"; + } + return stream.str(); + } + + //@} + +}; + + + +/** + * build a simplicial complex from a collection + * of top faces. + */ +template<typename Complex,typename SimplexHandleIterator> +unsigned make_complex_from_top_faces(Complex& complex,SimplexHandleIterator begin,SimplexHandleIterator end){ + typedef typename Complex::Simplex_handle Simplex_handle; + + int dimension = 0; + for(auto top_face = begin; top_face != end; ++top_face) + dimension = std::max(dimension,top_face->dimension()); + + std::vector< std::set<Simplex_handle> > simplices_per_dimension(dimension+1); + + + for(auto top_face = begin; top_face != end; ++top_face){ + register_faces(simplices_per_dimension,*top_face); + } + + // compute list of simplices + std::list<Simplex_handle> simplices; + for(int dim = 0 ; dim <= dimension ; ++dim){ + std::copy( + simplices_per_dimension[dim].begin(), + simplices_per_dimension[dim].end(), + std::back_inserter(simplices) + ); + } + complex = Complex(simplices); + return simplices.size(); +} + + + +} + +} // namespace GUDHI + + + +#endif + |