/* Copyright (c) 1997-2006 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. */ #ifndef _POLYMAKE_BENEATH_BEYOND_H #define _POLYMAKE_BENEATH_BEYOND_H "$Project: polymake $$Id: beneath_beyond.h 7315 2006-04-02 21:37:53Z gawrilow $" #include #include #include #include #include #include #include #include #include #include namespace polymake { namespace polytope { /** Encapsulating the beneath-beyond algorithm. One instance is used to solve exactly one convex-hull problem. @tmplparam E numerical type of the coordinates */ template class beneath_beyond_algo { public: /** The only constructor, initializing the whole stuff. @param points_arg rows are points with homogeneous coordinates @param already_VERTICES_arg true if it is already known that there are no redundant points in the input */ beneath_beyond_algo(const Matrix& points_arg, bool already_VERTICES_arg) : points(points_arg), already_VERTICES(already_VERTICES_arg), generic_position(already_VERTICES_arg), facet_normals_valid(false), AH(unit_matrix(points.cols())), interior_points(!already_VERTICES ? points.rows() : 0), free_facet(-1), vertices_this_step(!already_VERTICES ? points.rows() : 0), interior_points_this_step(!already_VERTICES ? points.rows() : 0) { #ifdef POLY_DEBUG const char *debug_env=getenv("POLY_DEBUG"); if (!debug_env) { debug=do_nothing; } else if (!*debug_env || !strcmp(debug_env, "dump")) { debug=do_dump; } else if (!strcmp(debug_env, "full_dump")) { debug=do_full_dump; } else if (!strcmp(debug_env, "check")) { debug=do_check; } else { throw std::runtime_error(std::string("beneath_beyond_algo - unknown debug keyword: ") + debug_env); } #endif } /** The main and only method which performs the computation. @param perm an end-sensitive input iterator over a sequence of cardinal numbers 0..#points-1 or a permutation thereof. It determines the order in which the points are successively added, and hence the resulting placing triangulation. */ template void compute(Iterator perm); // The rest public methods must be called after compute(); they merely retrieve the computation results. // The names are self-explanatory. Matrix getFacets() const; IncidenceMatrix<> getVertexFacetIncidence() const; Matrix getAffineHull() const; Matrix getVertices() const; Graph<> getDualGraph() const; Array< Set > getTriangulation() const; bool getGenericPosition() const; protected: // connects a facet with a triangulation simplex struct incident_simplex { const Set* simplex; // an element of triangulation int opposite_vertex; // the only vertex NOT belonging to the facet incident_simplex(const Set& simplex_arg, int vertex_arg) : simplex(&simplex_arg), opposite_vertex(vertex_arg) { } }; // description of a facet; stored as a node attribute of the dual graph struct facet_info { Vector normal; // normal vector, directed inside the polyhedron E sqr_normal; // sqr(normal) int orientation; // sign(normal * current-point-to-be-added) during one algo step // =0 : facet is incident, <0 : facet is violated (and will die) Set vertices; // ... incident to the facet // simplices from the polytope triangulation contributing to the triangulation of this facet typedef std::list simplex_list; simplex_list simplices; // compute the normal vector etc. assuming the full-dimensional case (Affine Hull is empty) void coord_full_dim(const beneath_beyond_algo&); // compute the normal vector etc. in the low-dimensional case void coord_low_dim(const beneath_beyond_algo&); // check the intersection of triangulation simplices from [s, s_end) with the facet, // include those with a (d-1)-face ompletely belonging to the facet in its simplex_list template void add_incident_simplices(Iterator s, Iterator s_end); // enables efficient memory management in the dual graph friend void relocate(facet_info* from, facet_info* to) { pm::relocate(&from->normal, &to->normal); pm::relocate(&from->sqr_normal, &to->sqr_normal); to->orientation=from->orientation; pm::relocate(&from->vertices, &to->vertices); pm::relocate(&from->simplices, &to->simplices); } }; const Matrix& points; bool already_VERTICES, generic_position, facet_normals_valid; // the node attributes are facet descriptions // the edge attributes are ridges, that is, vertices incident to both facets typedef Graph > DualGraph; DualGraph dual_graph; ListMatrix< SparseVector > AH, // affine hull facet_nullspace; // its affine nullspace - is not computed as long as // the consumed input vertices comprise a simplex Bitset interior_points, // indices of points which are not vertices active_facets; typedef pm::IndexedSubset&, const Bitset&> ActiveFacets; typedef std::list< Set > Triangulation; Triangulation triangulation; int triang_size; // = triangulation.size(); int valid_facet, // a facet where to start the visibility border search free_facet; // head of a list of empty (deleted) facets to be recycled // These are working variables valid within one algo step. // We define them as instance variables nevertheless to avoid the repeating allocation and deallocation. Bitset vertices_this_step, // points proved to be non-redundant interior_points_this_step, // points that could be redundant visited_facets; // facets seen // accumulates the non-redundant points; is filled until the polytope turns out to be full-dimensional Set vertices_so_far; // get an index of a new facet. // May force the dual graph to resize, invalidating all references to node attributes! int new_facet(); // release the most resources in the facet description, put it into recycling list void delete_facet(int f); /// create the start configuration: a line segment connecting two points /// @param p1,p2 row indices in the points matrix void start_with_points(int p1, int p2); // add the next point, given by the row index. // Recalculates the affine hull. If its dimension did not decrease, delegates the rest work to add_point_full_dim() void add_point_low_dim(int p); // The first phase of the step: looking for a facet violated by point p. If found, calls update_facets() void add_point_full_dim(int p); // helper function for add_point_full_dim int descend_to_violated_facet(int f, int p); // helper function void facet_normals_low_dim(); /// The main phase of the step: detect all facets to be deleted, create new facets and simplices /// @param f the index of the first facet violated by or incident with point p void update_facets(int f, int p); /// The final phase of the step: create new edges in the dual graph /// @param facets facets incident to the point p template void update_dual_graph(FacetSubset facets); #ifdef POLY_DEBUG void dump() const; void dump_p(int p) const; void check_f(int f, int last_p) const; void check_p(int p) const; void check_fp(int f_index, const facet_info& f, int p, std::ostringstream& errors) const; enum debug_kind { do_nothing, do_check, do_dump, do_full_dump }; debug_kind debug; Bitset points_so_far; #endif }; template inline Matrix beneath_beyond_algo::getFacets() const { return Matrix(dual_graph.nodes(), points.cols(), entire(attach_member_accessor(nodes(dual_graph), ptr2type, &facet_info::normal>()))); } template inline Matrix beneath_beyond_algo::getAffineHull() const { return AH; } template inline Matrix beneath_beyond_algo::getVertices() const { return points.minor(~interior_points,All); } template inline IncidenceMatrix<> beneath_beyond_algo::getVertexFacetIncidence() const { IncidenceMatrix<> VIF(dual_graph.nodes(), points.rows(), attach_member_accessor(nodes(dual_graph), ptr2type, &facet_info::vertices>()).begin()); if (already_VERTICES) return VIF; return VIF.minor(All,~interior_points); } template inline Graph<> beneath_beyond_algo::getDualGraph() const { return Graph<>(dual_graph); } template inline Array< Set > beneath_beyond_algo::getTriangulation() const { return Array< Set >(triang_size, triangulation.rbegin()); } template inline bool beneath_beyond_algo::getGenericPosition() const { return generic_position; } } } // end namespace polymake #endif // _POLYMAKE_BENEATH_BEYOND_H // Local Variables: // mode:C++ // c-basic-offset:3 // End: