Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:19:37

0001 /* This software is distributed under the GNU Lesser General Public License */
0002 //==========================================================================
0003 //
0004 //   planarity.h
0005 //
0006 //==========================================================================
0007 // $Id: planarity.h,v 1.22 2008/02/03 18:17:08 chris Exp $
0008 
0009 #ifndef PLANARITY_H
0010 #define PLANARITY_H
0011 
0012 #include <GTL/GTL.h>
0013 #include <GTL/graph.h>
0014 #include <GTL/algorithm.h>
0015 #include <GTL/st_number.h>
0016 #include <GTL/embedding.h>
0017 #include <GTL/biconnectivity.h>
0018 #include <GTL/pq_node.h>
0019 
0020 __GTL_BEGIN_NAMESPACE
0021 
0022 /**
0023  * $Date: 2008/02/03 18:17:08 $ 
0024  * $Revision: 1.22 $
0025  * 
0026  * @brief Tests if a %graph can be drawn on a plane without any %edge
0027  * crossings 
0028  * 
0029  * This class implements the Lempel-Even-Cederbaum %planarity test using
0030  * PQ-trees. In case the %graph is planar a planar embedding is obtained,
0031  * i.e. for each %node in the %graph an ordered adjacency list is calculated,
0032  * such that there exists a planar drawing in which all adjacent edges
0033  * around a %node apply to this order.
0034  *
0035  * If the %graph is not planar Kuratowski's famous theorem states that it
0036  * must contain a subgraph hoemeomorphic to either K5 (the complete %graph
0037  * with five nodes) or K3,3 (the complete bipartite %graph with three nodes
0038  * each side).  In this case the nodes and edges of the tested %graph that
0039  * form either of these two are calculated.
0040  *
0041  * In case the %graph is planar and has @f$N@f$ nodes the algorithm needs
0042  * @f$\mathcal{O}(N)@f$ time for the test (including the planar embedding).
0043  * In case the %graph isn't planar it needs at most @f$\mathcal{O}(E)@f$
0044  * time if @f$E@f$ is the number of edges for both the test and the
0045  * detection of K5 or K3,3.
0046  */
0047 class GTL_EXTERN planarity : public algorithm 
0048 {
0049 public:
0050     /**
0051      * @brief Creates an object of the planarity test %algorithm.
0052      *
0053      * @sa algorithm
0054      */
0055     planarity();
0056     
0057     /**
0058      * @brief Destructor
0059      */
0060     ~planarity();
0061 
0062     /**
0063      * @brief Checks whether planarity test can be applied to @p G.
0064      * 
0065      * This should return always @c GTL_OK. There aren't any
0066      * restrictions on @p G, even multiple edges and selfloops
0067      * are tolerated. 
0068      * 
0069      * @note Selfloops and multiple edges will not be added to
0070      * the planar embedding. planar_embedding::selfloops and
0071      * planar_embedding::multiple_edges can be used to get
0072      * these.
0073      *
0074      * @param G arbitrary %graph
0075      *
0076      * @retval GTL_OK if %planarity test can be applied
0077      * @retval GTL_ERROR if not
0078      *
0079      * @sa algorithm#check
0080      */
0081     int check(graph& G);
0082     
0083     /**
0084      * @brief Runs planarity test on @p G.
0085      * 
0086      * This should return always @c GTL_OK. The return value only
0087      * tracks errors that might occur, it is definitly @em not
0088      * the result of the test itself. The result of the test is
0089      * stored in a member variable and can be accessed via
0090      * #is_planar.
0091      *
0092      * @param G arbitrary %graph
0093      *
0094      * @retval GTL_OK if %planarity test was sucessfully applied 
0095      * @retval GTL_ERROR if not
0096      *
0097      * @sa algorithm::run
0098      */
0099     int run(graph& G);
0100     
0101     /**
0102      * @brief Resets algorithm object, such that it can  be applied to
0103      * another graph.
0104      *
0105      * @sa algorithm::reset
0106      */
0107     void reset();
0108     
0109     /**
0110      * @brief If @p p is true a planar embedding will be calculated in 
0111      * the next run. 
0112      *  
0113      * @param p @c true iff embedding should be calculated
0114      *
0115      * @sa #get_embedding
0116      * @sa planar_embedding
0117      */
0118     void calc_embedding(bool p)
0119     {
0120     emp = p;
0121     if (!emp) kup = false;
0122     }
0123 
0124     /** 
0125      * @brief Returns true if a planar embedding will be calculated in 
0126      * the next run.
0127      *  
0128      * @retval true iff embedding will be calculated
0129      *
0130      * @sa #get_embedding
0131      * @sa planar_embedding
0132      */
0133     bool calc_embedding () const
0134     { return emp; }
0135 
0136    /** 
0137      * @brief If @p p is true the obstructions to %planarity will be
0138      * calculated in the next %run. 
0139      * 
0140      * This implies the calculation of an embedding.
0141      *  
0142      * @param p @c true iff obstructions to %planarity should be calculated
0143      *
0144      * @sa #get_obstruction_edges
0145      * @sa #get_obstruction_nodes
0146      */
0147     void calc_obstruction(bool p)
0148     {
0149     kup = p;
0150     if (kup) emp = true;
0151     }
0152 
0153     /**
0154      * @brief Returns true if the obstructions to %planarity will be
0155      * calculated in the next %run. 
0156      *  
0157      * @retval true iff obstructions to %planarity will be calculated
0158      *
0159      * @sa #get_obstruction_edges
0160      * @sa #get_obstruction_nodes
0161      */
0162     bool calc_obstruction() const
0163     {
0164     return kup;
0165     }
0166 
0167     /**
0168      * @brief Determines the strategy used to test a graph which is not
0169      * biconnected.
0170      * 
0171      * If this is enabled the graph will be made biconnected by
0172      * adding some new edges. This is usually faster than testing
0173      * the biconnected components one by one, which is done if
0174      * this option is disabled. By default this is enabled. 
0175      * 
0176      * @note This is not fully tested, i.e. at the moment this
0177      * feature should be used only for the test without embedding
0178      * or kuratowski graphs.
0179      *
0180      * @param p true iff %graph should be made biconnected
0181      *
0182      * @sa biconnectivity::make_biconnected
0183      */ 
0184     void make_biconnected(bool p) 
0185     {
0186     bip = p;
0187     }
0188     
0189     /**
0190      * @brief Returns strategy for testing graphs, which are not
0191      * biconnected.
0192      * 
0193      * @retval true iff graph will be made biconnected before test
0194      *
0195      * @sa biconnectivity#make_biconnected
0196      */
0197     bool make_biconnected() const 
0198     {
0199     return bip;
0200     }
0201 
0202     /**
0203      * @brief Result of last test.
0204      *
0205      * @retval true iff %graph in last %run was planar.
0206      */
0207     bool is_planar() const
0208     {
0209     return planar;
0210     }
0211     
0212     /**
0213      * @brief If %graph in last #run was planar a planar embedding is
0214      * calculated during the reductions. This function gives access to it.
0215      *
0216      * @return planar embedding of %graph in last %run
0217      *
0218      * @sa #calc_embedding
0219      */
0220     planar_embedding& get_embedding()
0221     {
0222     return embedding;
0223     }
0224 
0225     /**
0226      * @brief Returns the edges of a subgraph homeomorphic to
0227      * either K3,3 or K5 if %graph in last %run was not planar.
0228      * 
0229      * @return edges of subgraph homeomorphic to either K3,3 or K5
0230      *
0231      * @sa #get_obstruction_nodes
0232      * @sa #calc_obstruction
0233      */
0234     list<edge>& get_obstruction_edges()
0235     {
0236     return ob_edges;
0237     }
0238 
0239     /**
0240      * @brief Returns the nodes of a subgraph homeomorphic to
0241      * either K3,3 or K5 if %graph in last %run was not planar.
0242      *
0243      * @return nodes of subgraph homeomorphic to either K3,3 or K5
0244      *
0245      * @sa #get_obstruction_edges
0246      * @sa #calc_obstruction
0247      */
0248     list<node>& get_obstruction_nodes()
0249     {
0250     return ob_nodes;
0251     }
0252 private:
0253     /**
0254      * @internal
0255      * Main procedure for planarity test. Assumes @p G to be undirected and
0256      * biconnected. Used to test whether the biconnected components of a
0257      * %graph are planar. 
0258      *
0259      * @param G biconnected, undirected graph
0260      * @param em planar embedding (should be empty)
0261      *
0262      * @retval true if @c G is planar
0263      */ 
0264     bool run_on_biconnected(graph& G, planar_embedding& em);
0265 
0266     /**
0267      * @internal
0268      * Adds the embedding for component @c G to the embedding of the whole
0269      * %graph.
0270      *
0271      * @param G biconnected graph 
0272      * @param em embedding obtained through testing @p G
0273      */
0274     void add_to_embedding(graph& G, planar_embedding& em);
0275 
0276     /**
0277      * @internal
0278      * The so called upward embedding can be obtained from the list of edges
0279      * one gets in the reduction steps of the %algorithm. The only problem
0280      * is that some of these lists may be turned later in the algorithm.
0281      * This procedure corrects the reversions according to the information
0282      * stored in @p dirs.
0283      *
0284      * @param em embedding 
0285      * @param st st-numbers of biconnected %graph
0286      * @param dirs direction indicators obtained after each reduction
0287      */
0288     void correct_embedding(planar_embedding& em,
0289                st_number& st,
0290                node_map<list<direction_indicator> >& dirs);
0291 
0292     /**
0293      * @internal
0294      * After the embedding has been corrected by the above procedure, we
0295      * have a so called upward embedding, this means only the edges leading
0296      * to nodes with smaller st-number than itself are in the adjacency list
0297      * for some node. This procedure extends the upward embedding @p em to a
0298      * full embedding. This is a recursive procedure  (well basically it's a
0299      * DFS starting at the %node with the highest st-number).
0300      *
0301      * @param n current node (used for recursion)
0302      * @param em embedding (at the beginning an upward embedding)
0303      * @param mark marks used nodes in DFS.
0304      * @param upward_begin marks the beginning of the upward embedding 
0305      */
0306     void extend_embedding(
0307     node n,
0308     planar_embedding& em,
0309     node_map<int>& mark,
0310     node_map<symlist<edge>::iterator >& upward_begin);
0311     
0312     /**
0313      * @internal
0314      * Make @p G the component specified in @p it by hiding everything not
0315      * in this subgraph. For the sake of efficiency the whole graph is
0316      * hidden at the beginning and then only what is in this component is 
0317      * restored.
0318      *
0319      * @param G whole graph; partially hidden 
0320      * @param it component to highlight
0321      *
0322      * @sa graph::hide
0323      */
0324     void switch_to_component(graph& G,
0325                  biconnectivity::component_iterator it);
0326  
0327     /**
0328      * @internal
0329      * Main procedure for detecting K5 or K3,3. Many cases have to be taken
0330      * into account so it is split in a lot of subroutines decribed below.
0331      *
0332      * @param G biconnected graph.
0333      * @param st st-numbers of @p G
0334      * @param act node for which the reduction failed 
0335      * @param fail (PQ-) node at which no matching could be applied
0336      * @param failed_at_root @c true iff @p fail is the root of the
0337      *        pertinent subtree.
0338      * @param em planar embedding obtained up to the moment the matchings
0339      *        stopped 
0340      * @param dirs direction indicators obtained up to the moment the
0341      *        matchings stopped
0342      * @param PQ tree
0343      */
0344     void examine_obstruction(graph& G,
0345                  st_number& st,
0346                  node act,
0347                  pq_node* fail,
0348                  bool failed_at_root,
0349                  planar_embedding& em,
0350                  node_map<list<direction_indicator> >& dirs,
0351                  pq_tree* PQ); 
0352 
0353     /**
0354      * @internal
0355      * Calculates a DFS-tree for the so called bush-form for the node with 
0356      * st-number @p stop, i.e. the induced subgraph consisting of all nodes
0357      * with st-number smaller than @p stop and all edges from one of these
0358      * to a higher numbered node lead to a virtual node with that number
0359      * (there may be duplicates).
0360      *
0361      * @param act used in recursion; starts with node numbered 1
0362      * @param mark marks for DFS; initially for all nodes 0
0363      * @param st st-numbers for graph
0364      * @param stop lowest st-number of virtual nodes
0365      * @param to_father stores the edge to predecessor of each node
0366      */
0367     void dfs_bushform(node act,
0368               node_map<int>& mark,
0369               st_number& st,
0370               int stop,
0371               node_map<edge>& to_father);
0372 
0373     
0374     /**
0375      * @internal
0376      * In case the reduction failed at a Q-node the boundary of the
0377      * biconnected component the Q-node represents can be obtained from @p
0378      * em.
0379      * No return value is needed, since all the edges on the boundary are
0380      * added to the obstruction edges (although some of them have to be
0381      * deleted in some cases).
0382      *
0383      * @param n node with lowest st-number in biconnected component 
0384      * @param em planar embedding (at least for this component)
0385      */
0386     void attachment_cycle (node n, planar_embedding& em);
0387 
0388     /**
0389      * @internal
0390      * Marks all neighbors of leaves in the subtree rooted at @p n.
0391      * In some cases where the reduction fails at a Q-node, which is not the
0392      * root of the pertinent subtree, an adjacent edge of the node for which
0393      * the reduction failed, which does not lead to that component has to be
0394      * found.
0395      *
0396      * @param n root of subtree
0397      * @param mark edges in subtree recieve 1, all other are unchanged.
0398      */
0399     void mark_all_neighbors_of_leaves (pq_node* act, node_map<int>& mark);
0400     
0401     /**
0402      * @internal
0403      * Searches one full and one empty leaf beneath @p partial. The join of
0404      * these leaves and the node on the boundary @p v to which @p partial is
0405      * attached is added to the obstruction nodes. All edges that form this
0406      * join are added to the obstruction edges.
0407      *
0408      * @param partial partial %node 
0409      * @param mark nodes already used 
0410      * @param to_father predecessor relation in DFS tree
0411      * @param v node on the boundary 
0412      * @return empty leaf
0413      */
0414     pq_leaf* run_through_partial(q_node* partial,
0415                  node_map<int>& mark,
0416                  node_map<edge>& to_father,
0417                                  node v);
0418 
0419     /**
0420      * @internal
0421      * Uses @p to_father to determine an already marked predecessor.
0422      *
0423      * @param act node
0424      * @param mark nodes already used
0425      * @param to_father predecessor relation in DFS tree
0426      *
0427      * @return marked node
0428      */
0429     node up_until_marked(node act,
0430              node_map<int>& mark,
0431              node_map<edge>& to_father);
0432 
0433     /**
0434      * @internal
0435      * Always uses a adjacent node with higher st-number as predecessor.
0436      * Searches marked predecessor.
0437      *
0438      * @param act node
0439      * @param mark nodes already used
0440      * @param st used to determine predecessor
0441      *
0442      * @return marked node
0443      */
0444     node up_until_marked(node act,
0445              node_map<int>& mark,
0446              st_number& st);
0447 
0448     /**
0449      * @internal
0450      * Assumes that @p n is non empty. Searches full leaf beneath @p n.
0451      *
0452      * @param n (PQ-) node
0453      *
0454      * @return full leaf in subtree of @p n
0455      */
0456     pq_leaf* search_full_leaf (pq_node* n);
0457     
0458     /**
0459      * @internal
0460      * Assumes that @p n is non full. Searches empty leaf beneath @p n.
0461      *
0462      * @param n (PQ-) node
0463      *
0464      * @return empty leaf in subtree of @p n
0465      */
0466     pq_leaf* search_empty_leaf(pq_node* n);
0467 
0468     /**
0469      * @internal
0470      * Reduction failed at a P-%node, which had at least three pertial
0471      * sons.
0472      *
0473      * @param p_fail P-%node at which reduction failed
0474      * @param act node for which reduction failed
0475      * @param _st st-numbers of graph
0476      * @param to_father predecessors in DFS-tree of bushform
0477      * @param G graph tested
0478      */
0479     void case_A(p_node* p_fail,
0480         node act,
0481         st_number& _st,
0482         node_map<edge> to_father,
0483         graph& G);
0484 
0485     /**
0486      * @internal
0487      * Reduction failed at a P-%node, which isn't the root of the pertinent
0488      * subtree and had at least two partial children.
0489      *
0490      * @param p_fail P-%node at which reduction failed
0491      * @param act node for which reduction failed
0492      * @param _st st-numbers of graph
0493      * @param to_father predecessors in DFS-tree of bushform
0494      * @param G graph tested
0495      */
0496     void case_B(p_node* p_fail,
0497         node act,
0498         st_number& _st,
0499         node_map<edge> to_father,
0500         graph& G);
0501 
0502     /**
0503      * @internal
0504      * Reduction failed at a Q-node, such that there exist children a < b <
0505      * c and a and c are both non-empty and b is non-full.
0506      *
0507      * @param nodes nodes on the boundary of @p q_fail to which the sons a,
0508      *        b, c are attached. 
0509      * @param leaves leaves in the subtrees of a, b, c. For a and c full 
0510      *        leaves and an empty one for b.
0511      * @param _st st-numbers of graph
0512      * @param to_father predecessors in DFS-tree of bushform
0513      * @param G graph tested
0514      * @param q_fail Q-node at which reduction failed
0515      */
0516     void case_C(node* nodes,
0517         pq_leaf** leaves,
0518         st_number& _st,
0519         node_map<edge> to_father,
0520         graph& G,
0521         q_node* q_fail);
0522 
0523     /**
0524      * @internal
0525      * Reduction failed at a non-root Q-node, such that there exist children
0526      * a < b < c and a and c are both non-full and b is non-empty.
0527      *
0528      * @param nodes nodes on the boundary of @p q_fail to which the sons a,
0529      *        b, c are attached. 
0530      * @param leaves leaves in the subtrees of a, b, c. For a and c full
0531      *        leaves and an empty one for b.
0532      * @param _st st-numbers of graph
0533      * @param to_father predecessors in DFS-tree of bushform
0534      * @param G graph tested
0535      * @param q_fail Q-node at which reduction failed
0536      */
0537     void case_D(node* nodes,
0538         pq_leaf** leaves,
0539         st_number& _st,
0540         node_map<edge> to_father,
0541         graph& G,
0542         q_node* q_fail);
0543 
0544     /**
0545      * @internal
0546      * Reduction failed at a non-root Q-node which has only two children, 
0547      * both partial.
0548      *
0549      * @param nodes nodes on the boundary of @p q_fail to which the two
0550      *        partial sons are attached. 
0551      * @param leaves two leaves in each subtree of a partial son. One full
0552      *        other empty.
0553      * @param _st st-numbers of graph
0554      * @param to_father predecessors in DFS-tree of bushform
0555      * @param G graph tested
0556      * @param q_fail Q-node at which reduction failed
0557      */
0558     void case_E(node* nodes,
0559         pq_leaf** leaves,
0560         st_number& _st,
0561         node_map<edge> to_father,
0562         graph& G,
0563         q_node* q_fail);
0564 
0565 #ifdef _DEBUG
0566     /**
0567      * @internal
0568      */
0569     void write_bushform(graph& G, st_number& _st, int k, const char* name,
0570                         const node_map<int>& mark, const node_map<edge>& to_father);
0571 
0572     /**
0573      * @internal
0574      */    
0575     void write_node(ostream& os, int id, int label, int mark);
0576 #endif
0577     
0578     /**
0579      * @internal
0580      */
0581     list<edge> ob_edges;
0582     
0583     /**
0584      * @internal
0585      */
0586     list<node> ob_nodes;
0587     
0588     /**
0589      * @internal
0590      */
0591     planar_embedding embedding;
0592     
0593     /**
0594      * @internal
0595      */
0596     bool planar;
0597     
0598     /**
0599      * @internal
0600      */
0601     bool emp;
0602     
0603     /**
0604      * @internal
0605      */
0606     bool kup;
0607     
0608     /**
0609      * @internal
0610      */
0611     bool bip;
0612 };
0613 
0614 __GTL_END_NAMESPACE
0615 
0616 #endif // PLANARITY_H
0617 
0618 //--------------------------------------------------------------------------
0619 //   end of file
0620 //--------------------------------------------------------------------------