/* Copyright (c) 1997-2004 Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany) http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de 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 2, or (at your option) any later version: http://www.gnu.org/licenses/gpl.txt. 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. */ #ident "$Project: polymake $$Id: complex_tools.tcc 7477 2006-11-28 22:27:27Z witte $" #include #include #include namespace polymake { namespace topaz { template HasseDiagram hasse_diagram(const Complex& C, const int d, const int end_dim) { // sort facets according to theire dimension Array< std::list > facets_of_dim(d+1); int dim=-1; for (typename Entire::const_iterator c_it=entire(C); !c_it.at_end(); ++c_it) { typename Complex::value_type f=*c_it; while (f.size() > facets_of_dim.size()) facets_of_dim.resize(2*facets_of_dim.size()); if (f.size()-1 > dim) dim = f.size()-1; facets_of_dim[f.size()-1].push_back(f); } // fill the hasse diagram HasseDiagram HD; typename HasseDiagram::_filler HD_filler(HD); HD_filler.add_node(sequence(0,0)); // node #0 is the top node representing the whole complex HD_filler.increase_dim(); int face_end_this_dim=1, face_index=1; if (C.empty()) // if c is empty, the HD is a single node only return HD; FaceMap<> FM; const int last_level= end_dim<0 ? dim + end_dim : end_dim; for (int d=dim; d>=last_level; --d) { // add facets of dimension d int i=face_end_this_dim; for (typename Entire< std::list >::const_iterator f_it=entire(facets_of_dim[d]); !f_it.at_end(); ++f_it, ++i) { HD_filler.add_node(*f_it); HD_filler.add_edge(i,0); } // add faces of dimension d which are not a facet if (d < dim) { while (face_index < face_end_this_dim) { const Subsets_less_1 faces_1_below(HD.node(face_index)); // add faces one below for (typename Entire< Subsets_less_1 >::const_iterator fbi=entire(faces_1_below); !fbi.at_end(); ++fbi) { int &face = FM[*fbi]; if (face==-1) { face=HD_filler.add_node(*fbi); } HD_filler.add_edge(face, face_index); } ++face_index; } } face_end_this_dim=HD.nodes(); HD_filler.increase_dim(); } HD_filler.add_node(sequence(0,0)); // the bottom node (empty face) while (face_index < face_end_this_dim) { HD_filler.add_edge(face_end_this_dim, face_index); ++face_index; } return HD; } template HasseDiagram pure_hasse_diagram(const Complex& C, const int end_dim) { // works for pure complexes only HasseDiagram HD; typename HasseDiagram::_filler HD_filler(HD); HD_filler.add_node(sequence(0,0)); // node #0 is the top node representing the whole complex HD_filler.increase_dim(); if (C.empty()) // if c is empty, the HD is a single node only return HD; const int dim=C.front().size()-1; // add facets of C HD_filler.add_nodes(C.size(), C.begin()); HD_filler.increase_dim(); int face_index=1, face_end_this_dim=C.size()+1; for (int i=1; i FM; const int last_level= end_dim<0 ? dim + end_dim : end_dim; for (int d=dim-1; d>=last_level; --d) { while (face_index < face_end_this_dim) { const Subsets_less_1 faces_1_below(HD.node(face_index)); // add faces one below for (typename Entire< Subsets_less_1 >::const_iterator fbi=entire(faces_1_below); !fbi.at_end(); ++fbi) { int &face = FM[*fbi]; if (face==-1) { face=HD_filler.add_node(*fbi); } HD_filler.add_edge(face, face_index); } ++face_index; } face_end_this_dim=HD.nodes(); HD_filler.increase_dim(); } HD_filler.add_node(sequence(0,0)); // the bottom node (empty face) while (face_index < face_end_this_dim) { HD_filler.add_edge(face_end_this_dim, face_index); ++face_index; } return HD; } template void remove_facet (HasseDiagram& HD, const GenericSet< _Set,int >& F) { // find the specified facet in the hasse diagram int start_node = -1; for (Entire::iterator it=entire(HD.nodes_of_dim(-1)); !it.at_end(); ++it) if (incl(HD.node(*it),F) == 0) start_node = *it; #ifdef POLY_DEBUG if (start_node == -1) throw std::runtime_error("remove_facet: Given set does not specify a facet.\ninvalid input"); #endif // remove all nodes of the HD that can be reached from start_node only Bitset visited(HD.nodes()); std::list node_queue; Set nodes_2B_removed; node_queue.push_back(start_node); visited+=start_node; HD.out_edges(start_node).clear(); while (!node_queue.empty()) { const int n = node_queue.front(); // remove first node from the queue node_queue.pop_front(); if (HD.out_degree(n) == 0) { // node is contained in F only nodes_2B_removed += n; for (typename Entire::in_edge_list>::const_iterator e=entire(HD.in_edges(n)); !e.at_end(); ++e) { const int nn=e.from_node(); if (!visited.contains(nn) && nn!=HD.bottom_node() ) { // nn not been visited yet and nn != bottom node visited += nn; // -> add nn to the queue node_queue.push_back(nn); } } HD.in_edges(n).clear(); } } // remove nodes to be removed HD.delete_nodes(nodes_2B_removed); } template bool adj_numbering (Complex& C, const Set& V) { if (V.empty()) return false; const bool renumber= V.front()!=0 || V.back()+1!=V.size(); if (renumber) { std_ext::hash_map vertex_map(V.size()); int count=0; for (typename Entire< Set >::const_iterator s_it=entire(V); !s_it.at_end(); ++s_it, ++count) vertex_map[*s_it]=count; for (typename Entire::iterator c_it=entire(C); !c_it.at_end(); ++c_it) { typedef typename Complex::value_type Facet; Facet f; for (typename Entire::iterator s_it=entire(*c_it); !s_it.at_end(); ++s_it) f += vertex_map[*s_it]; *c_it = f; } } return renumber; } template bool is_pseudo_manifold (const HasseDiagram& HD, OutputIterator boundary_consumer, const bool verbose) { if (HD.in_edges(HD.top_node()).empty()) return true; int test_dim = -1; for (typename Entire::in_edge_list>::const_iterator it=entire(HD.in_edges(HD.top_node())); !it.at_end(); ++it) { const int n = it.from_node(); if (test_dim == -1) // frist facet test_dim = HD.node(n).size()-1; if ( HD.node(n).size()-1 != test_dim ) { // complex is not pure if (verbose) cout << "is_pseudo_manifold: complex is not PURE." << endl; return false; } } bool is_pmf=true; for (typename Entire::const_iterator it=entire(HD.nodes_of_dim(-2)); !it.at_end(); ++it) { const int d = HD.out_degree(*it); if ( d > 2 ) { if (!verbose) return false; cout << "is_pseudo_manifold: " << HD.node(*it) << " is contained in " << d << ">2 facets." << endl; is_pmf=false; } if (!pm::derived_from_instance::value && d == 1 ) *boundary_consumer++ = HD.node(*it); } return is_pmf; } } } // Local Variables: // mode:C++ // c-basic-offset:3 // End: