![]() |
|
|||
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 //--------------------------------------------------------------------------
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |