1 /* planarity.c - code for planarity testing of undirected graphs.
2 * Method of Boyer and Myrvold, programmed by Paulette Lieby.
3 * The copyright of this program is owned by the Magma project.
4 * Distributed with nauty by permission.
5 ***************************************************************/
6
7 /*
8 * sparseg_adjl.c
9 */
10
11 /*
12 What:
13 *****
14
15 Implementing:
16
17 Some high-level functions on the sparse graph as
18 an adjacency list.
19 In particular, testing if it is planar.
20
21
22
23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
24 authors:
25 ********
26
27 Paulette Lieby (Magma), Brendan McKay (ANU)
28
29 Started October 2001
30 */
31
32 #include "planarity.h"
33
34 #define IF_DEB(x) {}
35 #define IF_VERB(x) {}
36
37
38
39 /* aproto: header embed_graph_protos.h */
40
41
42 #ifndef PLANAR_IN_MAGMA
43 #endif
44
45
46 boolean
sparseg_adjl_plan_and_iso(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int e,int * c,t_ver_sparse_rep ** VR,t_adjl_sparse_rep ** AR,t_embed_sparse_rep ** ER,int * nbr_e_obs)47 sparseg_adjl_plan_and_iso (t_ver_sparse_rep *V, int n, t_adjl_sparse_rep *A,
48 int e, int *c, t_ver_sparse_rep **VR, t_adjl_sparse_rep **AR,
49 t_embed_sparse_rep **ER, int *nbr_e_obs)
50 /*
51 the input graph is given as an adjacency list:
52 V: array of vertices
53 n: size of graph
54 A: adjacency list
55 e: number of edges
56
57 if the graph is planar the embedding is stored in VR and ER;
58 the embedding contains e edges
59 (nbr_e_obs not used)
60
61 if the graph is non planar the obstruction is returned in
62 VR and AR together with the number of edges in nbr_e_obs
63
64 in all cases is also returned the number of components (in c)
65 */
66 {
67 t_dlcl **dfs_tree, **back_edges, **mult_edges;
68 int edge_pos, v, w;
69 boolean ans;
70 t_ver_edge *embed_graph;
71
72 ans = sparseg_adjl_is_planar(V, n, A, c,
73 &dfs_tree, &back_edges, &mult_edges,
74 &embed_graph, &edge_pos, &v, &w);
75
76 if (!ans)
77 {
78 embedg_obstruction(V, A, dfs_tree, back_edges,
79 embed_graph, n, &edge_pos,
80 v, w, VR, AR, nbr_e_obs);
81 }
82 else
83 {
84 embedg_embedding(V, A, embed_graph, n, e, *c, edge_pos, mult_edges,
85 VR, ER);
86 }
87
88 sparseg_dlcl_delete(dfs_tree, n);
89 sparseg_dlcl_delete(back_edges, n);
90 sparseg_dlcl_delete(mult_edges, n);
91 embedg_VES_delete(embed_graph, n);
92
93 return ans;
94 }
95
96
97
98 int *
sparseg_adjl_footprint(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int v)99 sparseg_adjl_footprint (t_ver_sparse_rep *V, int n,
100 t_adjl_sparse_rep *A, int v)
101 /*
102 return v's footprint:
103 an array fp of size n where fp[i] = index of (directed)
104 edge [v, i] in A
105 */
106 {
107 /*
108 note that we won't initialise the array:
109 its subsequent usage doesn't require it
110 */
111 int *fp, e;
112
113 fp = (int *) mem_malloc(sizeof(int) * n);
114
115 if (V[v].first_edge == NIL)
116 /*
117 do nothing
118 */
119 return fp;
120
121 e = V[v].first_edge;
122 while (e != NIL)
123 {
124 fp[A[e].end_vertex] = e;
125 e = A[e].next;
126 }
127
128 return fp;
129 }
130
131
132 void
sparseg_adjl_print(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,boolean user_level)133 sparseg_adjl_print (t_ver_sparse_rep *V, int n,
134 t_adjl_sparse_rep *A, boolean user_level)
135 {
136 int v;
137
138 for (v = 0; v < n; v++)
139 {
140 int next;
141
142 if (user_level)
143 fprintf(stdout, "%d:\t", v + 1);
144 else
145 fprintf(stdout, "%d:\t", v);
146
147 next = V[v].first_edge;
148 while (next != NIL)
149 {
150 if (user_level)
151 fprintf(stdout, "%d ", A[next].end_vertex + 1);
152 else
153 fprintf(stdout, "%d ", A[next].end_vertex);
154
155 next = A[next].next;
156 }
157 fprintf(stdout, "\n");
158 }
159 }
160
161
162
163
164 void
sparseg_adjl_embed_print(t_ver_sparse_rep * V_e,int n,t_adjl_sparse_rep * A,t_embed_sparse_rep * E,boolean user_level)165 sparseg_adjl_embed_print (t_ver_sparse_rep *V_e, int n,
166 t_adjl_sparse_rep *A, t_embed_sparse_rep *E, boolean user_level)
167 /*
168 print the embedding given by E,
169 edges are referred to by their index in A
170
171 and V_e[v].first_edge is the index in E of the first edge
172 (in the embedding's order) incident from v
173
174 note that E is NOT indexed by the same vertices' array
175 that indexes A (at the creation of the sparse graph)
176 */
177 {
178 int v;
179
180 for (v = 0; v < n; v++)
181 {
182 int start, next;
183
184 if (user_level)
185 fprintf(stdout, "%d:\t", v + 1);
186 else
187 fprintf(stdout, "%d:\t", v);
188
189 if (V_e[v].first_edge == NIL)
190 {
191 fprintf(stdout, "\n");
192 continue;
193 }
194 start = next = V_e[v].first_edge;
195
196 if (user_level)
197 fprintf(stdout, "%d ", A[ E[next].in_adjl ].end_vertex + 1);
198 else
199 fprintf(stdout, "%d ", A[ E[next].in_adjl ].end_vertex);
200
201 next = E[next].next;
202
203 while (next != start)
204 /*
205 recall that in E edges are linked into a circular list
206 */
207 {
208 if (user_level)
209 fprintf(stdout, "%d ", A[ E[next].in_adjl ].end_vertex + 1);
210 else
211 fprintf(stdout, "%d ", A[ E[next].in_adjl ].end_vertex);
212
213 next = E[next].next;
214 }
215 fprintf(stdout, "\n");
216 }
217 }
218
219 graph *
sparseg_adjl_to_nauty_graph(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A)220 sparseg_adjl_to_nauty_graph (t_ver_sparse_rep *V, int n, t_adjl_sparse_rep *A)
221 /*
222 write the sparse graph as a nauty graph
223 */
224 {
225 int m, v, e, i;
226 graph *g;
227
228 m = (n + WORDSIZE - 1) / WORDSIZE;
229 g = (graph *) mem_malloc(n * m * sizeof(graph));
230 for (i = (long) m * n; --i >= 0;)
231 g[i] = 0;
232
233 /*
234 we first copy V and A's information into g
235 */
236 for (v = 0; v < n; v++)
237 {
238 e = V[v].first_edge;
239 while (e != NIL)
240 /*
241 A[e].end_vertex is the next neighbour in the list,
242 A[e].next points to the next edge in the list
243 */
244 {
245 if (A[e].end_vertex != v) /* no loops */
246 {
247 ADDELEMENT(GRAPHROW(g, v, m), A[e].end_vertex);
248 }
249 e = A[e].next;
250 }
251 }
252
253 return g;
254 }
255
256
257
258 #if 0
259 t_edge_sparse_rep *
260 sparseg_adjl_edges (t_ver_sparse_rep *V, int n,
261 t_adjl_sparse_rep *A, int e, boolean digraph)
262 /*
263 e is the number of edges
264 */
265 {
266 t_edge_sparse_rep *edges;
267 int m, u, v, pos_e;
268 graph *g;
269
270 edges = (t_edge_sparse_rep *) mem_malloc(sizeof(t_edge_sparse_rep) * e);
271
272 m = (n + WORDSIZE - 1) / WORDSIZE;
273 g = sparseg_adjl_to_nauty_graph(V, n, A);
274
275 pos_e = 0;
276 for (u = 0; u < n; u++)
277 {
278 v = digraph == TRUE ? 0 : u + 1;
279 for (; v < n; v++)
280 {
281 if (ISELEMENT(GRAPHROW(g, u, m), v))
282 {
283 t_edge_sparse_rep edge;
284
285 edge.ends[0] = u;
286 edge.ends[1] = v;
287 edges[pos_e++] = edge;
288 }
289 }
290 }
291 ASSERT(pos_e == e);
292 mem_free(g);
293
294 return edges;
295 }
296 #endif
297
298
299
300 t_edge_sparse_rep *
sparseg_adjl_edges(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int e,boolean digraph)301 sparseg_adjl_edges (t_ver_sparse_rep *V, int n, t_adjl_sparse_rep *A,
302 int e, boolean digraph)
303 /*
304 e is the number of edges
305 */
306 {
307 #if 0
308 t_edge_sparse_rep *edges;
309 int u, v, pos_e, *loops, *foot_print;
310 graph *g;
311
312 loops = (int *) mem_malloc(sizeof(int) * n);
313 for (v = 0; v < n; v++)
314 {
315 loops[v] = 0;
316 }
317
318 edges = (t_edge_sparse_rep *) mem_malloc(sizeof(t_edge_sparse_rep) * e);
319 pos_e = 0;
320
321 foot_print = (int *) mem_malloc(sizeof(int) * n);
322 for (u = 0; u < n; u++)
323 foot_print[u] = NIL;
324
325 for (v = 0; v < n; v++)
326 {
327 int ne;
328 t_edge_sparse_rep edge;
329
330 ne = V[v].first_edge;
331 while (ne != NIL)
332 {
333 u = A[ne].end_vertex;
334 if (digraph
335 || (!digraph && u > v))
336 {
337 foot_print[u] = v;
338 }
339 else if (!digraph && u == v)
340 {
341 if (loops[v] == 0)
342 {
343 foot_print[u] = v;
344 }
345
346 loops[v] ^= 1;
347 }
348
349 ne = A[ne].next;
350 }
351
352 for (u = 0; u < n; u++)
353 if (foot_print[u] == v)
354 {
355 edge.ends[0] = v;
356 edge.ends[1] = u;
357 edges[pos_e++] = edge;
358 }
359 }
360 ASSERT(pos_e == e);
361 mem_free(loops);
362 mem_free(foot_print);
363
364 return edges;
365
366 #endif
367 /*
368 there must be a simpler way
369 */
370 #if 0
371 typedef struct edge_list {
372 int size;
373 t_edge_sparse_rep *edges;
374 } t_edge_list;
375
376 t_edge_list *edge_table;
377 t_edge_sparse_rep *edges;
378 int u, v, nbr_e, pos_e, *loops;
379 graph *g;
380
381 loops = (int *) mem_malloc(sizeof(int) * n);
382 for (v = 0; v < n; v++)
383 {
384 loops[v] = 0;
385 }
386
387 /*
388 now create an edge table as follows:
389 - there are n lists in total
390 - their respective size is given by size
391 - their contents by *edges:
392
393 edge_table[i] will contain all the edges whose end-point is i:
394 these edges, by construction, will be sorted according to their
395 starting point
396
397 what for? to finish off each start-vertex processing
398 with a bucket sort so that
399 the edges are sorted wrt start- & end-point
400
401 bucket sort is linear, hence why...
402 */
403 edge_table = (t_edge_list *) mem_malloc(sizeof(t_edge_list) * n);
404 for (v = 0; v < n; v++)
405 {
406 edge_table[v].size = 0;
407 edge_table[v].edges = NP;
408 }
409
410 edges = (t_edge_sparse_rep *) mem_malloc(sizeof(t_edge_sparse_rep) * e);
411
412 nbr_e = 0;
413 pos_e = 0;
414 for (v = 0; v < n; v++)
415 {
416 int ne, w, u;
417
418 ne = V[v].first_edge;
419 while (ne != NIL)
420 {
421 u = A[ne].end_vertex;
422 if (digraph
423 || (!digraph && u > v))
424 {
425 t_edge_sparse_rep edge;
426
427 edge.ends[0] = v;
428 edge.ends[1] = u;
429
430 /*
431 now stick this edge into the table: one may ponder
432 as to the cost of constantly reallocating memory...
433 some cursory tests in another context tell me that
434 this is pretty much ok
435 (and certainly better than allocating n^2 storage space)
436 */
437 if (edge_table[u].size == 0)
438 {
439 edge_table[u].edges = (t_edge_sparse_rep *)
440 mem_malloc(sizeof(t_edge_sparse_rep));
441 }
442 else
443 {
444 edge_table[u].edges = (t_edge_sparse_rep *)
445 mem_realloc(edge_table[u].edges,
446 sizeof(t_edge_sparse_rep)
447 * (edge_table[u].size + 1));
448 }
449
450 (edge_table[u].edges)[edge_table[u].size] = edge;
451 edge_table[u].size += 1;
452 nbr_e++;
453 }
454 else if (!digraph && u == v)
455 {
456 if (loops[v] == 0)
457 {
458 t_edge_sparse_rep edge;
459
460 edge.ends[0] = v;
461 edge.ends[1] = u;
462
463 if (edge_table[u].size == 0)
464 {
465 edge_table[u].edges = (t_edge_sparse_rep *)
466 mem_malloc(sizeof(t_edge_sparse_rep));
467 }
468 else
469 {
470 edge_table[u].edges = (t_edge_sparse_rep *)
471 mem_realloc(edge_table[u].edges,
472 sizeof(t_edge_sparse_rep)
473 * (edge_table[u].size + 1));
474 }
475
476 (edge_table[u].edges)[edge_table[u].size] = edge;
477 edge_table[u].size += 1;
478 nbr_e++;
479 }
480
481 loops[v] ^= 1;
482 }
483
484 ne = A[ne].next;
485 }
486
487 /*
488 bucket sort must take place here:
489 of course the whole lot is not exactly linear!
490 since we perform the sort n times; but we can hope for
491 a "good" ?? average behaviour:
492
493 in any case this must be better that checking adjacencies
494 n^2 times in a sparse rep. (see edge_set_iset_assure)
495 */
496 for (w = 0; w < n; w++)
497 {
498 if (edge_table[w].size > 0)
499 {
500 for (u = 0; u < edge_table[w].size; u++)
501 {
502 ASSERT((edge_table[w].edges)[u].ends[0] == v);
503 edges[pos_e++] = (edge_table[w].edges)[u];
504 }
505 mem_free(edge_table[w].edges);
506 edge_table[w].size = 0;
507 edge_table[w].edges = NP;
508 }
509 }
510 }
511 ASSERT(nbr_e == e);
512 ASSERT(pos_e == e);
513 mem_free(loops);
514 mem_free(edge_table);
515
516 return edges;
517 #endif
518
519 t_edge_sparse_rep *edges;
520 int v, pos_e, *loops;
521
522 edges = (t_edge_sparse_rep *) mem_malloc(sizeof(t_edge_sparse_rep) * e);
523 loops = (int *) mem_malloc(sizeof(int) * n);
524 for (v = 0; v < n; v++)
525 {
526 loops[v] = 0;
527 }
528
529 pos_e = 0;
530 for (v = 0; v < n; v++)
531 {
532 int ne;
533
534 ne = V[v].first_edge;
535 while (ne != NIL)
536 {
537 int u;
538
539 u = A[ne].end_vertex;
540 if (digraph
541 || (!digraph && u > v))
542 {
543 t_edge_sparse_rep edge;
544
545 edge.ends[0] = v;
546 edge.ends[1] = u;
547 edges[pos_e++] = edge;
548 }
549 else if (!digraph && u == v)
550 {
551 if (loops[v] == 0)
552 {
553 t_edge_sparse_rep edge;
554
555 edge.ends[0] = v;
556 edge.ends[1] = u;
557 edges[pos_e++] = edge;
558 }
559
560 loops[v] ^= 1;
561 }
562 ne = A[ne].next;
563 }
564 }
565 ASSERT(pos_e == e);
566 mem_free(loops);
567
568 return edges;
569
570 }
571
572 /*
573 * sparseg_adjl_modify.c
574 */
575
576 /*
577 What:
578 *****
579
580 Implementing:
581
582 Some high-level functions on the sparse graph as
583 an adjacency list.
584 In particular, adding/removing vertices/edges.
585
586
587 NOTE: Most of the functions implicitely assume that the
588 graph is undirected;
589 this must be slightly rewritten for the general case
590 -- just haven't got the time right now...
591
592
593 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
594 authors:
595 ********
596
597 Paulette Lieby (Magma), Brendan McKay (ANU)
598
599 Started October 2001
600 */
601
602 #include "planarity.h"
603
604 #define IF_DEB(x) {}
605 #define IF_VERB(x) {}
606
607
608 /* aproto: header embed_graph_protos.h */
609
610
611
612 #ifndef PLANAR_IN_MAGMA
613 #endif
614
615
616
617 boolean
sparseg_adjl_add_edge(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep ** A,int * size_A,int * pos,int u,int v,boolean CHECK)618 sparseg_adjl_add_edge (t_ver_sparse_rep *V, int n, t_adjl_sparse_rep **A,
619 int *size_A, int *pos, int u, int v, boolean CHECK)
620 /*
621 add the UNDIRECTED edge to the sparse graph (V, n, A)
622 - pos records where to add the next edge in A
623 - if pos + 1 == size_A, we must extend A
624
625 we check if the edge is already in the graph iff CHECK true
626
627 also we assume that the graph (V, n, A) is undirected
628 */
629 {
630 boolean edge_exists;
631
632 edge_exists = FALSE;
633 if (CHECK)
634 {
635 edge_exists = sparseg_adjl_dir_edge_exists(V, n, *A, u, v);
636
637 if (edge_exists)
638 return FALSE;
639 }
640
641 if (*pos == *size_A)
642 {
643 IF_DEB(
644 fprintf(stdout, "realloc \n");
645 )
646
647 *size_A += 2; /* add two directed edges */
648 *A = (t_adjl_sparse_rep *)
649 mem_realloc(*A, sizeof(t_adjl_sparse_rep) * *size_A);
650 }
651 else if (*pos + 1 == *size_A)
652 {
653 IF_DEB(
654 fprintf(stdout, "realloc \n");
655 )
656
657 *size_A += 1; /* add two directed edges */
658 *A = (t_adjl_sparse_rep *)
659 mem_realloc(*A, sizeof(t_adjl_sparse_rep) * *size_A);
660 }
661 ASSERT(*pos + 1 < *size_A);
662
663 sparseg_adjl_add_dir_edge(V, n, A, size_A, pos, u, v, FALSE);
664 sparseg_adjl_add_dir_edge(V, n, A, size_A, pos, v, u, FALSE);
665
666 return TRUE;
667 }
668
669 boolean
sparseg_adjl_add_edge_no_extend(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int size_A,int * pos,int u,int v,boolean CHECK)670 sparseg_adjl_add_edge_no_extend (t_ver_sparse_rep *V, int n,
671 t_adjl_sparse_rep *A, int size_A, int *pos, int u, int v, boolean CHECK)
672 /*
673 like sparseg_adjl_add_edge but here we are guaranteed
674 that pos + 1 < size_A
675 (unless that for some reason we attempt to add
676 an edge which is already there)
677
678 this feature is required when A is part of a Magma block:
679 we do not want to reallocate A here
680 (would be done at a higher level)
681
682 we check if the edge is already in the graph iff CHECK true
683
684 also, we assume that we use this procedur only when dealing
685 with an undirected graph
686 */
687 {
688 boolean edge_added;
689
690 edge_added =
691 sparseg_adjl_add_dir_edge_no_extend(V, n, A, size_A, pos, u, v,
692 CHECK);
693
694 if (edge_added)
695 sparseg_adjl_add_dir_edge_no_extend(V, n, A, size_A, pos, v, u,
696 FALSE);
697
698 return edge_added;
699 }
700
701
702 boolean
sparseg_adjl_add_dir_edge(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep ** A,int * size_A,int * pos,int u,int v,boolean CHECK)703 sparseg_adjl_add_dir_edge (t_ver_sparse_rep *V, int n,
704 t_adjl_sparse_rep **A, int *size_A, int *pos, int u, int v,
705 boolean CHECK)
706 /*
707 add the DIRECTED edge to the sparse graph (V, n, A)
708 - pos records where to add the next edge in A
709 - if pos >= size_A, we must extend A
710
711 we check if the edge is already in the graph iff CHECK true
712 */
713 {
714 boolean edge_exists;
715
716 edge_exists = FALSE;
717 if (CHECK)
718 {
719 edge_exists = sparseg_adjl_dir_edge_exists(V, n, *A, u, v);
720
721 if (edge_exists)
722 return FALSE;
723 }
724
725 if (*pos == *size_A)
726 {
727 *size_A += 1; /* add one directed edge */
728 *A = (t_adjl_sparse_rep *)
729 mem_realloc(*A, sizeof(t_adjl_sparse_rep) * *size_A);
730 }
731 ASSERT(*pos < *size_A);
732
733 sparseg_adjl_add_dir_edge_no_extend(V, n, *A, *size_A, pos, u, v,
734 FALSE);
735
736 return TRUE;
737 }
738
739 boolean
sparseg_adjl_add_dir_edge_no_extend(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int size_A,int * pos,int u,int v,boolean CHECK)740 sparseg_adjl_add_dir_edge_no_extend (t_ver_sparse_rep *V, int n,
741 t_adjl_sparse_rep *A, int size_A, int *pos, int u, int v, boolean CHECK)
742 /*
743 add an edge where A is guaranteed to be be big enough
744 (unless that for some reason we attempt to add
745 an edge which is already there)
746
747 this feature is required when A is part of a Magma block:
748 we do not want to reallocate A here
749 (would be done at a higher level)
750
751 we check if the edge is already in the graph iff CHECK true
752 */
753 {
754 /*
755 given the way V and A represent the graph, it is simplest
756 to add the new edge at the beginning of i's adj. list
757 */
758 int i_v;
759 t_adjl_sparse_rep a;
760
761 if (CHECK && sparseg_adjl_dir_edge_exists(V, n, A, u, v))
762 return FALSE;
763
764 if (*pos >= size_A)
765 DIE();
766
767 /*
768 otherwise always add the edge
769 */
770 i_v = *pos;
771 a.end_vertex = v;
772 a.next = V[u].first_edge;
773 A[(*pos)++] = a;
774 V[u].first_edge = i_v;
775
776 return TRUE;
777 }
778
779
780
781 boolean
sparseg_adjl_remove_edge_no_red(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,int u,int v)782 sparseg_adjl_remove_edge_no_red (t_ver_sparse_rep *V, t_adjl_sparse_rep *A,
783 int u, int v)
784 /*
785 remove the UNDIRECTED edge from sparse graph (V, A)
786 if (u, v) is not an edge then nothing changes (and return FALSE)
787
788 A will be left with "holes"
789 */
790 {
791 sparseg_adjl_remove_dir_edge_no_red(V, A, u, v);
792 return sparseg_adjl_remove_dir_edge_no_red(V, A, v, u);
793 }
794
795
796 boolean
sparseg_adjl_remove_dir_edge_no_red(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,int u,int v)797 sparseg_adjl_remove_dir_edge_no_red (t_ver_sparse_rep *V,
798 t_adjl_sparse_rep *A, int u, int v)
799 /*
800 remove the DIRECTED edge from the sparse graph (V, n, A)
801 if (u, v) is not an edge then nothing changes (and return FALSE)
802
803 A will be left with "holes"
804 */
805 {
806 int cur_e, prev_e;
807
808 cur_e = V[u].first_edge;
809 if (cur_e == NIL)
810 /*
811 (u, v) is not an edge
812 */
813 return FALSE;
814
815 if (A[cur_e].end_vertex == v)
816 {
817 V[u].first_edge = A[cur_e].next;
818 return TRUE; /* done */
819 }
820
821 while (A[cur_e].end_vertex != v)
822 /*
823 if (u, v) is an edge then this loop will terminate
824 */
825 {
826 prev_e = cur_e;
827 cur_e = A[cur_e].next;
828 if (cur_e == NIL)
829 /*
830 (u, v) is not an edge
831 */
832 return FALSE;
833 }
834 ASSERT(A[cur_e].end_vertex == v);
835
836 A[prev_e].next = A[cur_e].next;
837 return TRUE;
838 }
839
840 int
sparseg_adjl_remove_all_dir_edge_no_red(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,int u,int v)841 sparseg_adjl_remove_all_dir_edge_no_red (t_ver_sparse_rep *V,
842 t_adjl_sparse_rep *A, int u, int v)
843 /*
844 remove all DIRECTED edges [u, v] from the non-simple
845 sparse graph (V, n, A)
846 if (u, v) is not an edge then nothing changes;
847 we return the number of edges removed
848
849 A will be left with "holes"
850 */
851 {
852 int cur_e, prev_e, e_removed;
853
854 if (V[u].first_edge == NIL)
855 /*
856 (u, v) is not an edge
857 */
858 return 0;
859
860 e_removed = 0;
861 while (A[V[u].first_edge].end_vertex == v)
862 {
863 V[u].first_edge = A[V[u].first_edge].next;
864 e_removed++;
865
866 if (V[u].first_edge == NIL)
867 return e_removed;
868 }
869 ASSERT(A[V[u].first_edge].end_vertex != v);
870
871 prev_e = V[u].first_edge;
872 cur_e = A[prev_e].next;
873 while (cur_e != NIL)
874 {
875 if (A[cur_e].end_vertex == v)
876 {
877 A[prev_e].next = A[cur_e].next;
878 e_removed++;
879 cur_e = A[cur_e].next;
880 }
881 else
882 {
883 prev_e = cur_e;
884 cur_e = A[cur_e].next;
885 }
886 }
887
888 return e_removed;
889 }
890
891
892
893 void
sparseg_adjl_add_vertices(t_ver_sparse_rep ** V,int n,int nmore)894 sparseg_adjl_add_vertices (t_ver_sparse_rep **V, int n, int nmore)
895 /*
896 add nmore vertices
897 V is assumed to have length n
898 */
899 {
900 *V = (t_ver_sparse_rep *)
901 mem_realloc(*V, sizeof(t_ver_sparse_rep) * (n + nmore));
902
903 sparseg_adjl_add_vertices_no_extend(*V, n, nmore);
904 }
905
906 void
sparseg_adjl_add_vertices_no_extend(t_ver_sparse_rep * V,int n,int nmore)907 sparseg_adjl_add_vertices_no_extend (t_ver_sparse_rep *V, int n, int nmore)
908 /*
909 add nmore vertices,
910 here V is assumed to have length n + nmore (ie V has already
911 been made bigger)
912 */
913 {
914 int v;
915
916 for (v = n; v < n + nmore; v++)
917 {
918 V[v].first_edge = NIL;
919 }
920 }
921
922 void
sparseg_adjl_remove_vertex(t_ver_sparse_rep ** V,int n,t_adjl_sparse_rep * A,int pos_A,int w,int * e)923 sparseg_adjl_remove_vertex (t_ver_sparse_rep **V, int n,
924 t_adjl_sparse_rep *A, int pos_A, int w, int *e)
925 /*
926 V is assumed to have length n: we will reallocate
927 V so that V will have length n-1
928
929 A is occupied from [0..pos-1], A will be left with holes
930
931 we also assume that the graph can have loops and multiple edges;
932 further, we the edge counting implicitely assumes that graph
933 is undirected!!!
934
935 this must be eventually fixed
936 */
937 {
938 int v, nv, edge, loops;
939 t_ver_sparse_rep *new_V;
940
941 /*
942 we first count the loops if any
943 */
944 loops = 0;
945 edge = (*V)[w].first_edge;
946 while (edge != NIL)
947 {
948 loops = A[edge].end_vertex == w ? loops + 1 : loops;
949 edge = A[edge].next;
950 }
951 ASSERT(loops % 2 == 0);
952 loops /= 2;
953
954 /*
955 we recreate the vertices array
956 */
957 new_V = (t_ver_sparse_rep *)
958 mem_malloc(sizeof(t_ver_sparse_rep) * (n - 1));
959
960 for (v = 0, nv = 0; v < n; v++, nv++)
961 {
962 if (v == w)
963 {
964 nv--;
965 }
966 else
967 {
968 new_V[nv].first_edge = (*V)[v].first_edge;
969 }
970 }
971 mem_free(*V);
972 *V = new_V;
973
974 *e -= loops;
975 sparseg_adjl_remove_vertex_no_red(*V, n, A, w, e);
976
977 /*
978 oops! not relabelling vertices can wreck havock!
979 */
980 sparseg_adjl_relabel_vertex(A, pos_A, w);
981 }
982
983 void
sparseg_adjl_remove_vertex_no_red(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int w,int * e)984 sparseg_adjl_remove_vertex_no_red (t_ver_sparse_rep *V, int n,
985 t_adjl_sparse_rep *A, int w, int *e)
986 /*
987 here V has already size n - 1 and has been initialised,
988 all what remains to do is to remove the edges incident
989 from w in A
990
991 A will be left with holes
992 */
993 {
994 int v, nbr_e_removed;
995
996 nbr_e_removed = 0;
997 for (v = 0; v < n - 1; v++)
998 {
999 nbr_e_removed += sparseg_adjl_remove_all_dir_edge_no_red(V, A, v, w);
1000 }
1001
1002 *e= *e - nbr_e_removed;
1003 }
1004
1005 void
sparseg_adjl_relabel_vertex(t_adjl_sparse_rep * A,int pos,int u)1006 sparseg_adjl_relabel_vertex (t_adjl_sparse_rep *A, int pos, int u)
1007 /*
1008 relabel all vertices v > u as v-1
1009 (required when removing a vertex)
1010 */
1011 {
1012 int i;
1013
1014 for (i = 0; i < pos; i++)
1015 {
1016 A[i].end_vertex = A[i].end_vertex > u ?
1017 A[i].end_vertex - 1 : A[i].end_vertex;
1018 }
1019 }
1020
1021 /*
1022 * sparseg_adjl_pred.c
1023 */
1024
1025 /*
1026 What:
1027 *****
1028
1029 Implementing:
1030
1031 Some high-level functions on the sparse graph as
1032 an adjacency list: predicates.
1033
1034
1035 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1036 authors:
1037 ********
1038
1039 Paulette Lieby (Magma), Brendan McKay (ANU)
1040
1041 Started October 2001
1042 */
1043
1044 #include "planarity.h"
1045
1046 #define IF_DEB(x) {}
1047 #define IF_VERB(x) {}
1048
1049
1050
1051 /* aproto: header embed_graph_protos.h */
1052
1053
1054 #ifndef PLANAR_IN_MAGMA
1055 #endif
1056
1057 boolean
sparseg_adjl_dir_edge_exists(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int u,int v)1058 sparseg_adjl_dir_edge_exists (t_ver_sparse_rep *V, int n,
1059 t_adjl_sparse_rep *A, int u, int v)
1060 /*
1061 does the directed edge [u, v] already exist in the graph
1062 */
1063 {
1064 int cur_e, prev_e;
1065
1066 cur_e = V[u].first_edge;
1067 if (cur_e == NIL)
1068 return FALSE;
1069
1070 if (A[cur_e].end_vertex == v)
1071 {
1072 return TRUE;
1073 }
1074
1075 while (A[cur_e].end_vertex != v)
1076 {
1077 prev_e = cur_e;
1078 cur_e = A[cur_e].next;
1079 if (cur_e == NIL)
1080 /*
1081 (u, v) is not an edge
1082 */
1083 return FALSE;
1084 }
1085 ASSERT(A[cur_e].end_vertex == v);
1086 return TRUE;
1087 }
1088
1089
1090
1091 boolean
sparseg_adjl_u_adj_v(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int u,int v)1092 sparseg_adjl_u_adj_v (t_ver_sparse_rep *V, int n, t_adjl_sparse_rep *A,
1093 int u, int v)
1094 /*
1095 is u adj. to v
1096 */
1097 {
1098 return sparseg_adjl_dir_edge_exists(V, n, A, u, v);
1099 }
1100
1101
1102 boolean
sparseg_adjl_sub(t_ver_sparse_rep * V1,int n1,t_adjl_sparse_rep * A1,t_ver_sparse_rep * V2,int n2,t_adjl_sparse_rep * A2)1103 sparseg_adjl_sub (t_ver_sparse_rep *V1, int n1, t_adjl_sparse_rep *A1,
1104 t_ver_sparse_rep *V2, int n2, t_adjl_sparse_rep *A2)
1105 /*
1106 test if the (V1, n1, A1) sparse graph is a subgraph of
1107 the (V2, n2, A2) graph
1108 */
1109 {
1110 int v, *fp, n, bign, i;
1111
1112 n = n1 > n2 ? n2 : n1;
1113 bign = n1 > n2 ? n1 : 0;
1114 fp = (int *) mem_malloc(sizeof(int) * n);
1115 for (i = 0; i < n; i++)
1116 fp[i] = NIL;
1117
1118 for (v = 0; v < n; v++)
1119 {
1120 int ne1, ne2;
1121
1122 ne1 = V1[v].first_edge;
1123 ne2 = V2[v].first_edge;
1124 if (ne1 == NIL)
1125 {
1126 continue;
1127 }
1128 else if (ne2 == NIL)
1129 {
1130 mem_free(fp);
1131 return FALSE;
1132 }
1133
1134 while (ne2 != NIL)
1135 {
1136 int u2;
1137
1138 u2 = A2[ne2].end_vertex;
1139 fp[u2] = v;
1140 ne2 = A2[ne2].next;
1141 }
1142
1143 while (ne1 != NIL)
1144 {
1145 int u1;
1146
1147 u1 = A1[ne1].end_vertex;
1148 if (fp[u1] != v)
1149 {
1150 mem_free(fp);
1151 return FALSE;
1152 }
1153 ne1 = A1[ne1].next;
1154 }
1155 }
1156 mem_free(fp);
1157
1158 for (v = n; v < bign; v++)
1159 /*
1160 those vertices must not be end points of edges:
1161 this chcek is only necessary in the digraph case
1162 */
1163 {
1164 if (V1[v].first_edge != NIL)
1165 return FALSE;
1166 }
1167
1168 return TRUE;
1169 }
1170
1171
1172
1173 boolean
sparseg_adjl_eq(t_ver_sparse_rep * V1,int n1,t_adjl_sparse_rep * A1,t_ver_sparse_rep * V2,int n2,t_adjl_sparse_rep * A2)1174 sparseg_adjl_eq (t_ver_sparse_rep *V1, int n1, t_adjl_sparse_rep *A1,
1175 t_ver_sparse_rep *V2, int n2, t_adjl_sparse_rep *A2)
1176 /*
1177 compare the two sparse graphs (V1, n1, A1) & (V2, n2, A2)
1178 we don't know their number of edges
1179 */
1180 {
1181 if (n1 != n2)
1182 return FALSE;
1183
1184 return sparseg_adjl_sub(V1, n1, A1, V2, n2, A2)
1185 && sparseg_adjl_sub(V2, n2, A2, V1, n1, A1);
1186 }
1187
1188
1189
1190 /*
1191 * sparseg_dlcl_misc.c
1192 */
1193
1194 /*
1195 What:
1196 *****
1197
1198 Implementing:
1199
1200 Housekeeping for an internal sparse graph representation
1201 internal to the planarity tester and obstruction isolator.
1202
1203 This sparse graph consists of an array of doubly linked circular lists
1204 (the neighbour lists for each vertex).
1205
1206
1207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1208 authors:
1209 ********
1210
1211 Paulette Lieby (Magma), Brendan McKay (ANU)
1212
1213 Started October 2001
1214 */
1215
1216 #include "planarity.h"
1217
1218 #define IF_DEB(x) {}
1219 #define IF_VERB(x) {}
1220
1221
1222 /* aproto: header embed_graph_protos.h */
1223
1224 /* aproto: beginstatic -- don't touch this!! */
1225 static boolean sparseg_dlcl_is_present (t_dlcl *, int, t_dlcl **);
1226 /* aproto: endstatic -- don't touch this!! */
1227
1228
1229 #ifndef PLANAR_IN_MAGMA
1230 #endif
1231
1232
1233 void
sparseg_dlcl_delete(t_dlcl ** g,int n)1234 sparseg_dlcl_delete (t_dlcl **g, int n)
1235 {
1236 int i;
1237
1238 for (i = 0; i < n; i++)
1239 {
1240 embedg_dlcl_delete(g[i]);
1241 }
1242 mem_free(g);
1243 }
1244
1245 void
sparseg_dlcl_print(t_dlcl ** g,int n)1246 sparseg_dlcl_print (t_dlcl **g, int n)
1247 {
1248 int i;
1249
1250 for (i = 0; i < n; i++)
1251 {
1252 fprintf(stdout,"%d:\t", i);
1253 embedg_dlcl_print(g[i]);
1254 }
1255 }
1256
1257
1258 static boolean
sparseg_dlcl_is_present(t_dlcl * l,int label,t_dlcl ** p)1259 sparseg_dlcl_is_present (t_dlcl *l, int label, t_dlcl **p)
1260 {
1261 *p = embedg_dlcl_find(l, label);
1262 return *p == NP ? FALSE : TRUE;
1263 }
1264
1265
1266 boolean
sparseg_dlcl_is_adjacent(t_dlcl ** g,int n,int v,int u,t_dlcl ** p)1267 sparseg_dlcl_is_adjacent (t_dlcl **g, int n, int v, int u, t_dlcl **p)
1268 /*
1269 is u adjacent to v
1270 */
1271 {
1272 ASSERT(v >= 0 && v < n && u >= 0 && u < n);
1273 return sparseg_dlcl_is_present(g[v], u, p);
1274 }
1275
1276 void
sparseg_dlcl_append_to_neigh_list(t_dlcl ** g,int n,int v,int u,int in_adjl)1277 sparseg_dlcl_append_to_neigh_list (t_dlcl **g, int n, int v, int u, int in_adjl)
1278 /*
1279 append u to the neighbour list of v
1280 */
1281 {
1282 t_dlcl *u_rec;
1283
1284 u_rec = embedg_dlcl_rec_new(u);
1285 u_rec->in_adjl = in_adjl;
1286 g[v] = embedg_dlcl_rec_append(g[v], u_rec);
1287 }
1288
1289
1290
1291
1292 void
sparseg_dlcl_to_sparseg(t_dlcl ** g,int n,int e,t_ver_sparse_rep ** V,t_adjl_sparse_rep ** A)1293 sparseg_dlcl_to_sparseg (t_dlcl **g, int n, int e,
1294 t_ver_sparse_rep **V, t_adjl_sparse_rep **A)
1295 /*
1296 e is the number of undirected edges of g
1297
1298 convert a dlcl into the standard sparseg rep. as an
1299 adjacency list
1300 */
1301 {
1302 int i_e, v;
1303
1304 *V = (t_ver_sparse_rep *) mem_malloc(sizeof(t_ver_sparse_rep) * n);
1305 *A = (t_adjl_sparse_rep *) mem_malloc(sizeof(t_adjl_sparse_rep) * 2 * e);
1306
1307 for (v = 0; v < n; v++)
1308 (*V)[v].first_edge = NIL;
1309
1310 i_e = 0;
1311 for (v = 0; v < n; v++)
1312 {
1313 t_dlcl *l, *p;
1314
1315 l = p = g[v];
1316 if (!embedg_dlcl_is_empty(p))
1317 {
1318 t_adjl_sparse_rep a;
1319
1320 ASSERT((*V)[v].first_edge == NIL);
1321 (*V)[v].first_edge = i_e;
1322 a.end_vertex = p->info;
1323 a.next = i_e + 1;
1324 (*A)[i_e++] = a;
1325
1326 p = embedg_dlcl_list_next(p);
1327 while (p != l)
1328 {
1329 a.end_vertex = p->info;
1330 a.next = i_e + 1;
1331 (*A)[i_e++] = a;
1332
1333 p = embedg_dlcl_list_next(p);
1334 }
1335
1336 /*
1337 end of list for v
1338 */
1339 (*A)[i_e - 1].next = NIL;
1340 }
1341 }
1342 ASSERT(i_e == 2 * e);
1343 }
1344
1345 boolean
sparseg_dlcl_sub(t_dlcl ** g1,int n1,t_dlcl ** g2,int n2)1346 sparseg_dlcl_sub (t_dlcl **g1, int n1, t_dlcl **g2, int n2)
1347 /*
1348 is g2 a subgraph of g1
1349
1350 I request that both graphs have same order
1351
1352 This is not used anywhere... do we need it???
1353 */
1354 {
1355 int n, v, *fp;
1356
1357 if (n1 != n2)
1358 return FALSE;
1359
1360 n = n1;
1361 fp = (int *) mem_malloc(sizeof(int) * n);
1362 for (v = 0; v < n; v++)
1363 fp[v] = NIL;
1364
1365 for (v = 0; v < n; v++)
1366 {
1367 t_dlcl *l1, *p1, *l2, *p2;
1368
1369 l1 = p1 = g1[v];
1370 l2 = p2 = g2[v];
1371 if (embedg_dlcl_is_empty(p1) && !embedg_dlcl_is_empty(p2))
1372 {
1373 mem_free(fp);
1374 return FALSE;
1375 }
1376 if (embedg_dlcl_is_empty(p2))
1377 {
1378 continue;
1379 }
1380
1381 fp[p1->info] = v;
1382 p1 = embedg_dlcl_list_next(p1);
1383 while (p1 != l1)
1384 {
1385 fp[p1->info] = v;
1386 p1 = embedg_dlcl_list_next(p1);
1387 }
1388
1389 if (fp[p2->info] != v)
1390 {
1391 mem_free(fp);
1392 return FALSE;
1393 }
1394 p2 = embedg_dlcl_list_next(p2);
1395 while (p2 != l2)
1396 {
1397 if (fp[p2->info] != v)
1398 {
1399 mem_free(fp);
1400 return FALSE;
1401 }
1402 }
1403 }
1404 mem_free(fp);
1405
1406 return TRUE;
1407 }
1408 /*
1409 * VES_misc.c
1410 */
1411
1412 /*
1413 What:
1414 *****
1415
1416 Implementing:
1417
1418 All low-level routines for the VES structure:
1419
1420 - the VES structure is solely used within the planarity tester
1421 and obstruction isolator
1422
1423 - it stores vertices, virtual vertices and edges
1424 --more on this later--
1425
1426 - it allows for circular doubly linked lists, hence
1427 enabling us -among other things- to store the
1428 graph embedding if the tester is successful
1429
1430 - basic features:
1431 + the VES has exactly size 2n + 2(3n-5) :
1432 we add at most one more edge than the max for a planar graph
1433 (need to x by 2: we store directed edges)
1434 + a vertex and the edges incident FROM it are linked in a doubly
1435 linked circular list
1436 + where a vertex is inserted between two of its outcoming edges
1437 determines an external face walk for a bicomponent
1438 + the twin edge is more commonly known as the inverse edge
1439 + we have tree and back edges (from the DFS), and short-cut edges
1440 which are added by the tester
1441 -but short-cut edges are added in such a way as to maintain
1442 planarity (in a local sense)
1443 + vertices and edges can be marked (visited for example)
1444 + they have an orientation which must be eventuall recovered
1445 and which is set in the merge_bicomp routine
1446 + vertices are essentially known via their DFI or DFS index
1447 (though their label is stored too)
1448
1449 blah, blah.... later then.
1450 Have a look at embedg_planar_alg_init which initialises the VES
1451 structure
1452
1453
1454 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1455 from
1456
1457 Simplified O(n) Planarity Algorithms (draft)
1458 ************************************
1459
1460 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
1461 Wendy Myrvold wendym@csr.uvic.ca
1462
1463
1464 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1465 authors:
1466 ********
1467
1468 Paulette Lieby (Magma), Brendan McKay (ANU)
1469
1470 Started October 2001
1471 */
1472
1473
1474 #include "planarity.h"
1475
1476 #define IF_DEB(x) {}
1477 #define IF_DEB_SCE(x) {}
1478 #define IF_DEB_PROPER_FACE(x) {}
1479 #define IF_VERB(x) {}
1480
1481
1482 /* aproto: header embed_graph_protos.h */
1483
1484 boolean
embedg_VES_is_vertex(int n,int i)1485 embedg_VES_is_vertex (int n, int i)
1486 /*
1487 is this a vertex
1488 (relative to the "big" array of size 2n + 2(3n-5))
1489 */
1490 {
1491 return i < n ? TRUE : FALSE;
1492 }
1493
1494 boolean
embedg_VES_is_virtual_vertex(int n,int i)1495 embedg_VES_is_virtual_vertex (int n, int i)
1496 /*
1497 is this a virtual vertex
1498 (relative to the "big" array of size 2n + 2(3n-5))
1499
1500 a virtual vertex is a vertex v^c which denotes the
1501 DFS parent of the child c
1502
1503 see embedg_planar_alg_init for more
1504 */
1505 {
1506 return i >= n && i < 2*n ? TRUE : FALSE;
1507 }
1508
1509 boolean
embedg_VES_is_edge(int n,int i)1510 embedg_VES_is_edge (int n, int i)
1511 /*
1512 is this an edge
1513 (relative to the "big" array of size 2n + 2(3n-5))
1514 */
1515 {
1516 return i >= 2*n ? TRUE : FALSE;
1517 }
1518
1519 boolean
embedg_VES_is_tree_edge(t_ver_edge * embed_graph,int n,int i)1520 embedg_VES_is_tree_edge (t_ver_edge *embed_graph, int n, int i)
1521 /*
1522 is this s tree edge
1523 */
1524 {
1525 return embedg_VES_is_edge(n, i)
1526 && embed_graph[i].type == TE;
1527 }
1528
1529 boolean
embedg_VES_is_back_edge(t_ver_edge * embed_graph,int n,int i)1530 embedg_VES_is_back_edge (t_ver_edge *embed_graph, int n, int i)
1531 /*
1532 is this a back edge
1533 */
1534 {
1535 return embedg_VES_is_edge(n, i)
1536 && embed_graph[i].type == BE;
1537 }
1538
1539 boolean
embedg_VES_is_short_cut_edge(t_ver_edge * embed_graph,int n,int i)1540 embedg_VES_is_short_cut_edge (t_ver_edge *embed_graph, int n, int i)
1541 /*
1542 as the name indicates...
1543 */
1544 {
1545 return embedg_VES_is_edge(n, i)
1546 && embed_graph[i].type == SCE;
1547 }
1548
1549 void
embedg_VES_print_vertex(int n,int v)1550 embedg_VES_print_vertex (int n, int v)
1551 {
1552 ASSERT(embedg_VES_is_vertex(n, v));
1553 fprintf(stdout, "%d ", v);
1554 }
1555
1556 void
embedg_VES_print_virtual_vertex(t_ver_edge * embed_graph,int n,int v)1557 embedg_VES_print_virtual_vertex (t_ver_edge *embed_graph, int n, int v)
1558 {
1559 int c;
1560
1561 ASSERT(embedg_VES_is_virtual_vertex(n, v));
1562 c = v - n;
1563 fprintf(stdout, "%d^%d ", embed_graph[c].DFS_parent, c);
1564 }
1565
1566 void
embedg_VES_print_any_vertex(t_ver_edge * embed_graph,int n,int v)1567 embedg_VES_print_any_vertex (t_ver_edge *embed_graph, int n, int v)
1568 {
1569 if (embedg_VES_is_vertex(n, v))
1570 {
1571 embedg_VES_print_vertex(n, v);
1572 }
1573 else
1574 {
1575 embedg_VES_print_virtual_vertex(embed_graph, n, v);
1576 }
1577 }
1578
1579 void
embedg_VES_print_any_rec(t_ver_edge * embed_graph,int n,int r)1580 embedg_VES_print_any_rec (t_ver_edge *embed_graph, int n, int r)
1581 {
1582 if (embedg_VES_is_edge(n, r))
1583 {
1584 embedg_VES_print_edge(embed_graph, n, r);
1585 }
1586 else
1587 {
1588 embedg_VES_print_any_vertex(embed_graph, n, r);
1589 }
1590 }
1591
1592 void
embedg_VES_print_edge(t_ver_edge * embed_graph,int n,int e)1593 embedg_VES_print_edge (t_ver_edge *embed_graph, int n, int e)
1594 {
1595 int v, prev, cur;
1596
1597 ASSERT(embedg_VES_is_edge(n, e));
1598
1599 /*
1600 must find the vertex in the doubly linked circular list
1601 of vertices/edges
1602 */
1603
1604 prev = e;
1605 cur = v = embed_graph[e].link[0];
1606 if (embedg_VES_is_vertex(n, v)
1607 || embedg_VES_is_virtual_vertex(n, v))
1608 {
1609 embedg_VES_print_any_vertex(embed_graph, n, v);
1610 fprintf(stdout, ", ");
1611 embedg_VES_print_any_vertex(embed_graph, n,
1612 embed_graph[e].neighbour);
1613 fprintf(stdout, "):0\n");
1614 }
1615 else while (!embedg_VES_is_vertex(n, v)
1616 && !embedg_VES_is_virtual_vertex(n, v))
1617 {
1618 v = embedg_VES_get_next_in_dlcl(embed_graph, n,
1619 cur, prev);
1620
1621 if (embedg_VES_is_vertex(n, v)
1622 || embedg_VES_is_virtual_vertex(n, v))
1623 {
1624 embedg_VES_print_any_vertex(embed_graph, n, v);
1625 fprintf(stdout, ", ");
1626 embedg_VES_print_any_vertex(embed_graph, n,
1627 embed_graph[e].neighbour);
1628 fprintf(stdout, "):0\n");
1629 }
1630 else
1631 {
1632 prev = cur;
1633 cur = v;
1634 }
1635 }
1636 }
1637
1638 void
embedg_VES_print_flipped_edges(t_ver_edge * embed_graph,int n,int edge_pos)1639 embedg_VES_print_flipped_edges (t_ver_edge *embed_graph, int n, int edge_pos)
1640 /*
1641 print those edges in the structure whose sign is CLOCKW,
1642 ie which have been flipped at some stage
1643 */
1644 {
1645 int e;
1646
1647 for (e = 2*n; e <= edge_pos; e++)
1648 {
1649 if (!embedg_VES_is_short_cut_edge(embed_graph, n, e))
1650 /*
1651 we don't care about the short-cut edges
1652 */
1653 {
1654 if (embed_graph[e].sign != CCLOCKW)
1655 {
1656 embedg_VES_print_edge(embed_graph, n, e);
1657 }
1658 }
1659 }
1660 }
1661
1662 #if 0
1663 int
1664 embedg_VES_get_edge_from_ver (t_ver_edge *embed_graph, int n, int v)
1665 /*
1666 not used anywhere; why is this here???
1667 */
1668 {
1669 int in, e;
1670
1671 ASSERT(embedg_VES_is_vertex(n, v)
1672 || embedg_VES_is_virtual_vertex(n, v));
1673
1674 in = embedg_VES_is_edge(n, embed_graph[v].link[0]) ? 0 : 1;
1675 e = embed_graph[v].link[in];
1676 ASSERT(embedg_VES_is_edge(n, e));
1677
1678 return e;
1679 }
1680
1681 int
1682 embedg_VES_get_ver_from_edge (t_ver_edge *embed_graph, int n, int e)
1683 {
1684 int in, v;
1685
1686 ASSERT(embedg_VES_is_edge(n, e));
1687
1688 in = embedg_VES_is_vertex(n, embed_graph[e].link[0])
1689 || embedg_VES_is_virtual_vertex(n, embed_graph[e].link[0])
1690 ?
1691 0 : 1;
1692
1693 v = embed_graph[e].link[in];
1694 ASSERT(embedg_VES_is_vertex(n, v)
1695 || embedg_VES_is_virtual_vertex(n, v));
1696
1697 return v;
1698 }
1699 #endif
1700
1701 int
embedg_VES_get_twin_edge(t_ver_edge * embed_graph,int n,int e)1702 embedg_VES_get_twin_edge (t_ver_edge *embed_graph, int n, int e)
1703 /*
1704 the twin edge is understood as being the inverse edge
1705 */
1706 {
1707 int twin;
1708
1709 ASSERT(embedg_VES_is_edge(n, e));
1710
1711 twin = e % 2 == 0 ? e + 1 : e - 1;
1712 ASSERT(embedg_VES_is_edge(n, twin));
1713
1714 return twin;
1715 }
1716
1717 int
embedg_VES_get_ver_from_virtual(t_ver_edge * embed_graph,int n,int vv)1718 embedg_VES_get_ver_from_virtual (t_ver_edge *embed_graph, int n, int vv)
1719 /*
1720 get v from the virtual vertex v^c
1721 */
1722 {
1723 int v;
1724
1725 ASSERT(embedg_VES_is_virtual_vertex(n, vv));
1726 v = embed_graph[vv - n].DFS_parent;
1727
1728 return v;
1729 }
1730
1731 int
embedg_VES_get_ver(t_ver_edge * embed_graph,int n,int v)1732 embedg_VES_get_ver (t_ver_edge *embed_graph, int n, int v)
1733 {
1734 if (embedg_VES_is_virtual_vertex(n, v))
1735 return embedg_VES_get_ver_from_virtual(embed_graph, n, v);
1736
1737 return v;
1738 }
1739
1740
1741 int
embedg_VES_get_next_in_dlcl(t_ver_edge * embed_graph,int n,int r,int prev)1742 embedg_VES_get_next_in_dlcl (t_ver_edge *embed_graph, int n, int r, int prev)
1743 /*
1744 r is a (virtual) vertex or edge record in embed_graph:
1745 get the next in the list (formed by the .link[] fields)
1746 in the doubly linked circular list
1747
1748 so that prev != next
1749 -- NOTE: a priori these lists always contain 2 elts at least
1750 so that there shouldn't be any problem...
1751 --> huh? is that true?
1752 */
1753 {
1754 return embed_graph[r].link[0] == prev ?
1755 embed_graph[r].link[1] : embed_graph[r].link[0];
1756 }
1757
1758
1759 void
embedg_VES_walk_bicomp(t_ver_edge * embed_graph,int n,int v,int vin)1760 embedg_VES_walk_bicomp (t_ver_edge *embed_graph, int n, int v, int vin)
1761 /*
1762 walk the external face of the bicomp starting
1763 at VIRTUAL vertex v entered via vin
1764
1765 this of course assumes that the "thing" rooted at
1766 v is a bicomponent -- depending where we are at in the
1767 tester this is not necessarily the case
1768 -- I comment upon this in merge_bicomps.c:
1769 embedg_VES_merge_pertinent_bicomps
1770 */
1771 {
1772 int start, startin, s, sin;
1773
1774 ASSERT(embedg_VES_is_virtual_vertex(n, v));
1775
1776 embedg_VES_print_virtual_vertex(embed_graph, n, v);
1777
1778 s = NIL;
1779 start = v;
1780 startin = vin;
1781 while (s != v)
1782 {
1783 embedg_VES_get_succ_on_ext_face(embed_graph, n, start, startin,
1784 FALSE, 0, &s, &sin);
1785 if (embedg_VES_is_virtual_vertex(n, s))
1786 {
1787 embedg_VES_print_virtual_vertex(embed_graph, n, s);
1788 }
1789 else
1790 {
1791 embedg_VES_print_vertex(n, s);
1792 }
1793 start = s;
1794 startin = sin;
1795 }
1796 fprintf(stdout, "\n");
1797 }
1798
1799 void
embedg_VES_print_adj_list(t_ver_edge * embed_graph,int n,int r,boolean consistent)1800 embedg_VES_print_adj_list (t_ver_edge *embed_graph, int n, int r,
1801 boolean consistent)
1802 /*
1803 print r's adjacency list - r can be a vertex or edge
1804
1805 the boolean <consistent> if true assumes that
1806 the list is consistent (will determine the way we traverse the list)
1807
1808 a priori we should get the same result either way
1809 */
1810 {
1811 if (consistent)
1812 {
1813 int next;
1814
1815 embedg_VES_print_any_rec(embed_graph, n, r);
1816
1817 next = embed_graph[r].link[0];
1818 while (next != r)
1819 {
1820 embedg_VES_print_any_rec(embed_graph, n, next);
1821 next = embed_graph[next].link[0];
1822 }
1823 }
1824 else
1825 {
1826 int prev, cur, next;
1827
1828 embedg_VES_print_any_rec(embed_graph, n, r);
1829
1830 prev = r;
1831 cur = embed_graph[r].link[0];
1832
1833 while (cur != r)
1834 {
1835 embedg_VES_print_any_rec(embed_graph, n, cur);
1836 next = embedg_VES_get_next_in_dlcl(embed_graph, n,
1837 cur, prev);
1838 prev = cur;
1839 cur = next;
1840 }
1841 }
1842 }
1843
1844 boolean
embedg_VES_is_adj_list_consistent(t_ver_edge * embed_graph,int n,int r)1845 embedg_VES_is_adj_list_consistent (t_ver_edge *embed_graph, int n, int r)
1846 /*
1847 checks that r's adjacency list is consistent:
1848 ie, that either traversing it using link[0] always
1849 or traversing it using embedg_VES_get_next_in_dlcl
1850 gives the SAME result
1851 */
1852 {
1853 int *list_link, *list_n_dldl, il, id, i;
1854
1855 list_link = (int *) mem_malloc(sizeof(int) * 2 * n);
1856 list_n_dldl = (int *) mem_malloc(sizeof(int) * 2 * n);
1857 /*
1858 must allocate 2*n space: I could have TE and SCE with same neighbour
1859 (or BE and SCE as well)
1860 */
1861 il = id = -1;
1862
1863 /*
1864 traversing the list via link[0]
1865 */
1866 {
1867 int next;
1868
1869 list_link[++il] = r;
1870
1871 next = embed_graph[r].link[0];
1872 while (next != r)
1873 {
1874 list_link[++il] = next;
1875 next = embed_graph[next].link[0];
1876 }
1877 }
1878
1879 /*
1880 traversing the list using embedg_VES_get_next_in_dlcl
1881 */
1882 {
1883 int prev, cur, next;
1884
1885 list_n_dldl[++id] = r;
1886 prev = r;
1887 cur = embed_graph[r].link[0];
1888
1889 while (cur != r)
1890 {
1891 list_n_dldl[++id] = cur;
1892 next = embedg_VES_get_next_in_dlcl(embed_graph, n,
1893 cur, prev);
1894 prev = cur;
1895 cur = next;
1896 }
1897 }
1898
1899 if (il != id)
1900 {
1901 mem_free(list_link);
1902 mem_free(list_n_dldl);
1903 return FALSE;
1904 }
1905
1906 for (i = 0; i <= il; i++)
1907 {
1908 if (list_link[i] != list_n_dldl[i])
1909 {
1910 mem_free(list_link);
1911 mem_free(list_n_dldl);
1912 return FALSE;
1913 }
1914 }
1915
1916 mem_free(list_link);
1917 mem_free(list_n_dldl);
1918 return TRUE;
1919 }
1920
1921
1922 boolean
embedg_VES_are_adj_lists_consistent(t_ver_edge * embed_graph,int n)1923 embedg_VES_are_adj_lists_consistent (t_ver_edge *embed_graph, int n)
1924 /*
1925 checks that the adjacency list of each vertex is consistent
1926 in the manner of embedg_VES_is_adj_list_consistent
1927 */
1928 {
1929 int i;
1930
1931 /*
1932 it is enough to visit the vertices and virtual vertices only
1933 (I don't think it is enough to do the vertices only --??)
1934 */
1935 for (i = 0; i < 2*n; i++)
1936 if (!embedg_VES_is_adj_list_consistent(embed_graph, n, i))
1937 return FALSE;
1938
1939 return TRUE;
1940 }
1941
1942
1943
1944 void
embedg_VES_remove_edge(t_ver_edge * embed_graph,int n,int e)1945 embedg_VES_remove_edge (t_ver_edge *embed_graph, int n, int e)
1946 /*
1947 remove edge e from the embedding
1948 */
1949 {
1950 int r1, r2, r1out, r2in, twin;
1951
1952 ASSERT(embedg_VES_is_edge(n, e));
1953
1954 IF_DEB_SCE(
1955 fprintf(stdout, "removing an SCE, enter\n");
1956 embedg_VES_print_edge(embed_graph, n, e);
1957 )
1958
1959 r1 = embed_graph[e].link[0];
1960 r2 = embed_graph[e].link[1];
1961
1962 /*
1963 disable e and link r1 and r2 together:
1964 we had r1 -> e -> r2
1965 */
1966 embed_graph[e].link[0] = embed_graph[e].link[1] = e;
1967
1968 r1out = embed_graph[r1].link[0] == e ? 0 : 1;
1969 r2in = embed_graph[r2].link[0] == e ? 0 : 1;
1970
1971 if (r1 == r2)
1972 /*
1973 this I think should never happen, but one never knows...
1974 */
1975 {
1976 embed_graph[r1].link[0] = embed_graph[r1].link[1] = r1;
1977 }
1978 else
1979 {
1980 embed_graph[r1].link[r1out] = r2;
1981 embed_graph[r2].link[r2in] = r1;
1982 }
1983
1984 ASSERT(embedg_VES_is_adj_list_consistent(embed_graph, n, r1));
1985
1986 /*
1987 now we must do a similar thing for the twin
1988 (which must get reomved as well)
1989 */
1990 twin = embedg_VES_get_twin_edge(embed_graph, n, e);
1991
1992 IF_DEB_SCE(
1993 fprintf(stdout, "removing an SCE, the twin\n");
1994 embedg_VES_print_edge(embed_graph, n, twin);
1995 )
1996
1997 r1 = embed_graph[twin].link[0];
1998 r2 = embed_graph[twin].link[1];
1999
2000 embed_graph[twin].link[0] = embed_graph[twin].link[1] = twin;
2001
2002 r1out = embed_graph[r1].link[0] == twin ? 0 : 1;
2003 r2in = embed_graph[r2].link[0] == twin ? 0 : 1;
2004
2005 if (r1 == r2)
2006 {
2007 embed_graph[r1].link[0] = embed_graph[r1].link[1] = r1;
2008 }
2009 else
2010 {
2011 embed_graph[r1].link[r1out] = r2;
2012 embed_graph[r2].link[r2in] = r1;
2013 }
2014
2015 ASSERT(embedg_VES_is_adj_list_consistent(embed_graph, n, r1));
2016 }
2017
2018
2019 void
embedg_VES_set_orientation(t_ver_edge * embed_graph,int n,int * ver_orient)2020 embedg_VES_set_orientation (t_ver_edge *embed_graph, int n, int *ver_orient)
2021 /*
2022 using the vertices' orientation as given in ver_orient
2023 we set the orientation for each edge in the adjacency list
2024 for each vertex
2025
2026 to do this we use the field sign which is NOT needed
2027 anymore by the tester since by the time we call this
2028 function we would have finished with that bit (the tester)
2029
2030 sign is only set when merging bicomps
2031 - even though we'll perform another walkdown when
2032 recovering an obstruction (if any) no bicomp merging will occur,
2033 so we are safe
2034 */
2035 {
2036 int v;
2037
2038 for (v = 0; v < n; v++)
2039 {
2040 int o, e;
2041
2042 o = ver_orient[v];
2043 embed_graph[v].sign = o;
2044
2045 e = embed_graph[v].link[0];
2046
2047 while (e != v)
2048 /*
2049 just as a note: note the way I get the next in the list
2050 here (as opposed to using
2051 embedg_VES_get_next_in_dlcl):
2052 this is because I implicitely assume that
2053 the adjacency lists are consistent
2054
2055 Also note that edges can be SCE, it doesn't really matter
2056 anyway (they may not have been removed yet
2057 -- see the way we recover the obstruction:
2058 embedg_mark_obstruction)
2059 */
2060 {
2061 embed_graph[e].sign = o;
2062 e = embed_graph[e].link[0];
2063 }
2064 }
2065 }
2066
2067
2068 /*
2069 * dlcl_misc.c
2070 */
2071
2072 /*
2073 What:
2074 *****
2075
2076 Implementing:
2077
2078 Housekeeping for a simple doubly linked circular list:
2079 this is a data structure ONLY used WITHIN
2080 the planarity tester and obstruction isolator and is not to be
2081 confused with the VES structure mentionned elsewhere.
2082
2083 The VES structure is an array, while the dlcl one is a list of
2084 pointers.
2085
2086 The dlcl is especially useful as it allows for the storage
2087 of an ordered list.
2088
2089
2090 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2091 from
2092
2093 Simplified O(n) Planarity Algorithms (draft)
2094 ************************************
2095
2096 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
2097 Wendy Myrvold wendym@csr.uvic.ca
2098
2099
2100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2101 authors:
2102 ********
2103
2104 Paulette Lieby (Magma), Brendan McKay (ANU)
2105
2106 Started October 2001
2107 */
2108
2109
2110 #include "planarity.h"
2111
2112 #define IF_DEB(x) {}
2113 #define IF_VERB(x) {}
2114
2115
2116 /* aproto: header embed_graph_protos.h */
2117
2118 /* aproto: beginstatic -- don't touch this!! */
2119 static void embedg_dlcl_rec_free (t_dlcl *);
2120 static void embedg_dlcl_rec_insert_right (t_dlcl *, t_dlcl *);
2121 static void embedg_dlcl_rec_insert_left (t_dlcl *, t_dlcl *);
2122 static void embedg_dlcl_rec_retrieve (t_dlcl *);
2123 static void embedg_dlcl_rec_delete (t_dlcl *);
2124 static boolean embedg_dlcl_is_singleton (t_dlcl *);
2125 /* aproto: endstatic -- don't touch this!! */
2126
2127
2128 #ifndef PLANAR_IN_MAGMA
2129 #endif
2130
2131
2132 t_dlcl *
embedg_dlcl_rec_new(int info)2133 embedg_dlcl_rec_new (int info)
2134 /*
2135 create a new record with info <info> in the global array
2136 to insert in the list
2137 */
2138 {
2139 t_dlcl *r;
2140
2141 r = (t_dlcl *) mem_malloc(sizeof(t_dlcl));
2142 r->info = info;
2143 r->in_adjl = r->twin_in_adjl = NIL;
2144 r->mult = 1;
2145 r->right = r;
2146 r->left = r;
2147 return r;
2148 }
2149
2150 static void
embedg_dlcl_rec_free(t_dlcl * r)2151 embedg_dlcl_rec_free (t_dlcl *r)
2152 /*
2153 free
2154 */
2155 {
2156 mem_free(r);
2157 }
2158
2159 void
embedg_dlcl_rec_print(t_dlcl * r)2160 embedg_dlcl_rec_print (t_dlcl *r)
2161 {
2162 fprintf(stdout,"%d ", r->info);
2163 }
2164
2165 void
embedg_dlcl_print(t_dlcl * l)2166 embedg_dlcl_print (t_dlcl *l)
2167 {
2168 t_dlcl *p = l;
2169
2170 if (!embedg_dlcl_is_empty(p))
2171 {
2172 embedg_dlcl_rec_print(p);
2173 p = embedg_dlcl_list_next(p);
2174 while (p != l)
2175 {
2176 embedg_dlcl_rec_print(p);
2177 p = embedg_dlcl_list_next(p);
2178 }
2179 }
2180 fprintf(stdout,"\n");
2181 }
2182
2183
2184 static void
embedg_dlcl_rec_insert_right(t_dlcl * l,t_dlcl * r)2185 embedg_dlcl_rec_insert_right (t_dlcl *l, t_dlcl *r)
2186 {
2187 t_dlcl *tmp_r, *tmp_l;
2188
2189 tmp_r = l->right;
2190 tmp_l = tmp_r->left;
2191
2192 l->right = r;
2193 r->right = tmp_r;
2194
2195 r->left = tmp_l;
2196 tmp_r->left = r;
2197 }
2198
2199
2200 static void
embedg_dlcl_rec_insert_left(t_dlcl * l,t_dlcl * r)2201 embedg_dlcl_rec_insert_left (t_dlcl *l, t_dlcl *r)
2202 {
2203 t_dlcl *tmp_r, *tmp_l;
2204
2205 tmp_l = l->left;
2206 tmp_r = tmp_l->right;
2207
2208 l->left = r;
2209 r->left = tmp_l;
2210
2211 r->right = tmp_r;
2212 tmp_l->right = r;
2213 }
2214
2215 t_dlcl *
embedg_dlcl_rec_append(t_dlcl * l,t_dlcl * r)2216 embedg_dlcl_rec_append (t_dlcl *l, t_dlcl *r)
2217 {
2218 if (embedg_dlcl_is_empty(l))
2219 return r;
2220
2221 embedg_dlcl_rec_insert_left(l, r);
2222 return l;
2223 }
2224
2225 t_dlcl *
embedg_dlcl_rec_prepend(t_dlcl * l,t_dlcl * r)2226 embedg_dlcl_rec_prepend (t_dlcl *l, t_dlcl *r)
2227 {
2228 if (embedg_dlcl_is_empty(l))
2229 return r;
2230
2231 embedg_dlcl_rec_insert_left(l, r);
2232 return r;
2233 }
2234
2235 t_dlcl *
embedg_dlcl_cat(t_dlcl * l,t_dlcl * m)2236 embedg_dlcl_cat (t_dlcl *l, t_dlcl *m)
2237 /*
2238 concatenate m to the RIGHT of the end of l
2239 WITHOUT copying m
2240 */
2241 {
2242 t_dlcl *h1, *h2, *e1, *e2;
2243
2244 if (embedg_dlcl_is_empty(l))
2245 return m;
2246 if (embedg_dlcl_is_empty(m))
2247 return l;
2248
2249 h1 = l;
2250 e1 = l->left;
2251 h2 = m;
2252 e2 = m->left;
2253
2254 e1->right = h2;
2255 h2->left = e1;
2256 e2->right = h1;
2257 h1->left = e2;
2258
2259 return l;
2260 }
2261
2262 t_dlcl *
embedg_dlcl_find(t_dlcl * l,int info)2263 embedg_dlcl_find (t_dlcl *l, int info)
2264 {
2265 t_dlcl *p = l;
2266
2267 if (!embedg_dlcl_is_empty(p))
2268 {
2269 if (p->info == info)
2270 {
2271 return p;
2272 }
2273 p = embedg_dlcl_list_next(p);
2274 while (p != l)
2275 {
2276 if (p->info == info)
2277 {
2278 return p;
2279 }
2280 p = embedg_dlcl_list_next(p);
2281 }
2282 }
2283 return NP;
2284 }
2285
2286 t_dlcl *
embedg_dlcl_find_with_NIL_twin_in_adjl(t_dlcl * l,int info)2287 embedg_dlcl_find_with_NIL_twin_in_adjl (t_dlcl *l, int info)
2288 {
2289 t_dlcl *p = l;
2290
2291 if (!embedg_dlcl_is_empty(p))
2292 {
2293 if (p->info == info && p->twin_in_adjl == NIL)
2294 {
2295 return p;
2296 }
2297 p = embedg_dlcl_list_next(p);
2298 while (p != l)
2299 {
2300 if (p->info == info && p->twin_in_adjl == NIL)
2301 {
2302 return p;
2303 }
2304 p = embedg_dlcl_list_next(p);
2305 }
2306 }
2307 return NP;
2308 }
2309
2310
2311
2312 static void
embedg_dlcl_rec_retrieve(t_dlcl * r)2313 embedg_dlcl_rec_retrieve (t_dlcl *r)
2314 {
2315 t_dlcl *right, *left;
2316
2317 right = r->right;
2318 left = r->left;
2319
2320 left->right = right;
2321 right->left = left;
2322
2323 r->right = r;
2324 r->left = r;
2325 }
2326
2327 static void
embedg_dlcl_rec_delete(t_dlcl * r)2328 embedg_dlcl_rec_delete (t_dlcl *r)
2329 {
2330 embedg_dlcl_rec_retrieve(r);
2331 embedg_dlcl_rec_free(r);
2332 }
2333
2334
2335 t_dlcl *
embedg_dlcl_delete_first(t_dlcl * l)2336 embedg_dlcl_delete_first (t_dlcl *l)
2337 /*
2338 prune the list from the head:
2339 - set new head to right of old head
2340 - delete old head
2341 */
2342 {
2343 t_dlcl *new_head;
2344
2345 ASSERT(!embedg_dlcl_is_empty(l));
2346 if (embedg_dlcl_is_singleton(l))
2347 {
2348 new_head = NP;
2349 }
2350 else
2351 {
2352 new_head = l->right;
2353 }
2354 embedg_dlcl_rec_delete(l);
2355 return new_head;
2356 }
2357
2358
2359 t_dlcl *
embedg_dlcl_delete_rec(t_dlcl * l,t_dlcl * r)2360 embedg_dlcl_delete_rec (t_dlcl *l, t_dlcl *r)
2361 /*
2362 delete r from l;
2363 if r == l, set new head to right of old head
2364 */
2365 {
2366 if (r == l)
2367 {
2368 return embedg_dlcl_delete_first(l);
2369 }
2370 embedg_dlcl_rec_delete(r);
2371 return l;
2372 }
2373
2374
2375 boolean
embedg_dlcl_is_empty(t_dlcl * l)2376 embedg_dlcl_is_empty (t_dlcl *l)
2377 {
2378 return (l == NP) ? TRUE : FALSE;
2379 }
2380
2381
2382 static boolean
embedg_dlcl_is_singleton(t_dlcl * l)2383 embedg_dlcl_is_singleton (t_dlcl *l)
2384 {
2385 return (l->right == l) ? TRUE : FALSE;
2386 /*
2387 same as l->left == l
2388 */
2389 }
2390
2391 t_dlcl *
embedg_dlcl_list_next(t_dlcl * l)2392 embedg_dlcl_list_next (t_dlcl *l)
2393 /*
2394 this assumes no choice in the direction of the walking
2395 (always to the right)
2396 -- good enough when deleting for example or when
2397 the direction of the walking does not matter
2398 */
2399 {
2400 return l->right;
2401 }
2402
2403
2404 t_dlcl *
embedg_dlcl_list_prev(t_dlcl * l)2405 embedg_dlcl_list_prev (t_dlcl *l)
2406 /*
2407 this assumes no choice in the direction of the walking
2408 (always to the right)
2409 */
2410 {
2411 return l->left;
2412 }
2413
2414 t_dlcl *
embedg_dlcl_list_last(t_dlcl * l)2415 embedg_dlcl_list_last (t_dlcl *l)
2416 {
2417 return embedg_dlcl_list_prev(l);
2418 }
2419
2420
2421
2422 void
embedg_dlcl_delete(t_dlcl * l)2423 embedg_dlcl_delete (t_dlcl *l)
2424 {
2425 if (!embedg_dlcl_is_empty(l))
2426 {
2427 while (!embedg_dlcl_is_singleton(l))
2428 {
2429 t_dlcl *next;
2430
2431 next = embedg_dlcl_list_next(l);
2432 embedg_dlcl_rec_delete(next);
2433 }
2434 embedg_dlcl_rec_delete(l);
2435 }
2436 }
2437
2438 t_dlcl *
embedg_dlcl_copy(t_dlcl * l)2439 embedg_dlcl_copy (t_dlcl *l)
2440 {
2441 t_dlcl *p, *c;
2442
2443 if (embedg_dlcl_is_empty(l))
2444 return NP;
2445
2446 c = embedg_dlcl_rec_new(l->info);
2447
2448 p = embedg_dlcl_list_next(l);
2449 while (p != l)
2450 {
2451 t_dlcl *temp;
2452
2453 temp = embedg_dlcl_rec_new(p->info);
2454 temp->in_adjl = p->in_adjl;
2455 temp->twin_in_adjl = p->twin_in_adjl;
2456 temp->mult = p->mult;
2457 c = embedg_dlcl_rec_append(c, temp);
2458 p = embedg_dlcl_list_next(p);
2459 }
2460 return c;
2461 }
2462
2463
2464 int
embedg_dlcl_length(t_dlcl * l)2465 embedg_dlcl_length (t_dlcl *l)
2466 {
2467 t_dlcl *p;
2468 int n;
2469
2470 if (embedg_dlcl_is_empty(l))
2471 return 0;
2472
2473 p = embedg_dlcl_list_next(l);
2474 n = 1;
2475 while (p != l)
2476 {
2477 n++;
2478 p = embedg_dlcl_list_next(p);
2479 }
2480 return n;
2481 }
2482 /*
2483 * planar_by_edge_addition.c
2484 */
2485
2486 /*
2487 What:
2488 *****
2489
2490 Implementing:
2491
2492 The top level for the planarity tester.
2493
2494
2495 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2496 from
2497
2498 Simplified O(n) Planarity Algorithms (draft)
2499 ************************************
2500
2501 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
2502 Wendy Myrvold wendym@csr.uvic.ca
2503
2504
2505 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2506 authors:
2507 ********
2508
2509 Paulette Lieby (Magma), Brendan McKay (ANU)
2510
2511 Started October 2001
2512 */
2513
2514
2515 #include "planarity.h"
2516
2517 #define IF_DEB(x) {}
2518 #define IF_VERB(x) {}
2519 #define IF_DEB_TREE(x) {}
2520 #define IF_DEB_EDGES(x) {}
2521 #define IF_CPU(x) {}
2522
2523
2524 /* aproto: header embed_graph_protos.h */
2525
2526
2527 #ifndef PLANAR_IN_MAGMA
2528 #endif
2529
2530
2531 boolean
sparseg_adjl_is_planar(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int * nbr_c,t_dlcl *** dfs_tree,t_dlcl *** back_edges,t_dlcl *** mult_edges,t_ver_edge ** embed_graph,int * edge_pos,int * vr,int * wr)2532 sparseg_adjl_is_planar (
2533 t_ver_sparse_rep *V,
2534 int n,
2535 t_adjl_sparse_rep *A, /* input sparse graph */
2536 int *nbr_c, /* size of the graph, #components
2537 */
2538 t_dlcl ***dfs_tree, /* a sparse graph rep. for the dfs tree
2539 -- vertices are as DFIs
2540 -- and children are ordered wrt
2541 lowpoint value
2542 */
2543 t_dlcl ***back_edges, /* for each vertex v, a dlcl
2544 of the back edges [v, x] incident to v
2545 where x is a DESCENDANT of v
2546 (vertices are given as DFIs)
2547 */
2548 t_dlcl ***mult_edges, /* for each vertex v, a dlcl
2549 of the back edges [v, x] incident to v
2550 where x is a DESCENDANT of v
2551 (vertices are given as DFIs)
2552 */
2553 t_ver_edge **embed_graph, /* output graph embedding -- more on that
2554 later
2555 */
2556 int *edge_pos, /* pos. in embed_graph for addition
2557 of the next edge */
2558 int *vr,
2559 int *wr /* if graph is non planar, return
2560 the unembedded edge
2561 (where wr descendant of vr)
2562 */
2563 )
2564 /*
2565 as the name indicates: is the graph planar?
2566 */
2567 {
2568 int v;
2569
2570 IF_CPU(
2571 float sttime; float time_to_now;
2572 )
2573
2574
2575 *embed_graph =
2576 embedg_planar_alg_init(V, n, A, nbr_c,
2577 edge_pos, dfs_tree, back_edges, mult_edges);
2578 IF_CPU(
2579 sttime = time_current_user();
2580 )
2581
2582 for (v = n - 1; v >= 0; v--)
2583 /*
2584 visit all vertices in descending DFI order
2585 */
2586 {
2587 t_dlcl *be_l, *te_l, *p;
2588
2589 IF_DEB(
2590 fprintf(stdout, "top level, vertex %d\n", v);
2591 )
2592
2593 /*
2594 find all the back edges [w, v] where w is a descendant of v
2595 and perform a walkup from w to v
2596 (ie determine which bicomps are pertinent)
2597 */
2598 be_l = (*back_edges)[v];
2599 p = be_l;
2600
2601 if (!embedg_dlcl_is_empty(p))
2602 {
2603 int w;
2604
2605 w = p->info;
2606 IF_DEB(
2607 fprintf(stdout, "top level, before walkup for w %d\n", w);
2608 )
2609 embedg_walkup(*embed_graph, n, v, p);
2610
2611 p = embedg_dlcl_list_next(p);
2612 while (p != be_l)
2613 {
2614 w = p->info;
2615 IF_DEB(
2616 fprintf(stdout, "top level, before walkup for w %d\n", w);
2617 )
2618 embedg_walkup(*embed_graph, n, v, p);
2619
2620 p = embedg_dlcl_list_next(p);
2621 }
2622 }
2623
2624 /*
2625 perform a walkdown for each tree edge [v, c], c a descendant of v
2626 (ie attempt to embed all back edges on the pertinent bicomps)
2627 */
2628 te_l = (*dfs_tree)[v];
2629 p = te_l;
2630
2631 if (!embedg_dlcl_is_empty(p))
2632 {
2633 int c, vv;
2634 t_merge_queue q;
2635
2636 c = p->info;
2637 vv = c + n;
2638 IF_DEB(
2639 fprintf(stdout, "top level, before walkdown for c %d\n", c);
2640 )
2641 q = embedg_walkdown(*embed_graph, n, edge_pos, vv);
2642
2643 IF_DEB(
2644 fprintf(stdout, "top level, after walkdown for c %d, state of edges'sign\n", c);
2645 embedg_VES_print_flipped_edges(*embed_graph,
2646 n, *edge_pos);
2647 )
2648
2649 /*
2650 temp only
2651 */
2652 embedg_merge_queue_delete(q);
2653 p = embedg_dlcl_list_next(p);
2654 while (p != te_l)
2655 {
2656 c = p->info;
2657 vv = c + n;
2658 IF_DEB(
2659 fprintf(stdout, "top level, before walkdown for c %d\n", c);
2660 )
2661 q = embedg_walkdown(*embed_graph, n, edge_pos, vv);
2662
2663 IF_DEB(
2664 fprintf(stdout, "top level, after walkdown for c %d, state of edges'sign\n", c);
2665 embedg_VES_print_flipped_edges(*embed_graph,
2666 n, *edge_pos);
2667 )
2668
2669 /*
2670 temp only
2671 */
2672 embedg_merge_queue_delete(q);
2673
2674 p = embedg_dlcl_list_next(p);
2675 }
2676 }
2677
2678
2679 /*
2680 check that each back edge [w, v], w a descendant of v,
2681 has been embedded
2682 */
2683 be_l = (*back_edges)[v];
2684 p = be_l;
2685
2686 if (!embedg_dlcl_is_empty(p))
2687 {
2688 int w;
2689
2690 w = p->info;
2691 IF_DEB(
2692 fprintf(stdout, "top level, before checking embedding for w %d\n",
2693 w);
2694 )
2695 if ((*embed_graph)[w].adjacent_to == v)
2696 /*
2697 this edge hasn't been embedded:
2698 the graph is non-planar
2699 */
2700 {
2701 /*
2702 before returning we really want to ensure that
2703 the vertices' adjacency lists are consistent
2704 */
2705 ASSERT(embedg_VES_are_adj_lists_consistent(
2706 *embed_graph, n));
2707
2708 IF_CPU(
2709 fprintf(stdout, "CPU for tester only %f\n",
2710 (time_current_user() - sttime));
2711 )
2712
2713 *vr = v;
2714 *wr = w;
2715 return FALSE;
2716 }
2717
2718 p = embedg_dlcl_list_next(p);
2719 while (p != be_l)
2720 {
2721 w = p->info;
2722 IF_DEB(
2723 fprintf(stdout, "top level, before checking embedding for w %d\n",
2724 w);
2725 )
2726 if ((*embed_graph)[w].adjacent_to == v)
2727 {
2728 /*
2729 before returning we really want to ensure that
2730 the vertices' adjacency lists are consistent
2731 */
2732 ASSERT(embedg_VES_are_adj_lists_consistent(
2733 *embed_graph, n));
2734
2735 IF_CPU(
2736 fprintf(stdout, "CPU for tester only %f\n",
2737 (time_current_user() - sttime));
2738 )
2739
2740 *vr = v;
2741 *wr = w;
2742 return FALSE;
2743 }
2744
2745 p = embedg_dlcl_list_next(p);
2746 }
2747 }
2748 }
2749 IF_DEB_EDGES(
2750 fprintf(stdout, "top level, total number of edges in embedding %d\n",
2751 *edge_pos - 2 * n + 1);
2752 )
2753
2754
2755 /*
2756 before returning we really want to ensure that
2757 the vertices' adjacency lists are consistent
2758 */
2759 ASSERT(embedg_VES_are_adj_lists_consistent(*embed_graph, n));
2760
2761 IF_CPU(
2762 fprintf(stdout, "CPU for tester only %f\n",
2763 (time_current_user() - sttime));
2764 )
2765
2766 return TRUE;
2767 }
2768
2769
2770
2771 /*
2772 * walkup.c
2773 */
2774
2775 /*
2776 What:
2777 *****
2778
2779 Implementing:
2780
2781 The walkup routine within the VES structure:
2782
2783 Walking up from w where [w, v^c] is a (directed)
2784 back edge to be embeeding later.
2785 Along the way collect all the pertinent bicomps that
2786 will need to be merged before embedding the back edges
2787 to v^c.
2788
2789
2790 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2791 from
2792
2793 Simplified O(n) Planarity Algorithms (draft)
2794 ************************************
2795
2796 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
2797 Wendy Myrvold wendym@csr.uvic.ca
2798
2799
2800 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2801 authors:
2802 ********
2803
2804 Paulette Lieby (Magma), Brendan McKay (ANU)
2805
2806 Started October 2001
2807 */
2808
2809
2810 #include "planarity.h"
2811
2812 #define IF_DEB(x) {}
2813 #define IF_VERB(x) {}
2814
2815
2816
2817 /* aproto: header embed_graph_protos.h */
2818
2819
2820 #ifndef PLANAR_IN_MAGMA
2821 #endif
2822
2823
2824 void
embedg_walkup(t_ver_edge * embed_graph,int n,int v,t_dlcl * p)2825 embedg_walkup (t_ver_edge *embed_graph, int n, int v, t_dlcl *p)
2826 /*
2827 walkup from w = p->info to v: [w, v] is a back edge where w is a DFS
2828 descendant of v
2829 */
2830 {
2831 int w, x, xin, y, yin;
2832
2833 w = p->info;
2834
2835 IF_DEB(
2836 fprintf(stdout, "walkup from %d to %d, enter\n", w, v);
2837 )
2838
2839 embed_graph[w].adjacent_to = v;
2840 /*
2841 dirty trick to record some information about the BE [w, v]
2842 which will be useful at the time of creation and insertion of
2843 this BE: this happens in the walkdown procedure
2844
2845 note that what I am doing here is safe: [w].in_adjl,
2846 [w].twin_in_adjl, [w].mult had no use so far since w is a vertex
2847 (and not an edge...)
2848 */
2849 embed_graph[w].in_adjl = p->in_adjl;
2850 embed_graph[w].twin_in_adjl = p->twin_in_adjl;
2851 embed_graph[w].mult = p->mult;
2852
2853 /*
2854 set up the traversal contexts for w: one in each direction
2855 */
2856 x = w;
2857 xin = 1;
2858 y = w;
2859 yin = 0;
2860
2861 while (x != v)
2862 {
2863 int vz, z, c;
2864
2865 IF_DEB(
2866 fprintf(stdout, "walkup, x %d and y %d\n", x, y);
2867 )
2868
2869 if (embed_graph[x].visited == v
2870 || embed_graph[y].visited == v)
2871 {
2872 IF_DEB(
2873 if (embed_graph[x].visited == v)
2874 fprintf(stdout, "walkup, x visited\n");
2875 else
2876 fprintf(stdout, "walkup, y visited\n");
2877 )
2878 break;
2879 }
2880
2881 /*
2882 set x and y as visited!
2883 */
2884 embed_graph[x].visited = embed_graph[y].visited = v;
2885
2886 vz = embedg_VES_is_virtual_vertex(n, x) ? x : NIL;
2887 vz = embedg_VES_is_virtual_vertex(n, y) ? y : vz;
2888
2889 if (vz != NIL)
2890 /*
2891 that is, x (or y) is a virtual vertex
2892 -- in other words, we are set to find the root of the bicomp
2893 containing w, or of the bicomp r^c such that w is in the tree
2894 rooted by c
2895
2896 consequently, by definition, vz is PERTINENT
2897 */
2898 {
2899 c = vz - n;
2900 z = embed_graph[c].DFS_parent;
2901
2902 IF_DEB(
2903 fprintf(stdout, "walkup, vz is virtual, %d^%d\n",
2904 z, c);
2905 )
2906
2907 if (z != v)
2908 /*
2909 determine if vz externally or internally active
2910 */
2911 {
2912 if (embed_graph[c].lowpoint < v)
2913 /*
2914 vz is externally active: APPEND to the list
2915 of pertinent bicomps
2916 */
2917 {
2918 IF_DEB(
2919 fprintf(stdout, "walkup, vz is ext. active\n");
2920 )
2921
2922 embed_graph[z].pertinent_bicomp_list =
2923 embedg_dlcl_rec_append(
2924 embed_graph[z].pertinent_bicomp_list,
2925 embedg_dlcl_rec_new(vz));
2926 }
2927 else
2928 /*
2929 vz is internally active: PREPEND to the list
2930 of pertinent bicomps
2931 */
2932 {
2933 IF_DEB(
2934 fprintf(stdout, "walkup, vz is pertinent\n");
2935 )
2936
2937 embed_graph[z].pertinent_bicomp_list =
2938 embedg_dlcl_rec_prepend(
2939 embed_graph[z].pertinent_bicomp_list,
2940 embedg_dlcl_rec_new(vz));
2941 }
2942 }
2943
2944 /*
2945 continue the walkup, look if there are any other
2946 pertinent bicomps
2947 -- here "jump" to the next bicomp "up"
2948 */
2949 x = z;
2950 xin = 1;
2951 y = z;
2952 yin = 0;
2953 }
2954 else
2955 /*
2956 continue the traversal of the bicomp until one finds
2957 its (virtual) root
2958 */
2959 {
2960 embedg_VES_get_succ_on_ext_face(embed_graph, n,
2961 x, xin, FALSE, 0, &x, &xin);
2962 embedg_VES_get_succ_on_ext_face(embed_graph, n,
2963 y, yin, FALSE, 0, &y, &yin);
2964 }
2965 }
2966 }
2967
2968 /*
2969 * walkdown.c
2970 */
2971
2972 /*
2973 What:
2974 *****
2975
2976 Implementing:
2977
2978 The walkdown routine within the VES structure:
2979
2980 walking down a bicomp rooted by a virtual vertex v^c
2981 and attempting to embed the back edges.
2982 This cannot be done if the walk has to stop due to the
2983 presence of externally active vertices on both
2984 the clockwise and the anticlockwise side of the bicomp.
2985
2986
2987 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2988 from
2989
2990 Simplified O(n) Planarity Algorithms (draft)
2991 ************************************
2992
2993 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
2994 Wendy Myrvold wendym@csr.uvic.ca
2995
2996
2997 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2998 authors:
2999 ********
3000
3001 Paulette Lieby (Magma), Brendan McKay (ANU)
3002
3003 Started October 2001
3004 */
3005
3006
3007 #include "planarity.h"
3008
3009 #define IF_DEB(x) {}
3010 #define IF_DEB_EMBED(x) {}
3011 #define IF_DEB_BE(x) {}
3012 #define IF_DEB_SCE(x) {}
3013 #define IF_VERB(x) {}
3014
3015
3016
3017 /* aproto: header embed_graph_protos.h */
3018
3019
3020 #ifndef PLANAR_IN_MAGMA
3021 #endif
3022
3023
3024
3025 t_merge_queue
embedg_walkdown(t_ver_edge * embed_graph,int n,int * edge_pos,int vv)3026 embedg_walkdown (t_ver_edge *embed_graph, int n, int *edge_pos, int vv)
3027 /*
3028 walkdown from the virtual vertex:
3029 embed any back edges incident to vv if any
3030 and merge the encountered bicomps while walking down
3031 (very informative isn't it? :))
3032
3033 ... and return the merge queue: will be useful when
3034 isolating the Kuratowski subgraphs
3035 */
3036 {
3037 t_merge_queue q;
3038 int v, c, vvout;
3039
3040 ASSERT(embedg_VES_is_virtual_vertex(n, vv));
3041
3042 /*
3043 find v and c such that v^c = vv
3044 */
3045 c = vv - n;
3046 v = embed_graph[c].DFS_parent;
3047
3048 IF_DEB(
3049 fprintf(stdout, "walkdown from %d^%d, enter\n", v, c);
3050 )
3051
3052 IF_DEB_EMBED(
3053 fprintf(stdout, "walkdown, embedding at start\n");
3054 embedg_VES_print_bigcomps(embed_graph, n);
3055 )
3056
3057 /*
3058 create an empty merge queue
3059 */
3060 q = embedg_merge_queue_new(n);
3061
3062 for (vvout = 0; vvout <= 1; vvout++)
3063 /*
3064 chose a direction for the walk, but walk in both
3065 directions unless a stopping vertex is encountered
3066 and other conditions are satisfied (see below)
3067 */
3068 {
3069 int w, win;
3070
3071 embedg_VES_get_succ_on_ext_face(embed_graph, n, vv, vvout ^ 1,
3072 FALSE, 0, &w, &win);
3073
3074 IF_DEB(
3075 fprintf(stdout, "walkdown, successor (outside while loop) from %d^%d:%d is %d:%d\n",
3076 embed_graph[vv-n].DFS_parent, vv-n, vvout ^ 1,
3077 w, win);
3078 )
3079
3080 while (w != vv)
3081 /*
3082 is there no danger we walk the whole way back to vv
3083 and that all the vertices along the walk are inactive?
3084
3085 answer: no, because of the short-cut edges.
3086
3087 Short-cut edges are precisely inserted to remove the inactive
3088 vertices from the external face (ie they are "pushed"
3089 to the internal face of the bicomp)
3090 */
3091 {
3092 if (embed_graph[w].adjacent_to == v)
3093 /*
3094 ie there is a (directed) back edge [w, v]
3095 (would have been set in the previous walkup routine):
3096 embed this edge, but before that, merge all the bicomps
3097 previouslsy collected
3098 */
3099 {
3100 IF_DEB(
3101 fprintf(stdout, "walkdown, embed BE (%d^%d:%d, %d:%d)\n",
3102 embed_graph[vv-n].DFS_parent, vv - n, vvout,
3103 w, win);
3104 fprintf(stdout, "walkdown, queue before pulling elts\n");
3105 embedg_merge_queue_print(q);
3106 )
3107
3108 while (!embedg_merge_queue_empty(q))
3109 {
3110 int u, uin, vu, vuout;
3111
3112 embedg_merge_queue_get(&q, &u, &uin, &vu, &vuout);
3113
3114 IF_DEB(
3115 fprintf(stdout, "walkdown, pull from queue (%d:%d, %d^%d:%d)\n",
3116 u, uin,
3117 embed_graph[vu-n].DFS_parent, vu-n,
3118 vuout);
3119 )
3120
3121 embedg_VES_merge_pertinent_bicomps(
3122 embed_graph, n,
3123 vu, vuout, u, uin);
3124 }
3125 IF_DEB_BE(
3126 fprintf(stdout, "walkdown, before embed BE [%d^%d:%d, %d:%d]\n",
3127 embed_graph[vv-n].DFS_parent, vv - n,
3128 vvout, w, win);
3129 embedg_VES_print_adj_list(
3130 embed_graph, n, vv,
3131 TRUE);
3132 fprintf(stdout, "\n");
3133 embedg_VES_print_adj_list(
3134 embed_graph, n, vv,
3135 FALSE);
3136 )
3137
3138 embedg_VES_embed_edge(embed_graph, n, edge_pos,
3139 BE, vv, vvout, w, win);
3140
3141 IF_DEB_BE(
3142 fprintf(stdout, "walkdown, after embed BE [%d^%d:%d, %d:%d]\n",
3143 embed_graph[vv-n].DFS_parent, vv - n,
3144 vvout, w, win);
3145 embedg_VES_print_adj_list(
3146 embed_graph, n, vv,
3147 TRUE);
3148 fprintf(stdout, "\n");
3149 embedg_VES_print_adj_list(
3150 embed_graph, n, vv,
3151 FALSE);
3152 )
3153 IF_DEB_EMBED(
3154 fprintf(stdout, "walkdown, embedding after bicomp merge & back edge embedding\n");
3155 embedg_VES_print_bigcomps(embed_graph, n);
3156 )
3157
3158 /*
3159 clear the adjacent_to flag
3160 */
3161 embed_graph[w].adjacent_to = n; /* "invalid" value */
3162 }
3163
3164 if (!embedg_dlcl_is_empty(embed_graph[w].pertinent_bicomp_list))
3165 /*
3166 each pertinent child bicomp of w
3167 (pertinent: contains active (ie more back edges to embed)
3168 elts)
3169 must be traversed
3170 and pushed onto the queue for later bicomp merging
3171 */
3172 {
3173 int vw, vwout, x, xin, y, yin, s, sin;
3174
3175 IF_DEB(
3176 fprintf(stdout, "walkdown, pertinent list for %d\n",
3177 w);
3178 embedg_dlcl_print(embed_graph[w].pertinent_bicomp_list);
3179 )
3180
3181 /*
3182 get the first child in the pertinent list
3183 (see how the list is built in embedg_walkup)
3184
3185 the child will eventually be removed from that list
3186 when merging the bicomps, and surely
3187 this bicomp (rooted at vw) will be merged (later)
3188 because it is active and hence pushed on
3189 the merge queue
3190 */
3191
3192 /*
3193 we can start by pushing the vertex (w, win) on
3194 the merge queue
3195 */
3196 embedg_merge_queue_append_vertex(&q, embed_graph, n, w, win);
3197
3198 IF_DEB(
3199 fprintf(stdout, "walkdown, push 1rst 2-tuple on queue\n");
3200 embedg_merge_queue_print(q);
3201 )
3202
3203 /*
3204 get the first child in the pertinent list
3205 */
3206 vw = (embed_graph[w].pertinent_bicomp_list)->info;
3207
3208 IF_DEB(
3209 fprintf(stdout, "walkdown, get pertinent %d^%d\n",
3210 embed_graph[vw - n].DFS_parent, vw - n);
3211 )
3212
3213 /*
3214 start two walks starting at vw
3215 */
3216 embedg_VES_get_succ_active_on_ext_face(embed_graph, n,
3217 v , vw, 1,
3218 FALSE, 0, &x, &xin);
3219 embedg_VES_get_succ_active_on_ext_face(embed_graph, n,
3220 v, vw, 0,
3221 FALSE, 0, &y, &yin);
3222
3223 /*
3224 because of the trick of inserting short-cut edges
3225 at previous stages, neighbours of vw are guaranteed
3226 to be active
3227
3228 (however I'll use the more general
3229 embedg_VES_get_succ_active_on_ext_face
3230 instead of the restrictive
3231 embedg_VES_get_succ_on_ext_face
3232 because the walkdown may be used later to isolate
3233 Kuratowski minors, in a situation where SCEs could have
3234 been removed and thus where the successor on the
3235 external face will no longer be guaranteed to be active)
3236 (* actually I have decided to remove the SCE at the
3237 very last moment hence the above pb
3238 does not occur in the present implementation)
3239
3240
3241 it only remains to chose the next vertex where from
3242 to continue the walk; the choice is made in that order:
3243 - an internally active vertex
3244 (incident to v via a backedge but whose lowpoint
3245 is NO less than v)
3246 - a (externally active) pertinent vertex
3247 (incident to v via a backedge but whose lowpoint
3248 is less than v: ie which is also externally active)
3249 - as a last resort, a non-pertinent externally vertex,
3250 which is then a stopping vertex
3251 */
3252 IF_DEB(
3253 fprintf(stdout, "walkdown, x and y: %d, %d\n", x, y);
3254 )
3255
3256 if (embedg_VES_is_ver_int_active(embed_graph, n,
3257 v, x))
3258 /*
3259 x is internally active
3260 */
3261 {
3262 IF_DEB(
3263 fprintf(stdout, "walkdown, x is int. active\n");
3264 )
3265
3266 s = x;
3267 sin = xin;
3268 }
3269 else if (embedg_VES_is_ver_int_active(
3270 embed_graph, n,
3271 v, y))
3272 /*
3273 y is internally active
3274 */
3275 {
3276 IF_DEB(
3277 fprintf(stdout, "walkdown, y is int. active\n");
3278 )
3279
3280 s = y;
3281 sin = yin;
3282 }
3283 else if (embedg_VES_is_ver_pertinent(
3284 embed_graph, n,
3285 v, x))
3286 /*
3287 x is pertinent
3288 */
3289 {
3290 IF_DEB(
3291 fprintf(stdout, "walkdown, x is pertinent\n");
3292 )
3293
3294 s = x;
3295 sin = xin;
3296 }
3297 else
3298 /*
3299 tough luck: y may be externally active
3300 */
3301 {
3302 IF_DEB(
3303 fprintf(stdout, "walkdown, tough luck\n");
3304 )
3305
3306 s = y;
3307 sin = yin;
3308 }
3309
3310 IF_DEB(
3311 fprintf(stdout, "walkdown, succ. on pertinent bicomp is %d:%d\n", s, sin);
3312 )
3313
3314 /*
3315 set vwout to respect consistency of traversal
3316 */
3317 vwout = s == x ? 0 : 1;
3318
3319 /*
3320 now that we know vwout we can push (vw, vwout)
3321 on the merge queue, thus completing the 4-tuple
3322 (w, win, vw, vwout) describing a bicomp merge
3323 to occur at a later stage
3324 */
3325 embedg_merge_queue_append_virtual_vertex(&q, embed_graph, n,
3326 vw, vwout);
3327
3328 IF_DEB(
3329 fprintf(stdout, "walkdown, push on queue (%d:%d, %d^%d:%d)\n",
3330 w, win, embed_graph[vw-n].DFS_parent, vw - n,
3331 vwout);
3332 embedg_merge_queue_print(q);
3333 )
3334
3335 /*
3336 we continue the walk
3337 */
3338 w = s;
3339 win = sin;
3340 }
3341 /*
3342 at this point, w is either inactive or externally active
3343 (w can't be pertinent: its pertinent bicomp list is empty,
3344 and the back edge [w, v], if any, has already been embedded)
3345 */
3346 else if (embedg_VES_is_ver_inactive(embed_graph, n,
3347 v, w))
3348 /*
3349 w is inactive: continue with the walk on the external face
3350 and, insert a short cut edge so that w is removed
3351 from the external face
3352 */
3353 {
3354 int s, sin;
3355
3356 IF_DEB(
3357 fprintf(stdout, "walkdown, %d has no pertinent bicomps and is inactive\n", w);
3358 )
3359
3360 embedg_VES_get_succ_on_ext_face(embed_graph, n,
3361 w, win,
3362 FALSE, 0, &s, &sin);
3363
3364 IF_DEB(
3365 fprintf(stdout, "walkdown, successor from %d:%d is %d:%d\n",
3366 w, win, s, sin);
3367 )
3368
3369 /*
3370 s is the successor of w: we embed a short circuit edge
3371 [vv, s] if
3372 - the bicomp is externally active (to ensure that
3373 at a later stage this new face gets bisected:
3374 so that we don't end up with a face of degree 2
3375 (parallel edges))
3376 - if [s, vv] is not a back edge
3377
3378 CONSEQUENTLY, adding SCE edges
3379 + does not destroy the planarity of the graph
3380 + ensures that each face has degree > 2 so that
3381 |E| <= 3 * |V| - 6 remains valid at all times
3382 + that the space allocated to the edges in embed_graph
3383 (via MAXDE(n)) is sufficient
3384
3385 NOTE:
3386 the above still allows to embed a short-cut edge
3387 as an edge parallel to a tree edge OR a back edge
3388 (which then has been embedded previously
3389 so that [w].adjacent has been cleared)
3390
3391 but again, since the degree of the face will be
3392 > 2, that's ok
3393
3394 recall that c = vv - n
3395 */
3396 if (embed_graph[c].lowpoint < v
3397 /*
3398 bicomp rooted at vv is externally active
3399 */
3400 && embed_graph[s].adjacent_to != v)
3401 /*
3402 [s, vv] is not a back edge
3403 */
3404 {
3405 IF_DEB_SCE(
3406 fprintf(stdout, "walkdown, before embed SCE [%d^%d:%d, %d:%d]\n",
3407 embed_graph[vv-n].DFS_parent, vv - n,
3408 vvout, s, sin);
3409 embedg_VES_print_adj_list(
3410 embed_graph, n, vv,
3411 TRUE);
3412 fprintf(stdout, "\n");
3413 embedg_VES_print_adj_list(
3414 embed_graph, n, vv,
3415 FALSE);
3416
3417 )
3418
3419 embedg_VES_embed_edge(embed_graph,
3420 n, edge_pos,
3421 SCE, vv, vvout, s, sin);
3422 /*
3423 note also that the addition of short cut edges
3424 does not change the fact that the graph is planar
3425 (when it is, so we never run into the problem
3426 of creating/adding too many edges to embed-graph)
3427 */
3428 IF_DEB_SCE(
3429 fprintf(stdout, "walkdown, after embed SCE [%d^%d:%d, %d:%d]\n",
3430 embed_graph[vv-n].DFS_parent, vv - n,
3431 vvout, s, sin);
3432 embedg_VES_print_adj_list(
3433 embed_graph, n, vv,
3434 TRUE);
3435 fprintf(stdout, "\n");
3436 embedg_VES_print_adj_list(
3437 embed_graph, n, vv,
3438 FALSE);
3439
3440 )
3441 IF_DEB(
3442 fprintf(stdout, "walkdown, embed SCE [%d^%d:%d, %d:%d]\n",
3443 embed_graph[vv-n].DFS_parent, vv - n,
3444 vvout, s, sin);
3445 )
3446
3447 }
3448 /*
3449 continue the walk
3450 */
3451 w = s;
3452 win = sin;
3453 }
3454 else
3455 /*
3456 w is non-pertinent and externally active:
3457 it is a stopping vertex:
3458 we stop here and see if we can walk in the other direction
3459 */
3460 {
3461 IF_DEB(
3462 fprintf(stdout, "walkdown, %d is externally active\n", w);
3463 )
3464 break;
3465 }
3466 }
3467 if (!embedg_merge_queue_empty(q))
3468 /*
3469 mumm.... don't understand this one... let's see:
3470 the queue constains pertinent bicomps collected during one of
3471 the traversal of the external face, so that once
3472 a stopping vertex has been encountered and the queue
3473 is not empty, this means that we will be unable
3474 to embed any remaining back edges:
3475
3476 it is important to remember that when w is a stopping vertex
3477 there is no choice left, since we walk the pertinent
3478 bicomp in both directions at once, and always choose
3479 the "best" possible vertex
3480 (see the choice strategy: (a) internally active, (b) pertinent,
3481 (c) the rest)
3482 */
3483 {
3484 IF_DEB(
3485 fprintf(stdout, "walkdown, merge queue is not empty\n");
3486 )
3487 break;
3488 }
3489 }
3490
3491 /*
3492 and return the merge queue
3493 */
3494 return q;
3495 }
3496
3497
3498
3499
3500 /*
3501 * merge_queue_misc.c
3502 */
3503
3504 /*
3505 What:
3506 *****
3507
3508 Implementing:
3509
3510 The merge queue stores the pertinent bicomps waiting to
3511 be merged before a subsequent back edge embedding.
3512 See walkdown.c
3513
3514 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3515 from
3516
3517 Simplified O(n) Planarity Algorithms (draft)
3518 ************************************
3519
3520 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
3521 Wendy Myrvold wendym@csr.uvic.ca
3522
3523
3524 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3525 authors:
3526 ********
3527
3528 Paulette Lieby (Magma), Brendan McKay (ANU)
3529
3530 Started October 2001
3531 */
3532
3533
3534 #include "planarity.h"
3535
3536 #define IF_DEB(x) {}
3537 #define IF_VERB(x) {}
3538
3539
3540
3541 /* aproto: header embed_graph_protos.h */
3542
3543
3544 #ifndef PLANAR_IN_MAGMA
3545 #endif
3546
3547 t_merge_queue
embedg_merge_queue_new(int n)3548 embedg_merge_queue_new (int n)
3549 /*
3550 create a merge queue of 4 * (n-1) elts:
3551 we can only have at most n-1 virtual vertices,
3552 and for each of those we need to store 4 bits of info
3553 */
3554 {
3555 t_merge_queue q;
3556
3557 q.start = q.end = 0;
3558 q.b = (int *) mem_malloc(sizeof(int) * 4 * (n - 1));
3559
3560 return q;
3561 }
3562
3563 void
embedg_merge_queue_delete(t_merge_queue q)3564 embedg_merge_queue_delete (t_merge_queue q)
3565 {
3566 mem_free(q.b);
3567 }
3568
3569
3570 boolean
embedg_merge_queue_empty(t_merge_queue q)3571 embedg_merge_queue_empty (t_merge_queue q)
3572 {
3573 return q.start == q.end ? TRUE : FALSE;
3574 }
3575
3576 void
embedg_merge_queue_print(t_merge_queue q)3577 embedg_merge_queue_print (t_merge_queue q)
3578 {
3579 int i;
3580
3581 for (i = q.start; i < q.end; i++)
3582 {
3583 fprintf(stdout, "%d:%d ", q.b[i], q.b[i+1]);
3584 ++i;
3585 }
3586 fprintf(stdout, "\n");
3587 }
3588
3589 void
embedg_merge_queue_append(t_merge_queue * q,t_ver_edge * embed_graph,int n,int v,int vin,int vv,int vvout)3590 embedg_merge_queue_append (t_merge_queue *q, t_ver_edge *embed_graph,
3591 int n, int v, int vin, int vv, int vvout)
3592 /*
3593 append the 4-tuple (v, vin, vv, vvout)
3594 where v is a vertex and vv is its virtual counterpart
3595
3596 we don't do much here, most of the work is done
3597 when pulling a bicomp/4-tuple from the queue
3598 */
3599 {
3600 /*
3601 is this really necessary? - YES!!!
3602 */
3603 ASSERT((*q).end < 4 * (n - 2));
3604 ASSERT(embedg_VES_is_vertex(n, v));
3605 ASSERT(embedg_VES_is_virtual_vertex(n, vv));
3606 ASSERT(embed_graph[vv - n].DFS_parent == v);
3607
3608 (*q).b[(*q).end++] = v;
3609 (*q).b[(*q).end++] = vin;
3610 (*q).b[(*q).end++] = vv;
3611 (*q).b[(*q).end++] = vvout;
3612 }
3613
3614 void
embedg_merge_queue_append_vertex(t_merge_queue * q,t_ver_edge * embed_graph,int n,int v,int vin)3615 embedg_merge_queue_append_vertex (t_merge_queue *q, t_ver_edge *embed_graph,
3616 int n, int v, int vin)
3617 /*
3618 same as above but were we only append the 2-tuple (v, vin),
3619 appending the 2-tuple (vv, vvout) at a later stage
3620 (see embedg_merge_queue_append_virtual_vertex)
3621 */
3622 {
3623 ASSERT((*q).end < 4 * (n - 2));
3624 ASSERT(embedg_VES_is_vertex(n, v));
3625
3626 (*q).b[(*q).end++] = v;
3627 (*q).b[(*q).end++] = vin;
3628
3629 IF_DEB(
3630 fprintf(stdout, "merge_queue_append_vertex, after, end is %d\n",
3631 (*q).end);
3632 )
3633 }
3634
3635 void
embedg_merge_queue_append_virtual_vertex(t_merge_queue * q,t_ver_edge * embed_graph,int n,int vv,int vvout)3636 embedg_merge_queue_append_virtual_vertex (t_merge_queue *q,
3637 t_ver_edge *embed_graph, int n, int vv, int vvout)
3638 /*
3639 counterpart to embedg_merge_queue_append_vertex:
3640 here we append the 2-tuple (vv, vvout), vv = v^c,
3641 where the 2-tuple (v, vin) is already in the queue
3642 (see embedg_merge_queue_append_vertex)
3643 */
3644 {
3645 ASSERT(!embedg_merge_queue_empty(*q));
3646 ASSERT(embedg_VES_is_virtual_vertex(n, vv));
3647 ASSERT(embed_graph[vv - n].DFS_parent == (*q).b[(*q).end - 2]);
3648
3649 (*q).b[(*q).end++] = vv;
3650 (*q).b[(*q).end++] = vvout;
3651
3652 IF_DEB(
3653 fprintf(stdout, "merge_queue_append_virtual_vertex, after, end is %d\n",
3654 (*q).end);
3655 )
3656 }
3657
3658 void
embedg_merge_queue_get(t_merge_queue * q,int * v,int * vin,int * vv,int * vvout)3659 embedg_merge_queue_get (t_merge_queue *q, int *v, int *vin, int *vv, int *vvout)
3660 /*
3661 pulling out a 4-tuple from the beginning of the FIFO queue
3662 */
3663 {
3664 ASSERT(!embedg_merge_queue_empty((*q)));
3665
3666 *v = (*q).b[(*q).start++];
3667 *vin = (*q).b[(*q).start++];
3668 *vv = (*q).b[(*q).start++];
3669 *vvout = (*q).b[(*q).start++];
3670 }
3671
3672 void
embedg_merge_queue_prune(t_merge_queue * q,int * v,int * vin,int * vv,int * vvout)3673 embedg_merge_queue_prune (t_merge_queue *q, int *v,
3674 int *vin, int *vv, int *vvout)
3675 /*
3676 pulling out a 4-tuple from the end of the FIFO queue
3677 */
3678 {
3679 ASSERT(!embedg_merge_queue_empty((*q)));
3680
3681 *vvout = (*q).b[--((*q).end)];
3682 *vv = (*q).b[--((*q).end)];
3683 *vin = (*q).b[--((*q).end)];
3684 *v = (*q).b[--((*q).end)];
3685 }
3686
3687 /*
3688 * vertex_activity.c
3689 */
3690
3691 /*
3692 What:
3693 *****
3694
3695 Implementing:
3696
3697 Determining a vertex's activity. This takes place within
3698 the VES structure.
3699
3700
3701 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3702 from
3703
3704 Simplified O(n) Planarity Algorithms (draft)
3705 ************************************
3706
3707 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
3708 Wendy Myrvold wendym@csr.uvic.ca
3709
3710
3711 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3712 authors:
3713 ********
3714
3715 Paulette Lieby (Magma), Brendan McKay (ANU)
3716
3717 Started October 2001
3718 */
3719
3720 #include "planarity.h"
3721
3722 #define IF_DEB(x) {}
3723 #define IF_VERB(x) {}
3724
3725
3726
3727 /* aproto: header embed_graph_protos.h */
3728
3729
3730 #ifndef PLANAR_IN_MAGMA
3731 #endif
3732
3733
3734
3735
3736 boolean
embedg_VES_is_ver_pertinent(t_ver_edge * embed_graph,int n,int v,int w)3737 embedg_VES_is_ver_pertinent (t_ver_edge *embed_graph, int n, int v, int w)
3738 /*
3739 is w pertinent (wrt v)
3740 - the field adjacent_to = v: means there is a back edge [w, v]
3741 - or w has a non empty pertinent_bicomp_list
3742 */
3743 {
3744 boolean ans;
3745
3746 ans = embed_graph[w].adjacent_to == v ? TRUE : FALSE;
3747
3748 if (ans)
3749 return TRUE;
3750 else
3751 return embedg_dlcl_is_empty(embed_graph[w].pertinent_bicomp_list) ?
3752 FALSE : TRUE;
3753 }
3754
3755 boolean
embedg_VES_is_ver_ext_active(t_ver_edge * embed_graph,int n,int v,int w)3756 embedg_VES_is_ver_ext_active (t_ver_edge *embed_graph, int n, int v, int w)
3757 /*
3758 is w externally active (wrt v)
3759 this is the case when either w's least_ancestor < v
3760 or the first member of w's separated_DFS_child_list has lowpoint < v
3761 (the vertices in separated_DFS_child_list are ordered by lowpoint)
3762
3763 why? because w's separated_DFS_child_list may be empty
3764 (due to prior bicomp merging say) and so its children are in effect
3765 inactive
3766 */
3767 {
3768 boolean ans;
3769
3770 ans = embed_graph[w].least_ancestor < v ? TRUE : FALSE;
3771
3772 if (ans)
3773 return TRUE;
3774 else
3775 {
3776 if (embedg_dlcl_is_empty(embed_graph[w].separated_DFS_child_list))
3777 {
3778 return FALSE;
3779 }
3780 else
3781 {
3782 int c;
3783
3784 c = (embed_graph[w].separated_DFS_child_list)->info;
3785 return embed_graph[c].lowpoint < v ? TRUE : FALSE;
3786 }
3787 }
3788 }
3789
3790
3791 boolean
embedg_VES_is_ver_int_active(t_ver_edge * embed_graph,int n,int v,int w)3792 embedg_VES_is_ver_int_active (t_ver_edge *embed_graph, int n, int v, int w)
3793 /*
3794 is w internally active (wrt v):
3795 this happens when w is pertinent but NOT externally active
3796 */
3797 {
3798 return embedg_VES_is_ver_pertinent(embed_graph, n, v, w)
3799 && !embedg_VES_is_ver_ext_active(embed_graph, n, v, w);
3800 }
3801
3802 boolean
embedg_VES_is_ver_inactive(t_ver_edge * embed_graph,int n,int v,int w)3803 embedg_VES_is_ver_inactive (t_ver_edge *embed_graph, int n, int v, int w)
3804 /*
3805 is w inactive (wrt v), that is w nor pertinent nor externally activ
3806 */
3807 {
3808 return !embedg_VES_is_ver_pertinent(embed_graph, n, v, w)
3809 && !embedg_VES_is_ver_ext_active(embed_graph, n, v, w);
3810 }
3811
3812 /*
3813 * merge_bicomps.c
3814 */
3815
3816 /*
3817 What:
3818 *****
3819
3820 Implementing:
3821
3822 In the VES structure, merging two bicomponents.
3823 That is, merging the virtual vertex v^c with the
3824 actual vertex v while merging their respective
3825 adjacency lists.
3826 This must be done in a very specific manner so as to able to
3827 determine the subsequent internal/external faces.
3828 Also, great care must be taken so that the resulting
3829 adj. list for v is consistent (wrt to the direction
3830 of traversal).
3831
3832
3833 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3834 from
3835
3836 Simplified O(n) Planarity Algorithms (draft)
3837 ************************************
3838
3839 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
3840 Wendy Myrvold wendym@csr.uvic.ca
3841
3842
3843 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3844 authors:
3845 ********
3846
3847 Paulette Lieby (Magma), Brendan McKay (ANU)
3848
3849 Started October 2001
3850 */
3851
3852 #include "planarity.h"
3853
3854 #define IF_DEB(x) {}
3855 #define IF_DEB_ADJL(x) {}
3856 #define IF_VERB(x) {}
3857
3858
3859
3860 /* aproto: header embed_graph_protos.h */
3861
3862
3863 void
embedg_VES_merge_simple_bicomps(t_ver_edge * embed_graph,int n,int vv,int vvout,int v,int vin)3864 embedg_VES_merge_simple_bicomps (t_ver_edge *embed_graph, int n, int vv,
3865 int vvout, int v, int vin)
3866 /*
3867 merge the bicomp rooted at vv (vv a virtual vertex) with
3868 its counterpart v so that the resulting adjacency list for v
3869 is consistent and is the union of the adjacency lists for vv and v
3870
3871 we treat the case that the bicomp may be flipped (vvout == vin)
3872 here
3873 */
3874 {
3875 int c, edge, twin, root_edge, cur, prev;
3876 int vout, vvin, e1, e2, e3, e4, e1out, e3out, e4in;
3877
3878 /*
3879 find c such that [v^c, c] is the root edge of the bicomp
3880 rooted at vv = v^c
3881 */
3882 c = vv - n;
3883 ASSERT(embed_graph[c].DFS_parent == v);
3884
3885 IF_DEB(
3886 fprintf(stdout, "merge_simple_bicomp, start: merge\n");
3887 embedg_VES_print_virtual_vertex(embed_graph, n, vv);
3888 fprintf(stdout, ":%d & ", vvout);
3889 embedg_VES_print_vertex(n, v);
3890 fprintf(stdout, ":%d\n", vin);
3891 )
3892
3893 IF_DEB_ADJL(
3894 fprintf(stdout, "merge_simple_bicomp, adj. list for %d (before)\n", vv);
3895 embedg_VES_print_adj_list(embed_graph, n, vv,
3896 TRUE);
3897 fprintf(stdout, "\n");
3898 embedg_VES_print_adj_list(embed_graph, n, vv,
3899 FALSE);
3900 fprintf(stdout, "\n");
3901
3902 fprintf(stdout, "merge_simple_bicomp, adj. list for %d (before)\n", v);
3903 embedg_VES_print_adj_list(embed_graph, n, v,
3904 TRUE);
3905 fprintf(stdout, "\n");
3906 embedg_VES_print_adj_list(embed_graph, n, v,
3907 FALSE);
3908 )
3909 /*
3910 find all edges incident to vv and (re)set all references
3911 to incidence to vv to incidence to v
3912
3913 by the same token, find the root_edge [v^c, c]
3914
3915 MOREVOVER, when vin == vvout, the bicomp (rooted by v^v = vv)
3916 will be flipped:
3917 we must invert the links of all the edges incident
3918 to vv so that their further union with v's adjacency list
3919 results in a consistent adjacency list for v!
3920
3921 we do everything in one go
3922 */
3923
3924 /*
3925 very careful here: a root edge must ALSO be a TE
3926 (because the same edge could have been added as a SCE)
3927 */
3928
3929 root_edge = NIL;
3930 edge = embed_graph[vv].link[vvout];
3931 ASSERT(embedg_VES_is_edge(n, edge));
3932 if (embed_graph[edge].neighbour == c
3933 && embedg_VES_is_tree_edge(embed_graph, n, edge))
3934 {
3935 root_edge = edge;
3936 }
3937
3938 if (vin == vvout)
3939 /*
3940 invert the links
3941 */
3942 {
3943 int in, out;
3944
3945 in = embed_graph[edge].link[0];
3946 out = embed_graph[edge].link[1];
3947 embed_graph[edge].link[0] = out;
3948 embed_graph[edge].link[1] = in;
3949 }
3950 /*
3951 get the twin and set the neighbour there to v (was vv originally)
3952 */
3953 twin = embedg_VES_get_twin_edge(embed_graph, n, edge);
3954 ASSERT(embed_graph[twin].neighbour == vv);
3955 embed_graph[twin].neighbour = v;
3956
3957 prev = vv;
3958 cur = edge;
3959 while (edge != vv)
3960 {
3961 edge =
3962 embedg_VES_get_next_in_dlcl(embed_graph, n,
3963 cur, prev);
3964
3965 if (embedg_VES_is_edge(n, edge))
3966 /*
3967 get the twin again (and invert the links if need be)
3968 */
3969 {
3970 if (embed_graph[edge].neighbour == c
3971 && embedg_VES_is_tree_edge(embed_graph, n, edge))
3972 {
3973 root_edge = edge;
3974 }
3975
3976 if (vin == vvout)
3977 {
3978 int in, out;
3979
3980 in = embed_graph[edge].link[0];
3981 out = embed_graph[edge].link[1];
3982 embed_graph[edge].link[0] = out;
3983 embed_graph[edge].link[1] = in;
3984 }
3985
3986 twin =
3987 embedg_VES_get_twin_edge(embed_graph, n, edge);
3988 ASSERT(embed_graph[twin].neighbour == vv);
3989 embed_graph[twin].neighbour = v;
3990
3991 prev = cur;
3992 cur = edge;
3993 }
3994 else
3995 {
3996 ASSERT(edge == vv);
3997 /*
3998 only one vertex in the whole circular list
3999 */
4000 }
4001 }
4002 ASSERT(root_edge != NIL);
4003
4004 /*
4005 and now union the adjacency lists of v and vv:
4006
4007 let e1 be the edge record used to enter v
4008 e2 exit v
4009 e3 enter vv
4010 e4 exit vv :
4011
4012 e1 -> v -> e2
4013 e3 -> vv -> e4
4014
4015 the union of the list is done in such a way that
4016 - e1 and e4 are consecutive in v's adjacency list:
4017 they are now in the internal face
4018 - e3 is now the edge record used to enter v:
4019 it is on the external face (along with e2) :
4020
4021 e1 -> e4
4022 e3 -> v -> e2
4023
4024 (note that this does not assume that e1 & e2 are distinct
4025 or that e3 & e4 are distinct)
4026 */
4027 /*
4028 I must not forget the case where v is a lone vertex:
4029 this is the case where v has no DFS ancestor, ie when
4030 v is the root of a tree in the DFS forest
4031 */
4032
4033 e1 = embed_graph[v].link[vin];
4034 vout = 1 ^ vin;
4035 e2 = embed_graph[v].link[vout];
4036
4037 if (e1 != v)
4038 {
4039 ASSERT(e2 != v);
4040 ASSERT(embedg_VES_is_edge(n, e1));
4041 ASSERT(embedg_VES_is_edge(n, e2));
4042 }
4043
4044 e4 = embed_graph[vv].link[vvout];
4045 ASSERT(embedg_VES_is_edge(n, e4));
4046
4047 vvin = 1 ^ vvout;
4048 e3 = embed_graph[vv].link[vvin];
4049 ASSERT(embedg_VES_is_edge(n, e3));
4050
4051 /*
4052 must take care of the adjacency list's consistency of traversal
4053 (will be important only when recovering the embedding)
4054 */
4055 if (e1 == e2)
4056 {
4057 ASSERT(embed_graph[e1].link[0] == embed_graph[e1].link[1]);
4058 if (vin == vvout)
4059 /*
4060 the bicomp will be flipped:
4061 must take 1 ^ vvout - difficult to explain -- later...
4062 */
4063 {
4064 e1out = 1 ^ vvout;
4065 }
4066 else
4067 {
4068 e1out = vvout;
4069 }
4070 }
4071 else
4072 {
4073 e1out = embed_graph[e1].link[0] == v ? 0 : 1;
4074 }
4075 if (e3 == e4)
4076 {
4077 ASSERT(embed_graph[e3].link[0] == embed_graph[e3].link[1]);
4078 e3out = 1 ^ vin;
4079 e4in = vin;
4080 }
4081 else
4082 {
4083 e4in = embed_graph[e4].link[0] == vv ? 0 : 1;
4084 e3out = embed_graph[e3].link[0] == vv ? 0 : 1;
4085 }
4086
4087 IF_DEB(
4088 fprintf(stdout, "merge_simple_bicomp, before union of lists, e1\n");
4089 embedg_VES_print_edge(embed_graph, n, e1);
4090 fprintf(stdout, "merge_simple_bicomp, e3\n");
4091 embedg_VES_print_edge(embed_graph, n, e3);
4092 fprintf(stdout, "merge_simple_bicomp, e4\n");
4093 embedg_VES_print_edge(embed_graph, n, e4);
4094 )
4095
4096 /*
4097 make e1 and e4 consecutive in the adjacency list
4098 */
4099 embed_graph[e1].link[e1out] = e4;
4100 embed_graph[e4].link[e4in] = e1;
4101 embed_graph[e3].link[e3out] = v;
4102 embed_graph[v].link[vin] = e3;
4103
4104 IF_DEB(
4105 fprintf(stdout, "merge_simple_bicomp, after union of lists, e1\n");
4106 embedg_VES_print_edge(embed_graph, n, e1);
4107 fprintf(stdout, "merge_simple_bicomp, e3\n");
4108 embedg_VES_print_edge(embed_graph, n, e3);
4109 fprintf(stdout, "merge_simple_bicomp, e4\n");
4110 embedg_VES_print_edge(embed_graph, n, e4);
4111 )
4112
4113 /*
4114 also, want to "disable" vv links, meaning then that
4115 vv is no longer a root of a bicomp
4116 */
4117 embed_graph[vv].link[0] = embed_graph[vv].link[1] = vv;
4118
4119 IF_DEB_ADJL(
4120 fprintf(stdout, "merge_simple_bicomp, adj. list for %d (after)\n", vv);
4121 embedg_VES_print_adj_list(embed_graph, n, vv,
4122 TRUE);
4123 fprintf(stdout, "\n");
4124 embedg_VES_print_adj_list(embed_graph, n, vv,
4125 FALSE);
4126 fprintf(stdout, "\n");
4127
4128 fprintf(stdout, "merge_simple_bicomp, adj. list for %d (after)\n", v);
4129 embedg_VES_print_adj_list(embed_graph, n, v,
4130 TRUE);
4131 fprintf(stdout, "\n");
4132 embedg_VES_print_adj_list(embed_graph, n, v,
4133 FALSE);
4134 )
4135
4136 ASSERT(embedg_VES_is_adj_list_consistent(embed_graph, n, v));
4137
4138 /*
4139 finally, give an orientation to the (formerly) root edge [vv, c]
4140 to keep traversal consistent (when recovering embedding)
4141 */
4142 if (vin == vvout)
4143 /*
4144 flip: set the sign of the root edge to clockwise
4145
4146 note: a bicomp is merged only once, so there is no need to
4147 "flip" the root_edge's sign: it is set once at initialisation
4148 and then changed here if need be.
4149 */
4150 {
4151 embed_graph[root_edge].sign = CLOCKW;
4152
4153 IF_VERB(
4154 fprintf(stdout, "merge_simple_bicomp, flip for %d, sign is now %d for %d of type %d\n",
4155 c, embed_graph[root_edge].sign, root_edge, embed_graph[root_edge].type);
4156 embedg_VES_print_edge(embed_graph, n, root_edge);
4157 )
4158 }
4159 }
4160
4161
4162
4163 void
embedg_VES_merge_pertinent_bicomps(t_ver_edge * embed_graph,int n,int vv,int vvout,int v,int vin)4164 embedg_VES_merge_pertinent_bicomps (t_ver_edge *embed_graph, int n,
4165 int vv, int vvout, int v, int vin)
4166 /*
4167 the bicomps to be merged are pertinent: on top (and before)
4168 performing a simple merge, there are several things to do
4169 related to the merging to pertinent bicomps
4170 */
4171 {
4172 /*
4173 a note of caution:
4174 it is (very) likely that after a bicomp merge the resulting
4175 bicomp is not biconnected (and hence traversal of the external face
4176 of the bicomp via embedg_VES_get_succ_on_ext_face is non-sensical)
4177
4178 remembering that a PERTINENT bicomp merge is ALWAYS followed
4179 by a back edge embedding we see that the end result is then a bicomp
4180 where again traversal of the external face
4181 via embedg_VES_get_succ_on_ext_face will make sense
4182 */
4183 t_dlcl *pertinent_list, *head, *rep_in_parent_list, *parent_list;
4184 int c;
4185
4186 /*
4187 find c such that [v^c, c] is the root edge of the bicomp
4188 rooted at vv = v^c
4189 */
4190 c = vv - n;
4191 ASSERT(embed_graph[c].DFS_parent == v);
4192
4193 /*
4194 two things to do first:
4195 - remove vv from head of pertinent_bicomp_list of v
4196 - remove c from separated_DFS_child_list of v
4197
4198 one may ask the point of this since the separated_DFS_child_list
4199 seems to mirror pertinent_bicomp_list: but this is not exactly so:
4200 + pertinent_bicomp_list is ordered according to the activity
4201 of the (virtual) vertices
4202 + separated_DFS_child_list is ordered according to the vertices'
4203 lowpoint values
4204 in effect, it could (almost?*) be said that these two lists
4205 are in reverse order (the *almost bit would warrant some thinking here)
4206 */
4207
4208 /*
4209 remove vv from head of pertinent_bicomp_list of v
4210 */
4211 pertinent_list = head = embed_graph[v].pertinent_bicomp_list;
4212 ASSERT(!embedg_dlcl_is_empty(pertinent_list));
4213 ASSERT(head->info == vv);
4214
4215 IF_DEB(
4216 fprintf(stdout, "merge_pertinent_bicomp, start: merge\n");
4217 embedg_VES_print_virtual_vertex(embed_graph, n, vv);
4218 fprintf(stdout, ":%d & ", vvout);
4219 embedg_VES_print_vertex(n, v);
4220 fprintf(stdout, ":%d\n", vin);
4221 )
4222
4223 IF_DEB(
4224 fprintf(stdout, "merge_pertinent_bicomp, pertinent bicomp_list of %d (before)\n", v);
4225 embedg_dlcl_print(embed_graph[v].pertinent_bicomp_list);
4226 )
4227
4228
4229 embed_graph[v].pertinent_bicomp_list =
4230 embedg_dlcl_delete_first(pertinent_list);
4231
4232 IF_DEB(
4233 fprintf(stdout, "merge_pertinent_bicomp, pertinent bicomp_list of %d (after)\n", v);
4234 embedg_dlcl_print(embed_graph[v].pertinent_bicomp_list);
4235 )
4236
4237 /*
4238 vv = v^c: remove c from separated_DFS_child_list of v
4239 */
4240 rep_in_parent_list = embed_graph[c].rep_in_parent_list;
4241 ASSERT(!embedg_dlcl_is_empty(rep_in_parent_list));
4242
4243 parent_list = embed_graph[v].separated_DFS_child_list;
4244 ASSERT(!embedg_dlcl_is_empty(parent_list));
4245 embed_graph[v].separated_DFS_child_list =
4246 embedg_dlcl_delete_rec(parent_list, rep_in_parent_list);
4247
4248 /*
4249 that's it, it remains to merge, ie. union the adjacency list,
4250 and flipping the bicomp if necessary
4251 */
4252 embedg_VES_merge_simple_bicomps(embed_graph, n,
4253 vv, vvout, v, vin);
4254 }
4255
4256
4257
4258
4259
4260
4261 /*
4262 * embed_edge.c
4263 */
4264
4265 /*
4266 What:
4267 *****
4268
4269 Implementing:
4270
4271 Embedding an edge so that it lies on the external face of a bicomp.
4272 We work here with the VES structure.
4273
4274
4275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4276 from
4277
4278 Simplified O(n) Planarity Algorithms (draft)
4279 ************************************
4280
4281 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
4282 Wendy Myrvold wendym@csr.uvic.ca
4283
4284
4285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4286 authors:
4287 ********
4288
4289 Paulette Lieby (Magma), Brendan McKay (ANU)
4290
4291 Started October 2001
4292 */
4293
4294
4295 #include "planarity.h"
4296
4297 #define IF_DEB(x) {}
4298 #define IF_DEB_EMBED(x) {}
4299 #define IF_VERB(x) {}
4300
4301
4302 /* aproto: header embed_graph_protos.h */
4303
4304
4305 void
embedg_VES_embed_edge(t_ver_edge * embed_graph,int n,int * edge_pos,int edge_type,int vv,int vvout,int w,int win)4306 embedg_VES_embed_edge (t_ver_edge *embed_graph, int n, int *edge_pos,
4307 int edge_type, int vv, int vvout, int w, int win)
4308 /*
4309 embed the edge (vv, w) (vv a virtual vertex, w a vertex) between
4310 vv and the edge vvout
4311 and the edge win and w
4312
4313 so that after the embedding, one exits vv via (vv, w) and
4314 enters w via the twin (w, vv)
4315 */
4316 {
4317 int temp, tempin, tempout;
4318
4319 ASSERT(edge_type == BE || edge_type == SCE);
4320 ASSERT(embedg_VES_is_virtual_vertex(n, vv));
4321 ASSERT(embedg_VES_is_vertex(n, w));
4322
4323 IF_DEB(
4324 fprintf(stdout, "embed_edge, (%d:%d)\n", vv, w);
4325 )
4326
4327 /*
4328 first, set the edge [vv, w] with the appropriate info
4329
4330 when [vv, w] is a back edge there is some more work to do
4331 (see the walkup procedure for the extra information we need
4332 to copy here
4333 */
4334 (*edge_pos)++;
4335 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
4336 embed_graph[*edge_pos].neighbour = w;
4337 embed_graph[*edge_pos].type = edge_type;
4338 embed_graph[*edge_pos].sign = CCLOCKW;
4339 if (edge_type == BE)
4340 {
4341 ASSERT(embed_graph[w].adjacent_to ==
4342 embed_graph[vv - n].DFS_parent);
4343
4344 /*
4345 PLUS: originally when the back edge [w, vv] was
4346 created (in the dfs preprocessing stage), it carried in
4347 .in_adjl the index of this directed edge in the
4348 adjacency list
4349
4350 but now, note that we are actually inserting the
4351 directed edge [vv, w] in vv's adjacency list,
4352 meaning that in_adjl and twin_in_adjl
4353 must be exchanged!
4354 */
4355 embed_graph[*edge_pos].in_adjl = embed_graph[w].twin_in_adjl;
4356 embed_graph[*edge_pos].twin_in_adjl = embed_graph[w].in_adjl;
4357
4358 ASSERT(embed_graph[w].mult % 2 == 0);
4359 /*
4360 the original graph is always undirected:
4361 we store its number of undirected edges
4362 */
4363 embed_graph[*edge_pos].mult = embed_graph[w].mult / 2;
4364 }
4365
4366 /*
4367 insert this edge between vertex record for vv
4368 and edge record vv.link[vvout]
4369 */
4370 temp = embed_graph[vv].link[vvout];
4371
4372 if (embed_graph[temp].link[0] == embed_graph[temp].link[1])
4373 /*
4374 this needs special treatment to ensure consistency of
4375 orientation
4376 */
4377 {
4378 ASSERT(embed_graph[temp].link[0] == vv);
4379 tempin = 1 ^ vvout;
4380 }
4381 else
4382 {
4383 tempin = embed_graph[temp].link[0] == vv ? 0 : 1;
4384 }
4385
4386 IF_DEB(
4387 fprintf(stdout, "embed_edge, edge out of vv\n");
4388 embedg_VES_print_edge(embed_graph, n, temp);
4389 )
4390
4391 embed_graph[vv].link[vvout] = *edge_pos;
4392 embed_graph[temp].link[tempin] = *edge_pos;
4393 /*
4394 the links for *edge_pos must also be "consistent"
4395 */
4396 embed_graph[*edge_pos].link[vvout] = temp;
4397 embed_graph[*edge_pos].link[vvout ^ 1] = vv;
4398
4399 /*
4400 now create/set the twin edge, the directed edge [w, vv]
4401 */
4402 (*edge_pos)++;
4403 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
4404 embed_graph[*edge_pos].neighbour = vv;
4405 embed_graph[*edge_pos].type = edge_type;
4406 embed_graph[*edge_pos].sign = CCLOCKW;
4407 if (edge_type == BE)
4408 {
4409 embed_graph[*edge_pos].in_adjl = embed_graph[w].in_adjl;
4410 embed_graph[*edge_pos].twin_in_adjl = embed_graph[w].twin_in_adjl;
4411 embed_graph[*edge_pos].mult = embed_graph[w].mult / 2;
4412 }
4413
4414 /*
4415 and insert the twin edge between edge record w.link[win]
4416 and vertex record for w
4417 */
4418 temp = embed_graph[w].link[win];
4419
4420 if (embed_graph[temp].link[0] == embed_graph[temp].link[1])
4421 /*
4422 again, special treatment to ensure consistency of orientation
4423 */
4424 {
4425 ASSERT(embed_graph[temp].link[0] == w);
4426 tempout = 1 ^ win;
4427 }
4428 else
4429 {
4430 tempout = embed_graph[temp].link[0] == w ? 0 : 1;
4431 }
4432
4433 IF_DEB(
4434 fprintf(stdout, "embed_edge, edge in of w\n");
4435 embedg_VES_print_edge(embed_graph, n, temp);
4436 )
4437
4438 embed_graph[w].link[win] = *edge_pos;
4439 embed_graph[temp].link[tempout] = *edge_pos;
4440 /*
4441 and consistent orientation
4442 */
4443 embed_graph[*edge_pos].link[win] = temp;
4444 embed_graph[*edge_pos].link[win ^ 1] = w;
4445 }
4446
4447
4448
4449 void
embedg_VES_add_edge(t_ver_edge * embed_graph,int n,int * edge_pos,int v,int w,boolean MARK,int mark)4450 embedg_VES_add_edge (t_ver_edge *embed_graph, int n, int *edge_pos,
4451 int v, int w, boolean MARK, int mark)
4452 /*
4453 add the edge (v, w): this is DIFFERENT from
4454 embedg_VES_embed_edge in the sense
4455 that the present function will only be used
4456 when building the Kuratowski homeomorphs:
4457
4458 that is, we are in a situation where the graph is NON planar
4459
4460 consequently it doesn't matter much where in the adjacency
4461 lists of v & w the edge is added:
4462 let's say that we always add it at the beginning
4463
4464 for our sanity's sake, we'll ensure that the resulting
4465 adjacency lists remain consistent!
4466
4467 and we add the edge as a BE!
4468 PLUS we mark it with mark in MARK true
4469 */
4470 {
4471 int temp;
4472
4473 ASSERT(embedg_VES_is_vertex(n, v) ||
4474 embedg_VES_is_virtual_vertex(n, v));
4475 ASSERT(embedg_VES_is_vertex(n, w) ||
4476 embedg_VES_is_virtual_vertex(n, w));
4477
4478 IF_DEB(
4479 fprintf(stdout, "add_edge, (%d:%d)\n", v, w);
4480 )
4481
4482 /*
4483 not sure this is the best place to do this: mark the endpoints
4484 */
4485 if (MARK)
4486 {
4487 embed_graph[v].visited = mark;
4488 embed_graph[w].visited = mark;
4489 }
4490
4491 /*
4492 first, set the edge [v, w] with the appropriate info
4493 */
4494 (*edge_pos)++;
4495 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
4496 embed_graph[*edge_pos].neighbour = w;
4497 embed_graph[*edge_pos].type = BE;
4498 /*
4499 the edge's orientation will be the same as the vertex
4500 */
4501 embed_graph[*edge_pos].sign = embed_graph[v].sign;
4502 /*
4503 and mark the edge
4504 */
4505 if (MARK)
4506 {
4507 embed_graph[*edge_pos].visited = mark;
4508 }
4509
4510 /*
4511 insert this edge between vertex record for v
4512 and edge record v.link[1]
4513 */
4514 temp = embed_graph[v].link[1];
4515
4516 IF_DEB(
4517 fprintf(stdout, "add_edge, edge out of v\n");
4518 embedg_VES_print_edge(embed_graph, n, temp);
4519 )
4520
4521 embed_graph[v].link[1] = *edge_pos;
4522 embed_graph[temp].link[0] = *edge_pos;
4523 /*
4524 the links for *edge_pos must also be "consistent"
4525 */
4526 embed_graph[*edge_pos].link[1] = temp;
4527 embed_graph[*edge_pos].link[0] = v;
4528
4529 /*
4530 now create/set the twin edge, the directed edge [w, v]
4531 */
4532 (*edge_pos)++;
4533 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
4534 embed_graph[*edge_pos].neighbour = v;
4535 embed_graph[*edge_pos].type = BE;
4536 embed_graph[*edge_pos].sign = embed_graph[w].sign;
4537 if (MARK)
4538 {
4539 embed_graph[*edge_pos].visited = mark;
4540 }
4541
4542 /*
4543 insert this edge between vertex record for w
4544 and edge record w.link[1]
4545 */
4546 temp = embed_graph[w].link[1];
4547
4548 IF_DEB(
4549 fprintf(stdout, "add_edge, edge out of w\n");
4550 embedg_VES_print_edge(embed_graph, n, temp);
4551 )
4552
4553 embed_graph[w].link[1] = *edge_pos;
4554 embed_graph[temp].link[0] = *edge_pos;
4555 /*
4556 and consistent orientation
4557 */
4558 embed_graph[*edge_pos].link[1] = temp;
4559 embed_graph[*edge_pos].link[0] = w;
4560 }
4561
4562
4563 /*
4564 * recover.c
4565 */
4566
4567 /*
4568 What:
4569 *****
4570
4571 Implementing:
4572
4573 From the VES data structure recover either the embedding ot
4574 the obstruction into the
4575
4576 t_sparseg_ver_struct,
4577 t_sparseg_adjl_struct,
4578 t_sparseg_embed_struct
4579
4580 data types.
4581
4582
4583 (This is no even quite true: for some obscure reason
4584 I recover the obstruction as a dlcl[] structure to be
4585 converted later.
4586 The obvious reason being that it is easier to check as such.
4587 Maybe I leave it as it is...)
4588
4589 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4590 from
4591
4592 Simplified O(n) Planarity Algorithms (draft)
4593 ************************************
4594
4595 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
4596 Wendy Myrvold wendym@csr.uvic.ca
4597
4598
4599 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4600 authors:
4601 ********
4602
4603 Paulette Lieby (Magma), Brendan McKay (ANU)
4604
4605 Started October 2001
4606 */
4607
4608
4609 #include "planarity.h"
4610
4611 #define IF_DEB(x) {}
4612 #define IF_DEB_EMBED_MULT(x) {}
4613 #define IF_DEB_EMBED_LOOPS(x) {}
4614 #define IF_DEB_EMBED(x) {}
4615 #define IF_DEB_CHECK_EMBED(x) {}
4616 #define IF_DEB_FACES(x) {}
4617 #define IF_VERB(x) {}
4618 #define IF_DEB_SCE(x) {}
4619 #define IF_DEB_OBS(x) {}
4620 #define IF_DEB_CHECK_OBS(x) {}
4621 #define IF_CPU(x) {}
4622
4623
4624
4625 /* aproto: header embed_graph_protos.h */
4626
4627 /* aproto: beginstatic -- don't touch this!! */
4628 static void embedg_recover_embedding_embed_mult
4629 (t_dlcl **, t_embed_sparse_rep *, int, int, int, int, int *, boolean *, int *);
4630 static void embedg_recover_embedding_embed_loops
4631 (t_dlcl **, t_embed_sparse_rep *, int, int, int *, boolean *);
4632 static t_dlcl **embedg_get_reduced_obs (t_dlcl **, int);
4633 static boolean embedg_is_red_obs_K33 (t_dlcl **, int);
4634 static boolean embedg_is_red_obs_K5 (t_dlcl **, int);
4635 /* aproto: endstatic -- don't touch this!! */
4636
4637
4638 #ifndef PLANAR_IN_MAGMA
4639 #endif
4640
4641 void
embedg_recover_embedding(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,t_ver_edge * embed_graph,int n,int nbr_e,t_dlcl ** mult_edges,t_ver_sparse_rep ** vertices,t_embed_sparse_rep ** embedding)4642 embedg_recover_embedding (
4643 t_ver_sparse_rep *V,
4644 t_adjl_sparse_rep *A, /* input (original sparse graph) */
4645 t_ver_edge *embed_graph,
4646 int n,
4647 int nbr_e,
4648 t_dlcl **mult_edges,
4649 t_ver_sparse_rep **vertices,
4650 t_embed_sparse_rep **embedding
4651 )
4652 /*
4653 recover the embedding
4654 to prepare for the final Magma type for sparse & embedded graph
4655
4656 we assume that all vertices/edges have been given their
4657 orientation
4658
4659 at this stage we also embed the multiple edges and loops
4660 which were set aside in mult_edges by
4661 sparseg_adjl_dfs_preprocessing:
4662
4663 as it turns out the last bit is pretty hairy!
4664 */
4665 {
4666 /*
4667 the idea is to return an array of vertices and an array
4668 representing the embedding
4669 (careful: need to weedout the SCE)
4670
4671 vertices: (*vertices)[i].first_edge contains index
4672 to first edge in embedding
4673
4674 embedding: a doubly linked circular list of edges,
4675 for each record/edge e = (*embedding)[i]:
4676 e.in_adjl: index in A of e
4677 e.next: next edge in CLOCKW
4678 (as an index in the embedding)
4679 e.prev: previous edge in CLOCKW
4680 (as an index in embedding)
4681 e.inv: inverse edge (as an index in embedding)
4682 e.mark: a mark for this edge
4683
4684 let's say that this new array is a slimmed down version of embed_graph
4685
4686 one issue to address:
4687 - for edge e, find its index in A: this should be found
4688 in either the embed_graph[v] record of the mult_edges[v] record
4689 */
4690 int index_embed, v, mult, w, v_w_in_embed, new_first_edge;
4691 boolean set_next;
4692
4693 IF_DEB(
4694 fprintf(stdout, "in recover emb.\n");
4695 sparseg_dlcl_print(mult_edges, n);
4696 );
4697
4698 *vertices = (t_ver_sparse_rep *)
4699 mem_malloc(sizeof(t_ver_sparse_rep) * n);
4700 *embedding = (t_embed_sparse_rep *)
4701 mem_malloc(sizeof(t_embed_sparse_rep) * 2 * nbr_e);
4702
4703 index_embed = 0;
4704 set_next = TRUE;
4705 for (v = 0; v < n; v++)
4706 {
4707 int v_l, orient, in, out, e, cur_e, next_e;
4708
4709 /*
4710 we take v's label
4711 */
4712 v_l = embed_graph[v].label;
4713
4714 /*
4715 first let's deal with the isolated vertex case: those
4716 that refer to self
4717 */
4718 if (embed_graph[v].link[0] == v)
4719 {
4720 int temp_index_embed;
4721
4722 ASSERT(embed_graph[v].link[1] == v);
4723
4724 /*
4725 there may be [v, v] loops for this vertex, must check this
4726 */
4727 temp_index_embed = index_embed - 1;
4728 /*
4729 temp_index_embed is pre-increased below
4730 */
4731 embedg_recover_embedding_embed_loops(mult_edges, *embedding,
4732 nbr_e, v,
4733 &temp_index_embed,
4734 &set_next);
4735
4736 if (temp_index_embed > index_embed - 1)
4737 /*
4738 must fix beginning and end of adjacency list:
4739 */
4740 {
4741 (*vertices)[v_l].first_edge = index_embed;
4742 (*embedding)[temp_index_embed].next =
4743 (*vertices)[v_l].first_edge;
4744 (*embedding)[(*vertices)[v_l].first_edge].prev =
4745 temp_index_embed;
4746
4747 index_embed = temp_index_embed;
4748 index_embed += 1;
4749 }
4750 else
4751 {
4752 (*vertices)[v_l].first_edge = NIL;
4753 }
4754 continue;
4755 }
4756
4757 /*
4758 get v's orientation, and from this decide the way in which
4759 v's adjacency list will be traversed
4760 (recall that the list is supposed to be consistent, so no bad
4761 surprises)
4762 */
4763 orient = embed_graph[v].sign;
4764 in = orient == CCLOCKW ? 0 : 1;
4765 out = 1 ^ in;
4766
4767 e = embed_graph[v].link[out];
4768 while (embedg_VES_is_short_cut_edge(embed_graph, n, e))
4769 {
4770 e = embed_graph[e].link[out];
4771 }
4772 ASSERT(embedg_VES_is_edge(n, e)
4773 && !embedg_VES_is_short_cut_edge(embed_graph, n, e));
4774 /*
4775 strictly speaking there should be no SCEs left at this stage...
4776
4777 if there are SCEs in v's list, it must be the case that
4778 the list also contains tree or back edges...
4779 */
4780
4781 (*vertices)[v_l].first_edge = index_embed;
4782
4783 IF_DEB_EMBED(
4784 fprintf(stdout, "recov. embed. DFI %d vertex %d at %d (edges) and %d (embedding)\n",
4785 v, v_l, index_e, (*vertices)[v_l].first_edge);
4786 )
4787
4788 cur_e = e;
4789 while (TRUE)
4790 {
4791 next_e = embed_graph[cur_e].link[out];
4792 while (embedg_VES_is_short_cut_edge(embed_graph, n, next_e))
4793 {
4794 next_e = embed_graph[next_e].link[out];
4795 }
4796 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph, n, next_e));
4797
4798 if (next_e == v)
4799 /*
4800 end of adjacency list
4801 */
4802 {
4803 break;
4804 }
4805
4806 ASSERT(embedg_VES_is_edge(n, next_e));
4807
4808 (*embedding)[index_embed].in_adjl = embed_graph[cur_e].in_adjl;
4809 (*embedding)[index_embed].next = index_embed + 1; /* next in adj.
4810 list */
4811 (*embedding)[index_embed].mark = NIL; /* mark */
4812
4813 /*
4814 cur_e's twin is trickier:
4815 we'll use twin's label field to store cur_e's index in
4816 the embedding
4817
4818 if cur_e's label != NIL this means that cur_e's twin
4819 is already stored in edges/embedding and consequently
4820 that cur_e.label = index of its twin (in the embedding)
4821
4822 note that it is safe to do so since an edge's label
4823 has no meaning
4824 */
4825 if (embed_graph[cur_e].label != NIL)
4826 {
4827 (*embedding)[index_embed].inv = embed_graph[cur_e].label;
4828
4829 /*
4830 but fix the twin by the same token
4831 */
4832 (*embedding)[embed_graph[cur_e].label].inv = index_embed;
4833 ASSERT((*embedding)[embed_graph[cur_e].label].in_adjl ==
4834 embed_graph[cur_e].twin_in_adjl);
4835 }
4836 else
4837 /*
4838 we store cur_e's index in the embedding in twin's label
4839 */
4840 {
4841 int twin;
4842
4843 twin = embedg_VES_get_twin_edge(embed_graph, n, cur_e);
4844 embed_graph[twin].label = index_embed;
4845 }
4846
4847 /*
4848 so the only thing we couldn't update yet is
4849 (*embedding)[index_embed].prev, cur_e previous edge in the list
4850
4851 but we can do this for next_e
4852 */
4853 (*embedding)[index_embed + 1].prev = index_embed;
4854
4855 /*
4856 we check if there are any multiple edges or loops
4857 to embed
4858 */
4859 w = embed_graph[cur_e].neighbour;
4860 mult = embed_graph[cur_e].mult - 1;
4861 /*
4862 one was for the TE or BE edge
4863 */
4864
4865 if (index_embed == (*vertices)[v_l].first_edge)
4866 /*
4867 when looking for multiple edges/loops
4868 we must temporarily "close" this ordered
4869 list of vertices when in presence of the first
4870 edge in the list:
4871
4872 not doing this would mean that
4873 (*embedding)[(*vertices)[v_l].first_edge].prev
4874 contains some irrelevant value which may cause
4875 (major) trouble when embedding inverses of
4876 multiple edges...
4877 */
4878 {
4879 (*embedding)[(*vertices)[v_l].first_edge].prev = index_embed;
4880 }
4881
4882 embedg_recover_embedding_embed_mult(mult_edges, *embedding,
4883 nbr_e, v, w, mult,
4884 &index_embed, &set_next,
4885 &new_first_edge);
4886 embedg_recover_embedding_embed_loops(mult_edges, *embedding,
4887 nbr_e, v, &index_embed,
4888 &set_next);
4889 set_next = TRUE;
4890
4891 /*
4892 yes, it may be the case that (*vertices)[v_l].first_edge
4893 change while in embedg_recover_embedding_embed_mult
4894 -- see that function for more
4895 */
4896 (*vertices)[v_l].first_edge = new_first_edge == NIL ?
4897 (*vertices)[v_l].first_edge : new_first_edge;
4898
4899 /*
4900 that's all, we proceed to read a new edge in the list
4901 */
4902 index_embed += 1;
4903 cur_e = next_e;
4904 }
4905
4906 /*
4907 now next_e = v so that cur_e is the last edge in v's adjacency list
4908 we must deal with this case separately
4909 */
4910
4911 /*
4912 fix cur_e in embedding (and its twin)
4913 */
4914 (*embedding)[index_embed].in_adjl = embed_graph[cur_e].in_adjl;
4915
4916 /*
4917 we temporarily set next of cur_e in to index_embed + 1
4918 */
4919 (*embedding)[index_embed].next = index_embed + 1;
4920 (*embedding)[index_embed].mark = NIL; /* mark */
4921
4922 /*
4923 fix cur_e's twin
4924 */
4925 if (embed_graph[cur_e].label != NIL)
4926 {
4927 (*embedding)[index_embed].inv = embed_graph[cur_e].label;
4928 (*embedding)[embed_graph[cur_e].label].inv = index_embed;
4929 ASSERT((*embedding)[embed_graph[cur_e].label].in_adjl ==
4930 embed_graph[cur_e].twin_in_adjl);
4931 }
4932 else
4933 {
4934 int twin;
4935
4936 twin = embedg_VES_get_twin_edge(embed_graph, n, cur_e);
4937 embed_graph[twin].label = index_embed;
4938 }
4939
4940 /*
4941 we temporarily set the next record's prev field:
4942 but we can do that only if we haven't processed
4943 all the edges yet
4944 */
4945 if (index_embed < 2 * nbr_e - 1)
4946 {
4947 (*embedding)[index_embed + 1].prev = index_embed;
4948
4949 /*
4950 again, check if there are any multiple edges/loops
4951 to embed
4952 */
4953 w = embed_graph[cur_e].neighbour;
4954 mult = embed_graph[cur_e].mult - 1;
4955 /*
4956 one was for the TE or BE edge
4957 */
4958 v_w_in_embed = index_embed;
4959
4960 if (index_embed == (*vertices)[v_l].first_edge)
4961 /*
4962 same comment as above
4963 */
4964 {
4965 (*embedding)[(*vertices)[v_l].first_edge].prev = index_embed;
4966 }
4967
4968 embedg_recover_embedding_embed_mult(mult_edges, *embedding,
4969 nbr_e, v, w, mult,
4970 &index_embed, &set_next,
4971 &new_first_edge);
4972 embedg_recover_embedding_embed_loops(mult_edges, *embedding,
4973 nbr_e, v, &index_embed,
4974 &set_next);
4975
4976 /*
4977 same comment as above
4978 */
4979 (*vertices)[v_l].first_edge = new_first_edge == NIL ?
4980 (*vertices)[v_l].first_edge : new_first_edge;
4981 }
4982
4983 /*
4984 to finish off, we must set:
4985
4986 cur_e's next field:
4987 next of cur_e in the list is ... vertices[v_l].first_edge
4988
4989 cur_e's next's previous field...
4990 */
4991 if (set_next)
4992 /*
4993 set_next (poorly named) is used to indicate which
4994 edges must be updated to "close off" the list:
4995
4996 if set_next is TRUE, we are in the standard case
4997 where the last edge in the ordered adj. list
4998 is at index_embed
4999
5000 if set_next is FALSE, the last edge in the ordered adj. list
5001 is at v_w_in_embed: because it could have happened
5002 (in embedg_recover_embedding_embed_mult only)
5003 that the edges have been "wedged" between
5004 v_w_in_embed.prev and v_w_in_embed,
5005 leaving v_w_in_embed the last in the list
5006 */
5007 {
5008 (*embedding)[index_embed].next = (*vertices)[v_l].first_edge;
5009 (*embedding)[(*vertices)[v_l].first_edge].prev = index_embed;
5010 }
5011 else
5012 {
5013 (*embedding)[v_w_in_embed].next = (*vertices)[v_l].first_edge;
5014 (*embedding)[(*vertices)[v_l].first_edge].prev = v_w_in_embed;
5015 }
5016 set_next = TRUE;
5017
5018 /*
5019 a simple check
5020 */
5021 ASSERT(embedg_dlcl_is_empty(mult_edges[v]));
5022
5023 /*
5024 we can process another vertex
5025 */
5026 index_embed += 1;
5027 }
5028 /*
5029 when this is done there are a few things that must hold
5030 */
5031 ASSERT(index_embed == 2 * nbr_e);
5032 }
5033
5034
5035 static void
embedg_recover_embedding_embed_mult(t_dlcl ** mult_edges,t_embed_sparse_rep * embedding,int nbr_e,int v,int w,int mult,int * index_embed,boolean * set_next,int * first_edge)5036 embedg_recover_embedding_embed_mult (t_dlcl **mult_edges,
5037 t_embed_sparse_rep *embedding, int nbr_e, int v, int w,
5038 int mult, int *index_embed, boolean *set_next, int *first_edge)
5039 /*
5040 see if the directed edge [v, w] is multiple: if so embed it
5041 in embedding
5042
5043 moreover if there are any [v, v] loops do that too
5044 */
5045 {
5046 /*
5047 we take care of multiple edges: for tree edges and back
5048 edges their multiplicity is indicated by the
5049 embed_graph[cur_e].mult field (which records the number
5050 of undirected edges)
5051
5052 for loops hovewer this information is stored in the mult
5053 field of the FIRST encountered neighbour v in v's neighbour
5054 list
5055 */
5056 t_dlcl *p;
5057 int v_w_in_embed, v_w_prev;
5058 boolean do_twins, start, do_first_edge;
5059
5060 IF_DEB_EMBED_MULT(
5061 fprintf(stdout, "in recover emb. mult, v %d w %d mult %d\n",
5062 v, w, mult);
5063 )
5064
5065 /*
5066 the current index_embed value is the edge [v, w]:
5067 I must record this value as it will be needed
5068 later
5069 */
5070 v_w_in_embed = *index_embed;
5071 start = TRUE;
5072 *set_next = TRUE;
5073 do_twins = FALSE;
5074 *first_edge = NIL;
5075 do_first_edge = FALSE;
5076 v_w_prev = NIL;
5077 while (mult > 0)
5078 {
5079 ASSERT(!embedg_dlcl_is_empty(mult_edges[v]));
5080 p = embedg_dlcl_find(mult_edges[v], w);
5081 /*
5082 note that using embedg_dlcl_find to always find
5083 the first in the list with p->info == w
5084 is ok here since any previous such records would
5085 have been deleted/removed from the list
5086 */
5087 ASSERT(p != NP);
5088 /*
5089 otherwise we couldn't have mult > 0 !
5090 */
5091
5092 *index_embed += 1;
5093
5094 /*
5095 once again I must use a similar sort of trick as in the
5096 main function to deal with the inverse edge:
5097
5098 the inverse edge is to be found in mult_edges[w]:
5099 if p->twin_in_adjl (which was initialised to NIL
5100 and has NOT been set in the DFS preprocessing),
5101 if p->twin_in_adjl != NIL, then
5102 a. its inverse in mult_edges[w] has already been embedded
5103 in *embedding
5104 b. its index there is stored in p->twin_in_adjl
5105 precisely
5106 */
5107 if (p->twin_in_adjl != NIL)
5108 {
5109 if (! start)
5110 /*
5111 if the first the multiple edges' inverse is already
5112 stored, then this is true for ALL of them
5113 */
5114 {
5115 ASSERT(do_twins == TRUE);
5116 }
5117 do_twins = TRUE;
5118 }
5119 else
5120 /*
5121 similarly, if the first the multiple edges' inverse is
5122 not already stored, then this is true for ALL of them
5123 */
5124 {
5125 ASSERT(do_twins == FALSE);
5126 }
5127
5128 embedding[*index_embed].in_adjl = p->in_adjl;
5129 embedding[*index_embed].mark = NIL;
5130
5131 /*
5132 as we will see do_twins has to be treated differently
5133 */
5134 if (!do_twins)
5135 /*
5136 this is pretty standard as works as the
5137 main recover function
5138 */
5139 {
5140 t_dlcl *i_m_l, *i_p;
5141
5142 embedding[*index_embed].next = *index_embed + 1;
5143
5144 /*
5145 we store the current index in the embedding in
5146 the twin/inverse's twin_in_adjl field
5147 */
5148 i_p = i_m_l = mult_edges[w];
5149 ASSERT(!embedg_dlcl_is_empty(i_m_l));
5150 i_p = embedg_dlcl_find_with_NIL_twin_in_adjl(i_m_l, v);
5151 ASSERT(i_p != NP);
5152 ASSERT(i_p->twin_in_adjl == NIL);
5153
5154 i_p->twin_in_adjl = *index_embed;
5155
5156 /*
5157 to finish off this bit we set embedding[*index_embed + 1].prev
5158
5159 but I can only set this prev field if I haven't reached
5160 the end of the embedding[] array: this is why we needed
5161 nbr_e (total number of edges to embed) as input
5162 */
5163
5164 if (*index_embed < 2 * nbr_e - 1)
5165 {
5166 embedding[*index_embed + 1].prev = *index_embed;
5167 }
5168 }
5169 else
5170 /*
5171 how to insert the inverses of multiple edges already
5172 in the embedding:
5173
5174 if one studies how the twin_in_adjl field has been
5175 set while dealing with the inverses of the
5176 present multiple edges one sees that
5177 the latter must be inserted in counter clockwise
5178 order (assuming that the inverses were inserted
5179 in clockwise order)
5180
5181 this is necessariy to ensure a correct matching between
5182 the edge and its inverse
5183 */
5184 {
5185
5186 embedding[*index_embed].inv = p->twin_in_adjl;
5187
5188 /*
5189 fix the twin by the same token
5190 */
5191 embedding[p->twin_in_adjl].inv = *index_embed;
5192
5193 /*
5194 general (reverse) insertion for these edges
5195 */
5196 embedding[*index_embed].prev = *index_embed + 1;
5197 embedding[*index_embed].next = *index_embed - 1;
5198
5199 /*
5200 ok, that was the easy bit, things are a bit more complicated
5201 below...
5202 */
5203 if (start)
5204 /*
5205 the edges are "wedged" between
5206 embedding[v_w_in_embed].prev and v_w_in_embed,
5207
5208 hence the following
5209 */
5210 {
5211 v_w_prev = embedding[v_w_in_embed].prev;
5212 if (v_w_prev == v_w_in_embed)
5213 /*
5214 in this case the first edge in the adj. list
5215 of the vertex whose first_edges is v_w_in_embed
5216 will be changed
5217 (because we insert in reverse order)
5218 */
5219 {
5220 do_first_edge = TRUE;
5221 }
5222
5223 embedding[*index_embed].next = v_w_in_embed;
5224 embedding[v_w_in_embed].prev = *index_embed;
5225
5226 ASSERT(embedding[embedding[*index_embed].inv].prev ==
5227 embedding[v_w_in_embed].inv);
5228 ASSERT(embedding[embedding[v_w_in_embed].inv].next ==
5229 embedding[*index_embed].inv);
5230 }
5231
5232 if (mult == 1)
5233 /*
5234 last inv. edge in this list to add
5235 */
5236 {
5237 ASSERT(v_w_prev != NIL);
5238
5239 /*
5240 must fix embedding[v_w_prev].next appropriately
5241 (and embedding[*index_embed].prev)
5242
5243 this may be overwritten later on, but not necessarily so
5244
5245 the next_set flag will enable us to decide
5246 which edge ends this adjacency list: see above
5247 */
5248
5249 embedding[*index_embed].prev = v_w_prev;
5250 embedding[v_w_prev].next = *index_embed;
5251 *set_next = FALSE;
5252
5253 ASSERT(embedding[embedding[*index_embed].inv].prev ==
5254 embedding[*index_embed - 1].inv);
5255 ASSERT(embedding[embedding[*index_embed - 1].inv].next ==
5256 embedding[*index_embed].inv);
5257
5258 if (do_first_edge)
5259 /*
5260 the first edge is the last one added
5261 */
5262 {
5263 *first_edge = *index_embed;
5264 }
5265
5266 embedding[v_w_in_embed].next = *index_embed + 1;
5267 if (*index_embed < 2 * nbr_e - 1)
5268 {
5269 embedding[*index_embed + 1].prev = v_w_in_embed;
5270 }
5271 }
5272
5273 ASSERT(embedding[embedding[*index_embed].inv].prev ==
5274 embedding[embedding[*index_embed].next].inv);
5275 }
5276
5277 /*
5278 to finish off this bit we delete the p record from m_l
5279 and set embedding[*index_embed + 1].prev
5280 */
5281 mult_edges[v] = embedg_dlcl_delete_rec(mult_edges[v], p);
5282
5283 mult--;
5284 start = FALSE;
5285 }
5286 /*
5287 conclusion: sevral days to get this working! *sigh*
5288 */
5289 }
5290
5291
5292
5293
5294 static void
embedg_recover_embedding_embed_loops(t_dlcl ** mult_edges,t_embed_sparse_rep * embedding,int nbr_e,int v,int * index_embed,boolean * set_next)5295 embedg_recover_embedding_embed_loops (t_dlcl **mult_edges,
5296 t_embed_sparse_rep *embedding, int nbr_e, int v,
5297 int *index_embed, boolean *set_next)
5298 /*
5299 embed the [v, v] loops
5300 */
5301 {
5302 /*
5303 the loops' multiplicity is stored in the mult
5304 field of the FIRST encountered neighbour v in v's neighbour
5305 list
5306 */
5307 t_dlcl *p;
5308 int nbr_loops;
5309
5310 /*
5311 have a look if there are any [v. v] loops
5312 */
5313 p = embedg_dlcl_find(mult_edges[v], v);
5314 if (p == NP)
5315 {
5316 return;
5317 }
5318
5319 /*
5320 when there are loops to add to the adjaceny list,
5321 edge insertion resume in the "normal" clockwaise saya, way:
5322 so we reset set_next to true
5323 */
5324 *set_next = TRUE;
5325
5326 nbr_loops = p->mult;
5327 ASSERT(nbr_loops % 2 == 0);
5328 /*
5329 we counted directed edges
5330 */
5331 nbr_loops /= 2;
5332
5333 IF_DEB_EMBED_LOOPS(
5334 fprintf(stdout, "in recover emb. loops, nbr_loops [v, v] %d\n",
5335 nbr_loops);
5336 )
5337
5338 while (nbr_loops > 0)
5339 /*
5340 a loop requires to embed two directed edges
5341 */
5342 {
5343 p = embedg_dlcl_find(mult_edges[v], v);
5344 ASSERT(p != NP);
5345
5346 *index_embed += 1;
5347
5348 embedding[*index_embed].in_adjl = p->in_adjl;
5349 embedding[*index_embed].next = *index_embed + 1;
5350 embedding[*index_embed].mark = NIL;
5351 embedding[*index_embed].inv = *index_embed + 1;
5352 embedding[*index_embed + 1].prev = *index_embed;
5353
5354 mult_edges[v] = embedg_dlcl_delete_rec(mult_edges[v], p);
5355
5356 IF_DEB_EMBED_LOOPS(
5357 fprintf(stdout, "in recover emb. loops, mid\n");
5358 embedg_dlcl_print(mult_edges[v]);
5359 );
5360
5361 /*
5362 now do the "inverse" loop
5363 */
5364 p = embedg_dlcl_find(mult_edges[v], v);
5365 ASSERT(p != NP);
5366
5367 *index_embed += 1;
5368
5369 embedding[*index_embed].in_adjl = p->in_adjl;
5370 embedding[*index_embed].next = *index_embed + 1;
5371 embedding[*index_embed].mark = NIL;
5372 embedding[*index_embed].inv = *index_embed - 1;
5373
5374 if (*index_embed < 2 * nbr_e - 1)
5375 {
5376 embedding[*index_embed + 1].prev = *index_embed;
5377 }
5378 mult_edges[v] = embedg_dlcl_delete_rec(mult_edges[v], p);
5379
5380 nbr_loops--;
5381
5382 IF_DEB_EMBED_LOOPS(
5383 fprintf(stdout, "in recover emb. loops, end\n");
5384 embedg_dlcl_print(mult_edges[v]);
5385 );
5386 }
5387 }
5388
5389
5390
5391
5392 void
embedg_recov_embed_walk_proper_face(int n,int e,t_adjl_sparse_rep * A,t_embed_sparse_rep * embedding,boolean MARK,int mark)5393 embedg_recov_embed_walk_proper_face (int n, int e, t_adjl_sparse_rep *A,
5394 t_embed_sparse_rep *embedding, boolean MARK, int mark)
5395 /*
5396 do a proper face walk in the recovered embedding starting
5397 at index e in the embedding
5398 */
5399 {
5400 int cur, next;
5401
5402 IF_DEB_FACES(
5403 fprintf(stdout, "recov. emb. proper face walk\n");
5404 fprintf(stdout, "[-, %d] ",
5405 A[embedding[e].in_adjl].end_vertex);
5406 )
5407
5408 cur = e;
5409 next = NIL;
5410 while (next != e)
5411 /*
5412 to get the next in a proper face traversal:
5413 get the previous of the cur's inverse
5414 */
5415 {
5416 int inv;
5417
5418 inv = embedding[cur].inv;
5419 next = embedding[inv].prev;
5420
5421 ASSERT(embedding[next].mark != mark);
5422
5423 if (MARK)
5424 {
5425 embedding[next].mark = mark;
5426 }
5427
5428 cur = next;
5429 IF_DEB_FACES(
5430 fprintf(stdout, "[-, %d] ",
5431 A[embedding[cur].in_adjl].end_vertex);
5432 )
5433 }
5434 IF_DEB_FACES(
5435 fprintf(stdout, "\n");
5436 )
5437 }
5438
5439
5440
5441 boolean
embedg_check_recov_embedding(int n,int nbr_e,int nbr_comp,t_ver_sparse_rep * vertices,t_adjl_sparse_rep * A,t_embed_sparse_rep * embedding)5442 embedg_check_recov_embedding (int n, int nbr_e, int nbr_comp,
5443 t_ver_sparse_rep *vertices, t_adjl_sparse_rep *A,
5444 t_embed_sparse_rep *embedding)
5445 /*
5446 check if the recovered embedding is a valid embedding
5447 SHOULD ONLY be use after creation, that is, after having
5448 recovered the embedding from the VES structure
5449 (because of the mark MIN_EMBED_MARK we use)
5450 */
5451 {
5452 int v, e, f;
5453
5454 f = 0;
5455 /*
5456 do all the edges in embedding:
5457 careful: we have 2 * nbr_e to visit (the edge and its inverse!)
5458 */
5459 for (e = 0; e < 2 * nbr_e; e++)
5460 {
5461 /*
5462 we check if the current edge is marked: if not, we
5463 traverse a proper face bordered by this edge
5464 */
5465 if (embedding[e].mark != MIN_EMBED_MARK)
5466 /*
5467 we --hopefully-- perform this check only after creation
5468 where mark == NIL
5469 */
5470 {
5471 embedg_recov_embed_walk_proper_face(n, e, A, embedding,
5472 TRUE, MIN_EMBED_MARK);
5473 f++;
5474 }
5475 }
5476
5477 /*
5478 must also count a face for each isolated vertex
5479 */
5480 for (v = 0; v < n; v++)
5481 {
5482 if (vertices[v].first_edge == NIL)
5483 f++;
5484 }
5485
5486 IF_DEB_CHECK_EMBED(
5487 fprintf(stdout, "recovered embedding, n: %d\t e: %d\t C: %d\t f: %d\n",
5488 n, nbr_e, nbr_comp, f);
5489 )
5490
5491 return f == 2 * nbr_comp + nbr_e - n ? TRUE : FALSE;
5492 }
5493
5494
5495 t_dlcl **
embedg_recover_obstruction(t_ver_edge * embed_graph,int n,minor m,int * nbr_e)5496 embedg_recover_obstruction (t_ver_edge *embed_graph, int n, minor m, int *nbr_e)
5497 /*
5498 recover the obstruction as a t_dlcl * structure:
5499 and return the number of edges: lets say we agree on returning
5500 the number of undirected edges
5501 -- I don't know yet which way to do, directed or undirected???
5502
5503 so far in the algorithm we only dealt with DFIs,
5504 but now, we retrieve the obstruction not wrt DFIs but
5505 wrt the vertices' labels
5506 */
5507 {
5508 /*
5509 so I am looking, in embed_graph, for the vertices and edges
5510 marked MARK_MINORS(n)
5511 */
5512
5513 int v;
5514 t_dlcl **obs;
5515
5516 obs = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
5517 for (v = 0; v < n; v++)
5518 obs[v] = NP;
5519
5520 *nbr_e = 0;
5521 for (v = 0; v < 2*n; v++)
5522 /*
5523 must check real vertices as well as virtual vertices
5524 */
5525 {
5526 int e;
5527
5528 if (embed_graph[v].link[0] == v)
5529 /*
5530 isolated vertex case
5531 */
5532 {
5533 ASSERT(embed_graph[v].link[1] == v);
5534 continue;
5535 }
5536
5537 e = embed_graph[v].link[0];
5538 while (e != v)
5539 {
5540 ASSERT(embedg_VES_is_edge(n, e));
5541 if (embed_graph[e].visited == MARK_MINORS(n))
5542 {
5543 int cur_v, neigh;
5544
5545 /*
5546 virtual vertices may still hang around
5547 */
5548 /*
5549 let's get the "actual" v:
5550 note that the statement below is safe since if v were
5551 not a valid virtual vertex (ie [v - n].DFS_parent = n)
5552 it would have an empty
5553 adjacency list and we wouldn't be there anyway
5554 */
5555 cur_v = embedg_VES_get_ver(embed_graph, n, v);
5556
5557 neigh = embedg_VES_get_ver(embed_graph, n,
5558 embed_graph[e].neighbour);
5559
5560 /*
5561 again, cur_v and neigh are DFIs,
5562 we want vertex labels at this stage
5563 */
5564 cur_v = embed_graph[cur_v].label;
5565 neigh = embed_graph[neigh].label;
5566 sparseg_dlcl_append_to_neigh_list(obs, n, cur_v, neigh,
5567 embed_graph[e].in_adjl);
5568 (*nbr_e)++;
5569 }
5570 e = embed_graph[e].link[0];
5571 }
5572 }
5573
5574 IF_DEB_OBS(
5575 fprintf(stdout, "recovering the obstruction\n");
5576 sparseg_dlcl_print(obs, n);
5577 );
5578
5579 ASSERT(*nbr_e % 2 == 0);
5580 *nbr_e /= 2;
5581
5582 return obs;
5583 }
5584
5585
5586 static t_dlcl **
embedg_get_reduced_obs(t_dlcl ** obs,int n)5587 embedg_get_reduced_obs (t_dlcl **obs, int n)
5588 /*
5589 reduce the obstruction by removing all degree 2 vertices
5590 (so that they become isolated vertices)
5591 */
5592 {
5593 t_dlcl **reduced;
5594 int v;
5595
5596 reduced = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
5597 for (v = 0; v < n; v++)
5598 {
5599 reduced[v] = embedg_dlcl_copy(obs[v]);
5600 }
5601
5602 for (v = 0; v < n; v++)
5603 {
5604 t_dlcl *n_l, *n_l_b, *p, *new_n_v, *n_l_x, *b_in_n_x;
5605 int a, b, n_x;
5606
5607 n_l = reduced[v];
5608 while (!embedg_dlcl_is_empty(n_l)
5609 && embedg_dlcl_list_last(n_l) == embedg_dlcl_list_next(n_l))
5610 /*
5611 pick out which vertices have deg 2
5612 */
5613 {
5614 a = n_l->info;
5615 b = embedg_dlcl_list_next(n_l)->info;
5616 /*
5617 we remove the edge (v, b), or rather, we identify v and b:
5618 b will then be an isolated vertex
5619
5620 fix v's neighbour list: all of b's neighbours
5621 are now v's neighbours
5622 */
5623 reduced[v] = n_l =
5624 embedg_dlcl_delete_rec(n_l, embedg_dlcl_list_last(n_l));
5625
5626 p = n_l_b = reduced[b];
5627 ASSERT(!embedg_dlcl_is_empty(n_l_b));
5628 n_x = p->info;
5629 if (n_x != v)
5630 {
5631 new_n_v = embedg_dlcl_rec_new(n_x);
5632 reduced[v] = n_l = embedg_dlcl_cat(n_l, new_n_v);
5633
5634 /*
5635 and in n_x neighbour list, we must replace b by v
5636 */
5637 n_l_x = reduced[n_x];
5638 b_in_n_x = embedg_dlcl_find(n_l_x, b);
5639 b_in_n_x->info = v;
5640 }
5641 /*
5642 and do this for all of b's neighbours
5643 */
5644 p = embedg_dlcl_list_next(p);
5645 while (p != n_l_b)
5646 {
5647 n_x = p->info;
5648 if (n_x != v)
5649 {
5650 new_n_v = embedg_dlcl_rec_new(n_x);
5651 reduced[v] = n_l = embedg_dlcl_cat(n_l, new_n_v);
5652 n_l_x = reduced[n_x];
5653 b_in_n_x = embedg_dlcl_find(n_l_x, b);
5654 b_in_n_x->info = v;
5655 }
5656 p = embedg_dlcl_list_next(p);
5657 }
5658 embedg_dlcl_delete(reduced[b]);
5659 reduced[b] = NP;
5660 }
5661 }
5662
5663 IF_DEB_CHECK_OBS(
5664 fprintf(stdout, "reducing the obstruction\n");
5665 sparseg_dlcl_print(reduced, n);
5666 )
5667
5668 /*
5669 now check no degree 2 vertices are left
5670 */
5671 for (v = 0; v < n; v++)
5672 {
5673 t_dlcl *n_l;
5674
5675 n_l = reduced[v];
5676 if (!embedg_dlcl_is_empty(n_l))
5677 {
5678 ASSERT(embedg_dlcl_list_last(n_l) != embedg_dlcl_list_next(n_l));
5679 }
5680 }
5681
5682 return reduced;
5683 }
5684
5685 static boolean
embedg_is_red_obs_K33(t_dlcl ** reduced,int n)5686 embedg_is_red_obs_K33 (t_dlcl **reduced, int n)
5687 /*
5688 check if the (reduced) obstruction is indeed K33
5689 */
5690 {
5691 int v, order, vs[6], i, b1[3];
5692
5693 /*
5694 check that order == 6 and that the obstruction is cubic
5695 */
5696 order = 0;
5697 for (v = 0; v < n; v++)
5698 {
5699 if (!embedg_dlcl_is_empty(reduced[v]))
5700 {
5701 if (order == 6)
5702 {
5703 return FALSE;
5704 }
5705 order++;
5706 vs[order - 1] = v;
5707
5708 if (embedg_dlcl_length(reduced[v]) != 3)
5709 {
5710 return FALSE;
5711 }
5712 }
5713 }
5714 if (order != 6)
5715 {
5716 return FALSE;
5717 }
5718
5719 /*
5720 check if bipartite
5721 */
5722 v = vs[0];
5723 ASSERT(!embedg_dlcl_is_empty(reduced[v]));
5724 b1[0] = reduced[v]->info;
5725 b1[1] = embedg_dlcl_list_next(reduced[v])->info;
5726 b1[2] = embedg_dlcl_list_prev(reduced[v])->info;
5727
5728 for (i = 1; i < 6; i++)
5729 {
5730 t_dlcl *n_v;
5731
5732 v = vs[i];
5733 n_v = reduced[v];
5734 ASSERT(!embedg_dlcl_is_empty(n_v));
5735 if (n_v->info == b1[0]
5736 || embedg_dlcl_list_next(n_v)->info == b1[0]
5737 || embedg_dlcl_list_prev(n_v)->info == b1[0])
5738 {
5739 if ((n_v->info != b1[1]
5740 && embedg_dlcl_list_next(n_v)->info != b1[1]
5741 && embedg_dlcl_list_prev(n_v)->info != b1[1])
5742 &&
5743 (n_v->info != b1[2]
5744 && embedg_dlcl_list_next(n_v)->info != b1[2]
5745 && embedg_dlcl_list_prev(n_v)->info != b1[2]))
5746 {
5747 return FALSE;
5748 }
5749 }
5750 else
5751 {
5752 if ((n_v->info == b1[1]
5753 || embedg_dlcl_list_next(n_v)->info == b1[1]
5754 || embedg_dlcl_list_prev(n_v)->info == b1[1])
5755 ||
5756 (n_v->info == b1[2]
5757 || embedg_dlcl_list_next(n_v)->info == b1[2]
5758 || embedg_dlcl_list_prev(n_v)->info == b1[2]))
5759 {
5760 return FALSE;
5761 }
5762 }
5763 }
5764
5765 return TRUE;
5766 }
5767
5768
5769 static boolean
embedg_is_red_obs_K5(t_dlcl ** reduced,int n)5770 embedg_is_red_obs_K5 (t_dlcl **reduced, int n)
5771 /*
5772 check if the (reduced) obstruction is indeed K5
5773 */
5774 {
5775 int v, order;
5776
5777 /*
5778 check that order == 5 and that the obstruction is quadric
5779 */
5780 order = 0;
5781 for (v = 0; v < n; v++)
5782 {
5783 if (!embedg_dlcl_is_empty(reduced[v]))
5784 {
5785 if (order == 5)
5786 {
5787 return FALSE;
5788 }
5789 order++;
5790
5791 if (embedg_dlcl_length(reduced[v]) != 4)
5792 {
5793 return FALSE;
5794 }
5795 }
5796 }
5797
5798 return TRUE;
5799 }
5800
5801
5802 boolean
embedg_check_recov_obs(t_dlcl ** obs,int n,minor m)5803 embedg_check_recov_obs (t_dlcl **obs, int n, minor m)
5804 /*
5805 check if the recovered obstruction is one of K33 or K5
5806 */
5807 {
5808 t_dlcl **reduced;
5809 boolean ans;
5810
5811 reduced = embedg_get_reduced_obs(obs, n);
5812 if (m != MINOR_E5)
5813 {
5814 ans = embedg_is_red_obs_K33(reduced, n);
5815 }
5816 else
5817 {
5818 ans = embedg_is_red_obs_K5(reduced, n);
5819 }
5820
5821 sparseg_dlcl_delete(reduced, n);
5822 return ans;
5823 }
5824 /*
5825 * obstruction.c
5826 */
5827
5828 /*
5829 What:
5830 *****
5831
5832 Implementing:
5833
5834 The graph is not planar: we recover the obstruction from the VES structure
5835 and check it as well.
5836 (Some of these checks will disappear later)
5837
5838
5839
5840 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
5841 from
5842
5843 Simplified O(n) Planarity Algorithms (draft)
5844 ************************************
5845
5846 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
5847 Wendy Myrvold wendym@csr.uvic.ca
5848
5849
5850 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
5851 authors:
5852 ********
5853
5854 Paulette Lieby (Magma), Brendan McKay (ANU)
5855
5856 Started October 2001
5857 */
5858
5859
5860 #include "planarity.h"
5861
5862 #define IF_DEB(x) {}
5863 #define IF_VERB(x) {}
5864 #define IF_DEB_OBS(x) {}
5865 #define IF_DEB_CHECK_OBS(x) {}
5866 #define IF_CPU(x) {}
5867 #define IF_DEB_MINOR(x) {}
5868
5869
5870 /* aproto: header embed_graph_protos.h */
5871
5872 void
embedg_obstruction(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int w_in,t_ver_sparse_rep ** OV,t_adjl_sparse_rep ** OA,int * nbr_e_obs)5873 embedg_obstruction (
5874 t_ver_sparse_rep *V,
5875 t_adjl_sparse_rep *A, /* the input graph as a sparse graph */
5876 t_dlcl **dfs_tree, /* a sparse graph rep. for the dfs tree
5877 -- vertices are as DFIs
5878 -- and children are ordered wrt
5879 lowpoint value
5880 */
5881 t_dlcl **back_edges, /* for each vertex v, a dlcl
5882 of the back edges [v, x] incident to v
5883 where x is a DESCENDANT of v
5884 (vertices are given as DFIs)
5885 */
5886 t_ver_edge *embed_graph, /* output of tester */
5887 int n, /* size of the graph */
5888 int *edge_pos, /* pos. in embed_graph for addition
5889 of the next edge */
5890 int v,
5891 int w_in, /* the unembedded directed back edge
5892 [w_in, v]
5893 */
5894 t_ver_sparse_rep **OV, /* the obstruction as an adjacency list */
5895 t_adjl_sparse_rep **OA,
5896 int *nbr_e_obs /* obstruction's #edges */
5897 )
5898
5899 /*
5900 the graph is non planar: we must mark & recover the K33 or K5
5901 homeomorph
5902 */
5903 {
5904 int *ver_orient;
5905 minor m;
5906 t_dlcl **obs;
5907
5908 /*
5909 this is magma code - must be removed
5910 */
5911 float sttime, time_to_now;
5912
5913 IF_CPU(
5914 sttime = time_current_user();
5915 )
5916
5917 /*
5918 we will NOT remove the short-cut edges at this stage:
5919 we'll have to perform another walkdown in embedg_iso_is_minor_A
5920 so
5921 1. saves time when looking for ext. active vertices
5922 2. more importantly this enables us to ascertain that the number of
5923 edges in embed_graph (even after completing whichever obstruction
5924 applying in this case) will NEVER be > 3*n - 5!!!
5925 3. SCEs are then removed in embedg_iso_is_minor_A
5926 (obligatory path for every possible case)
5927 */
5928
5929 /*
5930 we must compute each vertex's orientation (wrt flipped bicomps)
5931 and set the edges' orientation:
5932
5933 the other day I was wondering why this was necessary in this
5934 instance (because after all we won't get an embedding):
5935 orientation is required bacause later in the piece we
5936 do a proper face traversal (I guess for Minor C testing)
5937 */
5938 ver_orient = embedg_vertices_orientation(embed_graph, n);
5939 embedg_VES_set_orientation(embed_graph, n, ver_orient);
5940 mem_free(ver_orient);
5941
5942 m = embedg_mark_obstruction(dfs_tree, back_edges,
5943 embed_graph, n, edge_pos, v, w_in);
5944
5945 /*
5946 get the obstruction
5947 */
5948 obs = embedg_recover_obstruction(embed_graph, n, m, nbr_e_obs);
5949
5950 /*
5951 and check it
5952 */
5953 if (!embedg_check_recov_obs(obs, n, m))
5954 {
5955 sparseg_dlcl_delete(obs, n);
5956 DIE();
5957 }
5958
5959 sparseg_dlcl_to_sparseg(obs, n, *nbr_e_obs, OV, OA);
5960 sparseg_dlcl_delete(obs, n);
5961
5962 /*
5963 just for the sake of it, chcek if the obstruction is
5964 a subgraph of the input graph
5965 */
5966 if (!sparseg_adjl_sub(*OV, n, *OA, V, n, A))
5967 {
5968 DIE();
5969 }
5970
5971 IF_DEB_OBS(
5972 sparseg_adjl_print(*V, n, *A, FALSE);
5973 )
5974
5975 IF_CPU(
5976 fprintf(stdout, "CPU for obstruction recovering %f\n",
5977 (time_current_user() - sttime));
5978 )
5979 }
5980
5981
5982
5983
5984
5985
5986
5987 minor
embedg_mark_obstruction(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int w_in)5988 embedg_mark_obstruction (
5989 t_dlcl **dfs_tree, /* a sparse graph rep. for the dfs tree
5990 -- vertices are as DFIs
5991 -- and children are ordered wrt
5992 lowpoint value
5993 */
5994 t_dlcl **back_edges, /* for each vertex v, a dlcl
5995 of the back edges [v, x] incident to v
5996 where x is a DESCENDANT of v
5997 (vertices are given as DFIs)
5998 */
5999 t_ver_edge *embed_graph, /* output of tester */
6000 int n, /* size of the graph */
6001 int *edge_pos, /* pos. in embed_graph for addition
6002 of the next edge */
6003 int v,
6004 int w_in /* the unembedded directed back edge
6005 [w_in, v]
6006 */
6007 )
6008 /*
6009 the graph is non planar: we must mark & recover the K33 or K5
6010 homeomorph
6011 */
6012 {
6013 int c, vr, x, y, w;
6014 int *path_v, *path_e, nbr_v, entry_in_path_e;
6015 boolean px_attached_high, py_attached_high, is_minor_D;
6016 minor m;
6017
6018
6019 IF_CPU(
6020 float sttime; float time_to_now;
6021
6022 sttime = time_current_user();
6023 )
6024
6025
6026 /*
6027 find c such that v^c is the root of the biconnected
6028 component on which the walkdown failed
6029 */
6030 c = embedg_iso_get_c_of_v(embed_graph, n, v, w_in);
6031
6032 /*
6033 now: decide which minor we are dealing with and mark the
6034 appropriate one (vertices/edges marked as MARK_MINOR(n)
6035 in embed_graph)
6036 */
6037 if (embedg_iso_is_minor_A(embed_graph, n, edge_pos, v, c, &vr))
6038 {
6039 embedg_mark_minor_A(dfs_tree, back_edges,
6040 embed_graph, n, edge_pos, v, c, vr);
6041
6042 IF_DEB_MINOR(
6043 fprintf(stdout, "Minor A\n");
6044 )
6045
6046 return MINOR_A;
6047 }
6048
6049 /*
6050 get the externally active vertices x & y and the pertinent w
6051 on the external face of the bicomp rooted by v^c
6052
6053 and determine if minor B
6054 */
6055 if (embedg_iso_is_minor_B(embed_graph, n, edge_pos, v, c,
6056 &x, &y, &w))
6057 {
6058 embedg_mark_minor_B(dfs_tree, back_edges,
6059 embed_graph, n, edge_pos, v, c,
6060 x, y, w);
6061 IF_DEB_MINOR(
6062 fprintf(stdout, "Minor B\n");
6063 )
6064
6065 IF_CPU(
6066 fprintf(stdout, "CPU for obstruction isolation %f\n",
6067 time_current_user() - sttime);
6068 )
6069
6070 return MINOR_B;
6071 }
6072
6073 /*
6074 the remaining cases: must get the highest x-y path
6075
6076 it will be containing in path_v (vertices), path_e (edges)
6077 */
6078 embedg_iso_get_highest_x_y_path(embed_graph, n, MARK_EXT_FACE(n),
6079 MARK_EXT_FACE_L(n),
6080 MARK_EXT_FACE_R(n),
6081 v, c, x, y, w,
6082 &path_v, &path_e,
6083 &nbr_v, &entry_in_path_e,
6084 &px_attached_high,
6085 &py_attached_high,
6086 &is_minor_D);
6087
6088 /*
6089 we are in the minor C case if either one of p_x or p_y
6090 is attached high
6091 */
6092 if (px_attached_high || py_attached_high)
6093 {
6094 embedg_mark_minor_C(dfs_tree, back_edges, embed_graph, n, edge_pos,
6095 v, c, x, y, w,
6096 path_v, path_e, nbr_v,
6097 px_attached_high, py_attached_high);
6098 IF_DEB_MINOR(
6099 fprintf(stdout, "Minor C\n");
6100 )
6101
6102 mem_free(path_v);
6103 mem_free(path_e);
6104
6105 IF_CPU(
6106 fprintf(stdout, "CPU for obstruction isolation %f\n",
6107 time_current_user() - sttime);
6108 )
6109
6110 return MINOR_C;
6111 }
6112
6113 if (is_minor_D)
6114 {
6115 embedg_mark_minor_D(dfs_tree, back_edges, embed_graph, n, edge_pos,
6116 v, c, x, y, w,
6117 path_v, path_e, nbr_v, entry_in_path_e);
6118 IF_DEB_MINOR(
6119 fprintf(stdout, "Minor D\n");
6120 )
6121
6122 mem_free(path_v);
6123 mem_free(path_e);
6124
6125 IF_CPU(
6126 fprintf(stdout, "CPU for obstruction isolation %f\n",
6127 time_current_user() - sttime);
6128 )
6129
6130 return MINOR_D;
6131 }
6132
6133 /*
6134 finally, the minor E case
6135 */
6136 m = embedg_mark_minor_E(dfs_tree, back_edges, embed_graph, n, edge_pos,
6137 v, c, x, y, w,
6138 path_v, path_e, nbr_v);
6139 switch (m)
6140 {
6141 case MINOR_E1:
6142 IF_DEB_MINOR(
6143 fprintf(stdout, "Minor E1\n");
6144 )
6145 break;
6146 case MINOR_E2:
6147 IF_DEB_MINOR(
6148 fprintf(stdout, "Minor E2\n");
6149 )
6150 break;
6151 case MINOR_E3:
6152 IF_DEB_MINOR(
6153 fprintf(stdout, "Minor E3\n");
6154 )
6155 break;
6156 case MINOR_E4:
6157 IF_DEB_MINOR(
6158 fprintf(stdout, "Minor E4\n");
6159 )
6160 break;
6161 case MINOR_E5:
6162 IF_DEB_MINOR(
6163 fprintf(stdout, "Minor E5\n");
6164 )
6165 break;
6166 case MINOR_A:
6167 case MINOR_B:
6168 case MINOR_C:
6169 case MINOR_D:
6170 case MINOR_E:
6171 case NBR_MINORS:
6172 break;
6173 }
6174
6175 mem_free(path_v);
6176 mem_free(path_e);
6177
6178 IF_CPU(
6179 fprintf(stdout, "CPU (scaled) for obstruction isolation %f\n",
6180 (time_current_user() - sttime) / e);
6181 )
6182
6183 return m;
6184 }
6185 /*
6186 * isolator.c
6187 */
6188
6189 /*
6190 What:
6191 *****
6192
6193 Implementing:
6194
6195 The graph is non planar: we isolate the obstruction.
6196
6197
6198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6199 from
6200
6201 Simplified O(n) Planarity Algorithms (draft)
6202 ************************************
6203
6204 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
6205 Wendy Myrvold wendym@csr.uvic.ca
6206
6207
6208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6209 authors:
6210 ********
6211
6212 Paulette Lieby (Magma), Brendan McKay (ANU)
6213
6214 Started October 2001
6215 */
6216
6217
6218 #include "planarity.h"
6219
6220 #define IF_DEB(x) {}
6221 #define IF_VERB(x) {}
6222 #define IF_DEB_TREE(x) {}
6223 #define IF_DEB_EDGES(x) {}
6224 #define IF_CPU(x) {}
6225 /* #define IF_DEB_MINOR(x) {x} -- Not Used */
6226
6227
6228 /* aproto: header embed_graph_protos.h */
6229
6230 #ifndef PLANAR_IN_MAGMA
6231 #endif
6232
6233
6234
6235
6236 int
embedg_iso_get_c_of_v(t_ver_edge * embed_graph,int n,int v,int w)6237 embedg_iso_get_c_of_v (t_ver_edge *embed_graph, int n, int v, int w)
6238 /*
6239 the edge [v, w] (w a descendant of v) remains unembedded
6240 after the walkdown returns
6241
6242 find c such that v^c is the root of the biconnected
6243 component on which the walkdown failed
6244 */
6245 {
6246 /*
6247 how to do this??? easy! follow the DFS tree path as given
6248 by the field DFS_parent
6249 */
6250
6251 int u;
6252
6253 u = embed_graph[w].DFS_parent;
6254 while (embed_graph[u].DFS_parent != v)
6255 {
6256 u = embed_graph[u].DFS_parent;
6257 }
6258 /*
6259 this is guaranteed to succeed given the structure of the DFS tree
6260 and the fact that there exists a back edge [w, v]
6261 */
6262
6263 return u;
6264 }
6265
6266
6267 boolean
embedg_iso_is_minor_A(t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int * vr)6268 embedg_iso_is_minor_A (t_ver_edge *embed_graph, int n,
6269 int *edge_pos, int v, int c, int *vr)
6270 /*
6271 determines if the obstruction is a minor A
6272 */
6273 {
6274 /*
6275 to do this we again call the walkdown routine with v^c as input,
6276 the walkdown routine will fail (since there will be an
6277 un-embedded back edge incident to v and to a vertex
6278 in the subtree rooted by v^c)
6279
6280 the obstruction is a minor A if the merge queue returned by the
6281 walkdown is non-empty, if this is the case we return
6282 the bicomp last appended to the queue
6283 */
6284 int vv;
6285 t_merge_queue q;
6286
6287 vv = c + n;
6288
6289 q = embedg_walkdown(embed_graph, n, edge_pos, vv);
6290 /*
6291 we MUST remove the SCEs here: this is the only place where it
6292 will be done when looking for and recovering an obstruction
6293
6294 this is safe since this very function applies to ALL cases!
6295 */
6296 embedg_remove_SCE(embed_graph, n, *edge_pos);
6297
6298 if (!embedg_merge_queue_empty(q))
6299 /*
6300 the bicomp of interest is the last in the queue
6301 */
6302 {
6303 int r, rin, vrout;
6304
6305 embedg_merge_queue_prune(&q, &r, &rin, vr, &vrout);
6306 embedg_merge_queue_delete(q);
6307 return TRUE;
6308 }
6309 else
6310 {
6311 embedg_merge_queue_delete(q);
6312 return FALSE;
6313 }
6314 }
6315
6316
6317 void
embedg_iso_get_x_y_w(t_ver_edge * embed_graph,int n,int v,int r,int c,int mark,int mark_l,int mark_r,int * x,int * y,int * w)6318 embedg_iso_get_x_y_w (t_ver_edge *embed_graph, int n, int v, int r,
6319 int c, int mark, int mark_l, int mark_r, int *x, int *y, int *w)
6320 /*
6321 the obstruction is one of minor B, C, D, E.
6322
6323 get the externally active vertices x & y along the
6324 external face paths starting at r^c
6325
6326 get a pertinent vertex w along the lower external
6327 face path between x and y
6328
6329 external activity and pertinence are wrt v
6330
6331 all the vertices on the external face r^c...x...w
6332 and r^c...y...w will be marked (the visited field)
6333 */
6334 {
6335 int vr, vrin, x_y[4];
6336 int s, sin, cur, curin;
6337
6338 vr = c + n;
6339
6340 /*
6341 find x and y first:
6342
6343 note that we mark the vertices on the external face r^c...x
6344 and r^c...y
6345
6346 more on that below
6347 */
6348 embed_graph[vr].visited = mark;
6349 for (vrin = 0; vrin <= 1; vrin++)
6350 {
6351 int m;
6352
6353 m = vrin == 0 ? mark_l : mark_r;
6354 embedg_VES_get_succ_ext_active_on_ext_face(embed_graph, n, v,
6355 vr, vrin,
6356 TRUE, m,
6357 &s, &sin);
6358 x_y[vrin] = s;
6359 x_y[vrin + 2] = sin;
6360 /*
6361 note the bizarre way I store the active vertex
6362 and the direction out of which to continue a walk
6363 on the lower external face as described above
6364 */
6365 }
6366 *x = x_y[0];
6367 *y = x_y[1];
6368
6369 /*
6370 next get the pertinent w on the lower external face from x to y
6371 */
6372 cur = x_y[0];
6373 curin = x_y[2];
6374 embedg_VES_get_succ_pertinent_on_ext_face(embed_graph, n, v,
6375 cur, curin,
6376 TRUE, mark_l, w, &sin);
6377
6378 /*
6379 now all the vertices r^c...x...w and r^c...y have been marked,
6380 it remains to mark the vertices on the y...w external face path
6381
6382 (will need to be able to distinguish the external face later on)
6383
6384 Note the way the external face is marked (needed when recovering
6385 the highest x-y path):
6386 mark_l for the path v^c...x...w
6387 mark_r for the path v^c...y
6388 mark for the lower external face y...w
6389 */
6390 cur = x_y[1];
6391 curin = x_y[3];
6392 s = n;
6393 while (s != *w)
6394 {
6395 embedg_VES_get_succ_pertinent_on_ext_face(embed_graph, n, v,
6396 cur, curin,
6397 TRUE, mark, &s, &sin);
6398 cur = s;
6399 curin = sin;
6400 }
6401
6402 IF_DEB(
6403 fprintf(stdout, "get x, y & w: the external face\n");
6404 fprintf(stdout, "%d\t", vr);
6405 cur = vr;
6406 curin = 0;
6407 while (s != vr)
6408 {
6409 embedg_VES_get_succ_on_ext_face(embed_graph, n,
6410 cur, curin,
6411 FALSE, 0, &s, &sin);
6412 cur = s;
6413 curin = sin;
6414 fprintf(stdout, "%d\t", s);
6415 }
6416 fprintf(stdout, "\n");
6417 )
6418 }
6419
6420
6421
6422
6423 boolean
embedg_iso_is_minor_B(t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int * x,int * y,int * w)6424 embedg_iso_is_minor_B (t_ver_edge *embed_graph, int n, int *edge_pos,
6425 int v, int c, int *x, int *y, int *w)
6426 /*
6427 determines if the obstruction is a minor B and return x, y
6428 (ext. active) and w (pertinent)
6429 */
6430 {
6431 /*
6432 get x & y the ext. active vertices on the (external face)
6433 path out of v^c,
6434 and w the pertinent vertex on the lower external face x-y
6435
6436 PLUS mark the whole external face with MARK_EXT_FACE(n)
6437 */
6438 embedg_iso_get_x_y_w(embed_graph, n, v, v, c,
6439 MARK_EXT_FACE(n),
6440 MARK_EXT_FACE_L(n), MARK_EXT_FACE_R(n),
6441 x, y, w);
6442
6443 if (embedg_dlcl_is_empty(embed_graph[*w].pertinent_bicomp_list))
6444 /*
6445 w has no pertinent child bicomp: not a minor B
6446 */
6447 return FALSE;
6448 else
6449 {
6450 t_dlcl *pert_l;
6451 int l;
6452
6453 pert_l = embed_graph[*w].pertinent_bicomp_list;
6454 l = embedg_dlcl_list_last(pert_l)->info;
6455 /*
6456 if w has an ext. active pertinent child bicomp then minor B
6457
6458 note that we need to know if w has an ext. active AND pertinent
6459 bicomp child: so it is NOT good enough to test
6460 w's separated_DFS_child_list as is done in
6461 embedg_VES_is_ver_ext_active!!!!!!!!!
6462
6463 PLUS: l is actually a VIRTUAL vertex: to check its lowpoint
6464 I must take its DFS child l - n !!!!!!!!
6465 */
6466 ASSERT(embedg_VES_is_virtual_vertex(n, l));
6467 l = l - n;
6468 return embed_graph[l].lowpoint < v ? TRUE : FALSE;
6469 }
6470 }
6471
6472 void
embedg_iso_get_highest_x_y_path(t_ver_edge * embed_graph,int n,int mark,int mark_l,int mark_r,int v,int c,int x,int y,int w,int ** path_v,int ** path_e,int * nbr_v,int * entry_in_path_e,boolean * px_attached_high,boolean * py_attached_high,boolean * is_minor_D)6473 embedg_iso_get_highest_x_y_path (
6474 t_ver_edge *embed_graph,
6475 int n,
6476 int mark,
6477 int mark_l,
6478 int mark_r,
6479 int v,
6480 int c,
6481 int x,
6482 int y,
6483 int w,
6484 int **path_v, /* stack of vertices in x-y path */
6485 int **path_e, /* stack of egdes in x-y path */
6486 int *nbr_v, /* number of vertices in path_v */
6487 int *entry_in_path_e, /* the in direction for the FIRST edge in
6488 path_e: needed later on *sigh*
6489 */
6490 boolean *px_attached_high,
6491 boolean *py_attached_high,
6492 boolean *is_minor_D
6493 )
6494 /*
6495 the obstruction is one of minor C, D, E.
6496
6497 we want to recover the highest x-y path:
6498 the obstructing path attached to the external faces v^c - x - w
6499 and v^c - y - w
6500
6501 while doing all this we also determine if the case is a minor C
6502 or a minor D
6503 */
6504 {
6505 /*
6506 the path is obtained by walking the proper face starting at v
6507 where ALL the edges incident to v^c BUT the ones bordering
6508 the external face have been removed
6509
6510 I won't I don't think remove these edges, but instead I'll be
6511 implementing an "avoidance" walk
6512 */
6513
6514 int vv, s, sin, p_x, p_y, cur_v, cur_vin;
6515 int e, ein, s_e, s_ein;
6516 boolean avoid_vv;
6517
6518 /*
6519 must start the walk at edge embed_graph[v^c].link[1 ^ 0],
6520 (vvin = 0 is in direction of x, see embedg_iso_get_x_y_w)
6521 */
6522 vv = c + n;
6523 e = embed_graph[vv].link[1];
6524 ein = 0; /* because of adjacency list consistency */
6525
6526 *path_v = (int *) mem_malloc(sizeof(int) * n);
6527 *path_e = (int *) mem_malloc(sizeof(int) * n);
6528 (*nbr_v) = -1;
6529
6530 /*
6531 recall that in embedg_iso_get_x_y_w we did mark
6532 (with mark, mark_l, mark_r)
6533 ALL the vertices lying on the external face walk starting
6534 & ending at v^c: we will use this fact to enable us
6535 to decide if a vertex is on the external face
6536 (as opposed to being on the internal face)
6537 */
6538
6539 s = embed_graph[e].neighbour;
6540 ASSERT(embed_graph[s].visited == mark_l);
6541 /*
6542 this must be the case since s lies on the external face
6543 starting at v^c in x's direction
6544 -- we push s onto the stack
6545 */
6546 (*path_v)[++(*nbr_v)] = s;
6547
6548 /*
6549 start the proper face walk which "avoids" v^c since the
6550 internal edges incident to v^c are supposed to have
6551 been removed
6552
6553 please read on
6554 */
6555 avoid_vv = FALSE;
6556 while (TRUE)
6557 {
6558 boolean av;
6559
6560 av =
6561 embedg_VES_get_succ_on_proper_face_with_avoidance(
6562 embed_graph, n,
6563 e, ein, vv,
6564 FALSE, 0,
6565 &s, &s_e, &s_ein);
6566 avoid_vv = av == TRUE ? av : avoid_vv;
6567 if (embed_graph[s].visited == mark_l)
6568 /*
6569 means that s is still on the external face:
6570 empty the path's stack and push s
6571 */
6572 {
6573 (*nbr_v) = -1;
6574 (*path_v)[++(*nbr_v)] = s;
6575 e = s_e;
6576 ein = s_ein;
6577 }
6578 else if (*nbr_v == 0)
6579 /*
6580 s is the first encountered vertex after
6581 path_v[0] which does not
6582 lie on the external face v^c...c...w
6583
6584 given the way we pushed things on the vertex stack, path_v[0]
6585 will be the point of attachement of the x-y path
6586 on the v^c...x...w external face
6587
6588 path_e[0] will contain nothing: a dummy
6589
6590 path_e[1] will be the first edge in the x-y path
6591 (and entry_in_path will give the in-direction to this edge)
6592
6593 oh yes!, we break the loop at this point if
6594 the vertex s lies on the v^c...y...w external face
6595 */
6596 {
6597 ASSERT(embed_graph[(*path_v)[0]].visited == mark_l);
6598 /*
6599 the first vertex on the path must be on the
6600 v^c...x...w external face
6601 */
6602 (*path_v)[++(*nbr_v)] = s;
6603 /*
6604 and now we also push the edge on the edge stack
6605
6606 I'll need this later to initiate a proper face walk
6607 starting at the first vertex/edge in the x-y path,
6608 which is the same as starting from s_e
6609 */
6610 (*path_e)[*nbr_v] = s_e;
6611 *entry_in_path_e = s_ein;
6612 e = s_e;
6613 ein = s_ein;
6614
6615 /*
6616 since we are at the start of the path, we must not
6617 forget to reset avoid_vv
6618 */
6619 avoid_vv = FALSE;
6620
6621 if (embed_graph[s].visited == mark_r
6622 || embed_graph[s].visited == mark)
6623 /*
6624 we have reached the v^c...y...w external face:
6625 we can stop here
6626 */
6627 {
6628 break;
6629 }
6630
6631 /*
6632 if not finished yet,
6633 we also mark s (and path_v[0]) as visited:
6634 later on we'll need to recognise which of the vertices
6635 in path have already been encountered
6636 (in case of encountering a cut-vertex due to the
6637 "removal" of the "internal" edges incidnet ot v^c)
6638
6639 note that we mark s as visited iff s if not already
6640 on the v^c..y..w external face
6641 */
6642
6643 ASSERT(embedg_VES_is_vertex(n, (*path_v)[0]));
6644 ASSERT(embedg_VES_is_vertex(n, s));
6645
6646 embed_graph[s].visited = MARK_X_Y_PATH(n);
6647 }
6648 else if (embed_graph[s].visited == MARK_X_Y_PATH(n))
6649 /*
6650 this means that s is a cut vertex on the internal
6651 face walk: pop all the vertices from path
6652 until s's last occurrence in path
6653 */
6654 {
6655 ASSERT((*nbr_v) >= 0);
6656 while ((*path_v)[(*nbr_v)] != s)
6657 {
6658 (*nbr_v)--;
6659 ASSERT((*nbr_v) >= 0);
6660 /*
6661 note that s should be somewhere in path!
6662 */
6663 }
6664 /*
6665 note also that popping from path_v also implies
6666 popping from path_e
6667 */
6668 e = s_e;
6669 ein = s_ein;
6670 }
6671 else
6672 /*
6673 we push s and s_e on their respective stacks
6674 */
6675 {
6676 (*path_v)[++(*nbr_v)] = s;
6677 (*path_e)[*nbr_v] = s_e;
6678 e = s_e;
6679 ein = s_ein;
6680
6681 if (embed_graph[s].visited == mark_r
6682 || embed_graph[s].visited == mark)
6683 /*
6684 again, s lies on the v^c...y...w external face:
6685 we end the walk: path_v now contains the highest x-y path
6686
6687 note that there can be no conflict between
6688 mark_r or mark and MARK_X_Y_PATH(n) since
6689 we mark with MARK_X_Y_PATH iff the vertex
6690 is NOT marked with mark_r/mark!
6691 */
6692 {
6693 break;
6694 }
6695 else
6696 /*
6697 we must mark this vertex as MARK_X_Y_PATH since we aren't
6698 finished yet
6699 */
6700 {
6701 embed_graph[s].visited = MARK_X_Y_PATH(n);
6702 }
6703 }
6704 }
6705
6706 /*
6707 there is only one thing remaining to do: see if p_x or
6708 p_y are attached high
6709 (ie closer to v^c than x or y resp.)
6710
6711 we walk the external face starting at v^c in y's direction
6712 (again see embedg_iso_get_x_y_w)
6713 */
6714 *px_attached_high = TRUE;
6715 p_x = (*path_v)[0];
6716 /*
6717 p_y denotes the attachement point of the x-y path
6718 on the v^c...y...w external face
6719 */
6720
6721 s = n;
6722 cur_v = vv;
6723 cur_vin = 0;
6724 while (s != p_x)
6725 {
6726 embedg_VES_get_succ_on_ext_face(embed_graph, n,
6727 cur_v, cur_vin,
6728 FALSE, 0, &s, &sin);
6729 if (s == x)
6730 {
6731 *px_attached_high = FALSE;
6732 break;
6733 }
6734 cur_v = s;
6735 cur_vin = sin;
6736 }
6737
6738 *py_attached_high = TRUE;
6739 p_y = (*path_v)[*nbr_v];
6740 /*
6741 p_y denotes the attachement point of the x-y path
6742 on the v^c...y...w external face
6743 */
6744
6745 s = n;
6746 cur_v = vv;
6747 cur_vin = 1;
6748 while (s != p_y)
6749 {
6750 embedg_VES_get_succ_on_ext_face(embed_graph, n,
6751 cur_v, cur_vin,
6752 FALSE, 0, &s, &sin);
6753 if (s == y)
6754 {
6755 *py_attached_high = FALSE;
6756 break;
6757 }
6758 cur_v = s;
6759 cur_vin = sin;
6760 }
6761
6762 /*
6763 now we are in the minor C case if either p_x or p_y are
6764 attached high
6765
6766 the minor D case:
6767 this happens when there is a path v^c - z where z lies
6768 on the x-y path
6769
6770 that is, when
6771
6772 either v^c has been effectively "avoided" within the
6773 embedg_VES_get_succ_on_proper_face_with_avoidance function
6774 BUT ONLY if this "avoidance" happened AFTER having
6775 encountered the very first vertex on the x-y path!
6776
6777 or when a cut vertex has been encountered on the x-y path:
6778 separable components on this walk can only occur
6779 if one walks the face while skipping the edges incident to v^c
6780
6781 in any case this means that checking the return from
6782 the embedg_VES_get_succ_on_proper_face_with_avoidance function
6783 is enough: this is the purpose of avoid_vv.
6784 */
6785
6786 *is_minor_D = !(*px_attached_high || *py_attached_high) && avoid_vv;
6787
6788
6789 IF_DEB(
6790 int i;
6791
6792 fprintf(stdout, "x-y path\t");
6793 for (i = 0; i <= *nbr_v; i++)
6794 fprintf(stdout, "%d\t", (*path_v)[i]);
6795 fprintf(stdout, "\n");
6796 )
6797 }
6798
6799
6800 /*
6801 * embedg_misc.c
6802 */
6803
6804 /*
6805 What:
6806 *****
6807
6808 Implementing:
6809
6810 Some high level routinse for the VES structure.
6811 See VES_misc.c.
6812
6813
6814 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6815 from
6816
6817 Simplified O(n) Planarity Algorithms (draft)
6818 ************************************
6819
6820 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
6821 Wendy Myrvold wendym@csr.uvic.ca
6822
6823
6824 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6825 authors:
6826 ********
6827
6828 Paulette Lieby (Magma), Brendan McKay (ANU)
6829
6830 Started October 2001
6831 */
6832
6833
6834 #include "planarity.h"
6835
6836 #define IF_DEB(x) {}
6837 #define IF_VERB(x) {}
6838 #define IF_DEB_TREE(x) {}
6839
6840
6841
6842 /* aproto: header embed_graph_protos.h */
6843
6844 #ifndef PLANAR_IN_MAGMA
6845 #endif
6846
6847
6848
6849
6850 void
embedg_VES_delete(t_ver_edge * embed_graph,int n)6851 embedg_VES_delete (t_ver_edge *embed_graph, int n)
6852 {
6853 int i;
6854
6855 for (i = 0; i < n; i++)
6856 {
6857 embedg_dlcl_delete(embed_graph[i].separated_DFS_child_list);
6858 /*
6859 embedg_dlcl_delete(embed_graph[i].rep_in_parent_list);
6860
6861 NO!!! this points to something in separated_DFS_child_list
6862 */
6863 embedg_dlcl_delete(embed_graph[i].pertinent_bicomp_list);
6864 }
6865 mem_free(embed_graph);
6866 }
6867
6868
6869
6870 void
embedg_VES_print(t_ver_edge * embed_graph,int n)6871 embedg_VES_print (t_ver_edge *embed_graph, int n)
6872 {
6873 int i;
6874
6875 fprintf(stdout, "vertices\n");
6876 for (i = 0; i < n; i++)
6877 {
6878 t_ver_edge rec;
6879
6880 rec = embed_graph[i];
6881
6882 fprintf(stdout, "\nDFI\t%d\tlabel\t%d\n", i, rec.label);
6883 fprintf(stdout, "DFS parent\t%d\tleast_a\t%d\tlowpoint\t%d\n",
6884 rec.DFS_parent, rec.least_ancestor, rec.lowpoint);
6885 fprintf(stdout, "separated_DFS_child_list\n");
6886 embedg_dlcl_print(rec.separated_DFS_child_list);
6887 }
6888
6889 fprintf(stdout, "\nvirtual vertices\n");
6890 for (i = n; i < 2*n; i++)
6891 {
6892 int c;
6893
6894 c = i - n;
6895 fprintf(stdout, "%d^%d\t", embed_graph[c].DFS_parent, c);
6896 }
6897 fprintf(stdout, "\n");
6898
6899 embedg_VES_print_bigcomps(embed_graph, n);
6900 }
6901
6902
6903 void
embedg_VES_print_bigcomps(t_ver_edge * embed_graph,int n)6904 embedg_VES_print_bigcomps (t_ver_edge *embed_graph, int n)
6905 /*
6906 walking the external faces of all the bicomp; for testing only
6907 */
6908 {
6909 int i;
6910
6911 fprintf(stdout, "bicomponents\n");
6912 /*
6913 to get to the bicomps, it makes sense to start at the
6914 virtual vertices????
6915 */
6916 for (i = n + 1; i < 2*n; i++)
6917 /*
6918 a note of caution: there is no virtual vertex at
6919 embed_graph[n] since that would mean a virtual vertex x^0
6920 which makes no sense (0 is the root of the dfs_tree)
6921 */
6922 {
6923 embedg_VES_walk_bicomp(embed_graph, n, i, 0);
6924 }
6925 fprintf(stdout, "\n");
6926 }
6927 /*
6928 * planar_alg_init.c
6929 */
6930
6931 /*
6932 What:
6933 *****
6934
6935 Implementing:
6936
6937 Initialising the embed_graph aka VES data structure from the information
6938 collected from the DFS.
6939
6940 The embed_graph/VES data structure is an array consisting of vertices,
6941 virtual vertices and edges;
6942 vertices, virtual vertices and edges share a common record structure;
6943 one of the particular features is that any vertex is linked
6944 together with its incident edges into a doubly circular linked list.
6945
6946 See also VES_misc.c.
6947
6948 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6949 from
6950
6951 Simplified O(n) Planarity Algorithms (draft)
6952 ************************************
6953
6954 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
6955 Wendy Myrvold wendym@csr.uvic.ca
6956
6957
6958 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
6959 authors:
6960 ********
6961
6962 Paulette Lieby (Magma), Brendan McKay (ANU)
6963
6964 Started October 2001
6965 */
6966
6967 #include "planarity.h"
6968
6969 #define IF_DEB(x) {}
6970 #define IF_DEB_DFS(x) {}
6971 #define IF_VERB(x) {}
6972 #define IF_DEB_TREE(x) {}
6973 #define IF_CPU(x) {}
6974
6975
6976 /* aproto: header embed_graph_protos.h */
6977
6978 /* aproto: beginstatic -- don't touch this!! */
6979 static void embedg_init_insert_TE (t_ver_edge *, int, int *, t_dlcl *);
6980 /* aproto: endstatic -- don't touch this!! */
6981
6982 #ifndef PLANAR_IN_MAGMA
6983 #endif
6984
6985
6986 t_ver_edge *
embedg_planar_alg_init(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int * nbr_c,int * edge_pos,t_dlcl *** dfs_tree,t_dlcl *** back_edges,t_dlcl *** mult_edges)6987 embedg_planar_alg_init (
6988 t_ver_sparse_rep *V,
6989 int n,
6990 t_adjl_sparse_rep *A, /* input sparse graph */
6991 int *nbr_c, /* size of the graph, #components*/
6992 int *edge_pos, /* pos in the struct where the last edge
6993 has been inserted
6994 */
6995 t_dlcl ***dfs_tree, /* a sparse graph rep. for the dfs tree
6996 -- vertices are as DFIs
6997 */
6998 t_dlcl ***back_edges, /* for each vertex v, a dlcl
6999 of the back edges [v, x] incident to v
7000 where x is a DESCENDANT of v
7001 -- vertices are as DFIs
7002 */
7003 t_dlcl ***mult_edges /* for each vertex v, a dlcl
7004 of the back edges [v, x] incident to v
7005 where x is a DESCENDANT of v
7006 -- vertices are as DFIs
7007 */
7008 )
7009 /*
7010 initialising embed_graph, the fundamental data structure
7011 underpinning the tester and obstruction isolator
7012
7013 from there on, a vertex is exclusively referred to by its DFI!!
7014 -- so forget about labels
7015 */
7016 {
7017 int *dfs_nbr; /* dfs numbering for each vertex */
7018 int *dfs_order; /* vertices in dfs order */
7019 int *lowpoint; /* lowpoint value for each DFI */
7020 int *dfs_parent; /* for each DFI, its DFS ancestor
7021 as a DFI (DFS index)
7022 */
7023 int *least_a; /* for each DFI, its least ancestor's DFI
7024 (via a back edge exclusively)
7025 */
7026
7027 t_ver_edge *embed_graph;
7028 int i;
7029
7030
7031 IF_CPU(
7032 float sttime; float time_to_now;
7033
7034 sttime = time_current_user();
7035 )
7036
7037 ASSERT(n >= 1);
7038
7039 /*
7040 DFS and lowpoint calculations + ordering
7041 */
7042 sparseg_adjl_dfs_preprocessing(V, n, A, nbr_c,
7043 &dfs_nbr, &dfs_order, &lowpoint,
7044 dfs_tree, back_edges,
7045 &dfs_parent, &least_a, mult_edges);
7046
7047 IF_CPU(
7048 fprintf(stdout, "CPU for DFS only %f\n",
7049 (time_current_user() - sttime));
7050 sttime = time_current_user();
7051 )
7052
7053 IF_DEB_DFS(
7054 fprintf(stdout, "DFS indices\n");
7055 for (i = 0; i < n; i++)
7056 fprintf(stdout, "%d ", dfs_nbr[i]);
7057 fprintf(stdout, "\n");
7058
7059 fprintf(stdout, "DFS order\n");
7060 for (i = 0; i < n; i++)
7061 fprintf(stdout, "%d ", dfs_order[i]);
7062 fprintf(stdout, "\n");
7063
7064 fprintf(stdout, "lowpoint values\n");
7065 for (i = 0; i < n; i++)
7066 fprintf(stdout, "%d ", lowpoint[i]);
7067 fprintf(stdout, "\n");
7068 );
7069
7070 IF_VERB(
7071 fprintf(stdout, "DFS parent\n");
7072 for (i = 0; i < n; i++)
7073 fprintf(stdout, "%d ", dfs_parent[i]);
7074 fprintf(stdout, "\n");
7075 );
7076
7077 IF_VERB(
7078 fprintf(stdout, "least ancestors\n");
7079 for (i = 0; i < n; i++)
7080 fprintf(stdout, "%d ", least_a[i]);
7081 fprintf(stdout, "\n");
7082 );
7083
7084 IF_VERB(
7085 for (i = 0; i < n; i++)
7086 {
7087 fprintf(stdout, "the list of children ordered by lowpoint for %d\n",
7088 i);
7089 embedg_dlcl_print((*dfs_tree)[i]);
7090 }
7091 );
7092
7093 IF_DEB_DFS(
7094 fprintf(stdout, "the tree edges\n");
7095 sparseg_dlcl_print(*dfs_tree, n);
7096
7097 fprintf(stdout, "the back edges\n");
7098 sparseg_dlcl_print(*back_edges, n);
7099
7100 fprintf(stdout, "multiple edges\n");
7101 sparseg_dlcl_print(*mult_edges, n);
7102 );
7103
7104 /*
7105 create the data structure for the embedded graph:
7106 it will have (max) size 2*n + 2 * MAXE(n)
7107
7108 we will see that that number of edges is sufficient
7109 even when later adding short-cut edges (see embedg_walkdown)
7110 */
7111 embed_graph = (t_ver_edge *) mem_malloc(sizeof(t_ver_edge)
7112 * (2*n + 2 * MAXE(n)));
7113 /*
7114 initialisation
7115 */
7116 for (i = 0; i < 2*n + 2 * MAXE(n); i++)
7117 /*
7118 some fields are initialised to n as n is actually
7119 an "invalid" value
7120 */
7121 {
7122 t_ver_edge rec;
7123
7124 rec.label = NIL;
7125 rec.DFS_parent = n;
7126 rec.least_ancestor = n;
7127 rec.lowpoint = n;
7128 rec.separated_DFS_child_list = NP;
7129 rec.rep_in_parent_list = NP;
7130 rec.pertinent_bicomp_list = NP;
7131 rec.adjacent_to = n;
7132 rec.visited = n;
7133 rec.neighbour = n;
7134 rec.in_adjl = NIL;
7135 rec.twin_in_adjl = NIL;
7136 rec.mult = 0;
7137 rec.type = NIL;
7138 rec.sign = NILSIGN;
7139 /*
7140 make the links refer back to self
7141 */
7142 rec.link[0] = rec.link[1] = i;
7143
7144 embed_graph[i] = rec;
7145 }
7146
7147 /*
7148 embed_graph[0..n-1]: the n vertices
7149 ATTENTION: the vertices are stored according to their DFS numbering
7150 */
7151 for (i = 0; i < n; i++)
7152 {
7153 t_ver_edge rec;
7154
7155 rec = embed_graph[i];
7156
7157 rec.label = dfs_order[i];
7158 rec.DFS_parent = dfs_parent[i];
7159 rec.least_ancestor = least_a[i];
7160 rec.lowpoint = lowpoint[i];
7161 rec.separated_DFS_child_list = embedg_dlcl_copy((*dfs_tree)[i]);
7162
7163 IF_VERB(
7164 fprintf(stdout, "the list of children ordered by lowpoint for DFI %d\n",
7165 i);
7166 embedg_dlcl_print(rec.separated_DFS_child_list);
7167 );
7168
7169 embed_graph[i] = rec;
7170 }
7171
7172 /*
7173 one more thing to do for these vertices:
7174 fix the rep_in_parent_list field
7175 */
7176 for (i = 1; i < n; i++)
7177 {
7178 t_dlcl *parent_list, *rep;
7179 int parent;
7180
7181 parent = embed_graph[i].DFS_parent; /* careful: this is a DFI */
7182 /*
7183 recall that the vertices in embed_graph are accessed via their DFI
7184 */
7185
7186 if (parent != n)
7187 /*
7188 when parent == n this means that i the root of a DFS tree
7189 in the disconnected graph
7190 */
7191 {
7192 parent_list = embed_graph[parent].separated_DFS_child_list;
7193 rep = embedg_dlcl_find(parent_list, i);
7194 ASSERT(rep != NP);
7195 embed_graph[i].rep_in_parent_list = rep;
7196 }
7197 }
7198
7199 /*
7200 embed_graph[n..2*n-1]: the n virtual vertices
7201 do I need to do anything here?????
7202
7203 no - I don't think so
7204
7205 let's try to explain what virtual vertices are:
7206 let v^c be a virtual vertex:
7207 - it is at position c + n in the array,
7208 - c is the DFS child of v,
7209 - v can be retrieved by taking embed_graph[c].DFS_parent,
7210 - v^c is said virtual as long as the bicomp rooted by v^c is not
7211 merged with the vertex v
7212 - once v is merged (identified?) with v^c, then v^c
7213 is of no relevance anymore
7214
7215 below we will see that we embed all the tree edges as singleton
7216 bicomps (bicomponent): (0^1, 1), (1^2, 2) etc...:
7217 this is what virtual vertices are there for:
7218 to distinguish them from their "real" counterpart with
7219 which they will be ultimately merged
7220
7221 the primary reason for this is:
7222 while testing for planarity virtual vertices are the roots of bicomps
7223 */
7224
7225 /*
7226 now the edges:
7227 we actually embed the tree edges so that each tree edge
7228 forms a (singleton) biconnected component
7229
7230 embedding an edge in effect means creating the
7231 doubly linked circular list of [virtual] vertices & the edges incident
7232 to it
7233
7234 this list is built using the links 0 & 1 in embed_graph[i]
7235 */
7236
7237 /*
7238 for each tree edge (v,u) we embed (v^u, u) (v^u is the virtual vertex)
7239
7240 CAREFUL: when talking about vertex v say,
7241 we mean the vertex with DFI v, and NOT the vertex with label v
7242 **************************************************************
7243 */
7244 *edge_pos = 2*n - 1;
7245 /*
7246 edge_pos will tell us where to insert the next edge in embed_graph[]
7247 */
7248 for (i = 0; i < n; i++)
7249 {
7250 t_dlcl *te_l, *p;
7251
7252 te_l = (*dfs_tree)[i];
7253 p = te_l;
7254
7255 if (!embedg_dlcl_is_empty(p))
7256 {
7257 /*
7258 the test below is a bit stupid... well...
7259 */
7260 ASSERT(embed_graph[p->info].DFS_parent == i);
7261
7262 embedg_init_insert_TE(embed_graph, n, edge_pos, p);
7263 p = embedg_dlcl_list_next(p);
7264 while (p != te_l)
7265 {
7266 ASSERT(embed_graph[p->info].DFS_parent == i);
7267 embedg_init_insert_TE(embed_graph, n, edge_pos, p);
7268
7269 p = embedg_dlcl_list_next(p);
7270 }
7271 }
7272 }
7273
7274 mem_free(dfs_nbr);
7275 mem_free(dfs_order);
7276 mem_free(lowpoint);
7277
7278 mem_free(dfs_parent);
7279 mem_free(least_a);
7280
7281 IF_CPU(
7282 fprintf(stdout, "CPU for remainder of initialisation %f\n",
7283 (time_current_user() - sttime));
7284 )
7285
7286 return embed_graph;
7287 }
7288
7289
7290 static void
embedg_init_insert_TE(t_ver_edge * embed_graph,int n,int * edge_pos,t_dlcl * p)7291 embedg_init_insert_TE (t_ver_edge *embed_graph, int n, int *edge_pos, t_dlcl *p)
7292 /*
7293 init and insert a tree edge in embed graph:
7294
7295 the tree edge will form a singleton bicomponent (v^c, c)
7296 where c is p->info and v is c.DFS_parent
7297 */
7298 {
7299 int c, v;
7300
7301 c = p->info;
7302 v = embed_graph[c].DFS_parent;
7303 ASSERT(v >= 0 && v < n);
7304
7305 /*
7306 now (v, c) is a tree edge; embed the directed edge [v^c, c]
7307
7308 -- and recall that v^c is a virtual vertex, at position c + n
7309 in embed_graph, and that vertex c is at position c
7310 */
7311
7312 /*
7313 first, set this edge with the appropriate info
7314 */
7315 (*edge_pos)++;
7316 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
7317 embed_graph[*edge_pos].neighbour = c;
7318 embed_graph[*edge_pos].in_adjl = p->in_adjl;
7319 embed_graph[*edge_pos].twin_in_adjl = p->twin_in_adjl;
7320
7321 ASSERT(p->mult % 2 == 0);
7322 /*
7323 we want the number of undirected edges
7324 */
7325 embed_graph[*edge_pos].mult = p->mult / 2;
7326 embed_graph[*edge_pos].type = TE;
7327 embed_graph[*edge_pos].sign = CCLOCKW;
7328
7329 /*
7330 link this with vertex v^c in a doubly linked circular list
7331 */
7332 embed_graph[c + n].link[0] =
7333 embed_graph[c + n].link[1] = *edge_pos;
7334 embed_graph[*edge_pos].link[0] =
7335 embed_graph[*edge_pos].link[1] = c + n;
7336
7337 /*
7338 now create/set the twin edge, the directed edge [c, v^c]
7339 */
7340 (*edge_pos)++;
7341 ASSERT(*edge_pos < 2*n + 2 * MAXE(n));
7342 embed_graph[*edge_pos].neighbour = c + n;
7343 embed_graph[*edge_pos].in_adjl = p->twin_in_adjl;
7344 embed_graph[*edge_pos].twin_in_adjl = p->in_adjl;
7345 embed_graph[*edge_pos].mult = p->mult / 2;
7346 embed_graph[*edge_pos].type = TE;
7347 embed_graph[*edge_pos].sign = CCLOCKW;
7348
7349 /*
7350 and link it with vertex c in a doubly linked circular list
7351 */
7352 embed_graph[c].link[0] = embed_graph[c].link[1] = *edge_pos;
7353 embed_graph[*edge_pos].link[0] =
7354 embed_graph[*edge_pos].link[1] = c;
7355 }
7356 /*
7357 * dfs_preprocessing.c
7358 */
7359
7360 /*
7361 What:
7362 *****
7363
7364 Implementing:
7365
7366 A DFS as an initialisation step for the planarity tester.
7367 This is an especially beefed up DFS that collects lots of
7368 marginal information:
7369
7370 - a DFS tree as a list of DFS children for each vertex
7371 - the DFS children are sorted according to their lowpoint value
7372 - a back_edge structure as a list of descendants v for each
7373 vertex u such that [v, u] is a back edge
7374 - a multiple edges structure which stores multiple (directed) edges
7375 NOT in the DFS tree nor in the back_edge struc, and loops
7376
7377 - the vertices in DFS order
7378 - the DFS index (DFI) for each vertex
7379 - the lowpoint value for each vertex
7380 - the number of components of the (possibly disconnected) graph
7381 - for each vertex, its DFS parent
7382 - for each vertex v, its least ancestor u such that [v, u]
7383 is a back edge
7384
7385 ALL info above (except the vertices in DFS order) is given
7386 in terms of the vertices' DFIs and NOT their labels.
7387
7388
7389
7390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
7391 from
7392
7393 Simplified O(n) Planarity Algorithms (draft)
7394 ************************************
7395
7396 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
7397 Wendy Myrvold wendym@csr.uvic.ca
7398
7399
7400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
7401 authors:
7402 ********
7403
7404 Paulette Lieby (Magma), Brendan McKay (ANU)
7405
7406 Started October 2001
7407 */
7408
7409
7410 /*
7411 There are some dodgy things which need some thought; it would be nice
7412 to fix them so that the code get's cleaner:
7413
7414 - we do store in_adj (and twin_in_adjl) for each directed edge:
7415
7416 + this is ONLY needed at the time of recovering the embedding
7417 (see embedg_recover_embedding) and its sole use is to establish
7418 a link between an edge in the embedding structure
7419 t_embed_sparse_rep *E and the corresponding edge
7420 in the t_adjl_sparse_rep *A struc.
7421
7422 + well, I cannot recall why I thought this correspondence
7423 was needed in the first place and it might well be the case
7424 that there is no use for it; in which case recovering the
7425 embedding is simplified
7426 (we would store the end-vertex in the embedding's edges instead
7427 of their index in the adjacency list)
7428
7429 - there are some non-linear bits in the DFS below: when searching
7430 for an already existing tree/back/multiple edge.
7431 I couldn't fix this in less then one hour so I leave it as it is...
7432 for now.
7433
7434 This shouldn't be a major issue, overall timings of the planarity
7435 tester do not show this non-linear "bump"...
7436
7437 - also, this algorithm has been growing incrementally and I now
7438 realise that I am using some redundant data structures:
7439 for example visited[] and the vertex and could be dispensed with...
7440 ...more things to clean up...
7441
7442 Paulette 07/02/02
7443 */
7444
7445
7446 #include "planarity.h"
7447
7448 #define IF_DEB(x) {}
7449 #define IF_VERB(x) {}
7450 #define IF_DEB_TREE(x) {}
7451
7452
7453 /* aproto: header embed_graph_protos.h */
7454
7455 #ifndef PLANAR_IN_MAGMA
7456 #endif
7457
7458
7459 void
sparseg_adjl_dfs_preprocessing(t_ver_sparse_rep * V,int n,t_adjl_sparse_rep * A,int * c,int ** dfs_nbr,int ** dfs_order,int ** lowpoint,t_dlcl *** dfs_tree,t_dlcl *** back_edges,int ** dfs_parent,int ** least_a,t_dlcl *** mult_edges)7460 sparseg_adjl_dfs_preprocessing (
7461 t_ver_sparse_rep *V,
7462 int n, /* size of the graph */
7463 t_adjl_sparse_rep *A, /* input sparse graph */
7464 int *c, /* nbr of components */
7465 int **dfs_nbr, /* dfs numbering for each vertex */
7466 int **dfs_order, /* vertices in dfs order */
7467 int **lowpoint, /* lowpoint value for each DFI */
7468 t_dlcl ***dfs_tree, /* a sparse graph rep. for the dfs tree:
7469 for each DFI, a list of its children's
7470 DFI ordered wrt their lowpoint values
7471 */
7472 t_dlcl ***back_edges, /* for each DFI v, a dlcl
7473 of the back edges [v, x] incident to v
7474 where x is a DESCENDANT of v */
7475 int **dfs_parent, /* for each DFI its DFS ancestor */
7476 int **least_a, /* for each DFI, its least ancestor's DFI
7477 via a back edge exclusively */
7478 t_dlcl ***mult_edges /* for each DFI v, a dlcl
7479 of the multiple directed
7480 edges NOT included
7481 in either dfs_tree or back_edges
7482 */
7483 )
7484
7485 /*
7486 in ALL the returned info above BUT dfs_order[] we store
7487 the vertices' DFIs (DFS indices) and NOT their labels!
7488
7489 -- shuffling between labels and vertices can then be done
7490 via dfs_nbr[] and dfs_order[]
7491 */
7492 {
7493 int pos_v_stack, pos_e_stack, dfs_n;
7494 int *visited, *vertex_stack, *edge_stack, *lowpoint_order;
7495 int *TE_in_adjl, *TE_twin_in_adjl, *TE_mult;
7496 int v, lp, cur, cur_e, next;
7497 t_dlcl **temp, *lowpoint_list, **new_dfs_tree;
7498
7499 /*
7500 create the dfs tree as a sparse graph
7501 */
7502 *dfs_tree = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
7503 /*
7504 the DFS numbering for the vertices
7505 */
7506 *dfs_nbr = (int *) mem_malloc(sizeof(int) * n);
7507 /*
7508 the vertices as ordered by their DFS index
7509 */
7510 *dfs_order = (int *) mem_malloc(sizeof(int) * n);
7511 /*
7512 the lowpoint value for each DFI
7513 */
7514 *lowpoint = (int *) mem_malloc(sizeof(int) * n);
7515
7516 /*
7517 the (directed) back edges
7518 */
7519 *back_edges = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
7520
7521
7522 /*
7523 the DFS parent for each DFI
7524 */
7525 *dfs_parent = (int *) mem_malloc(sizeof(int) * n);
7526 /*
7527 the least ancestor (via a back edge exlusively) for each DFI
7528 */
7529 *least_a = (int *) mem_malloc(sizeof(int) * n);
7530
7531 /*
7532 the (directed) multiple edges
7533 */
7534 *mult_edges = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
7535
7536 /*
7537 the vertices visited while DFS
7538 */
7539 visited = (int *) mem_malloc(sizeof(int) * n);
7540 /*
7541 stack of vertices: last current vertex
7542 */
7543 vertex_stack = (int *) mem_malloc(sizeof(int) * n);
7544 /*
7545 stack of (tree) edges: last added tree edge
7546 */
7547 edge_stack = (int *) mem_malloc(sizeof(int) * n);
7548
7549 /*
7550 the following will be used in order to recreate the dfs_tree
7551 so that the DFS children of each DFI are ordered
7552 according to their lowpoint value
7553 */
7554 lowpoint_order = (int *) mem_malloc(sizeof(int) * n);
7555 temp = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
7556 new_dfs_tree = (t_dlcl **) mem_malloc(sizeof(t_dlcl *) * n);
7557
7558 /*
7559 finally, three more holding arrays: a trick to remember which
7560 tree edges we are talking about:
7561
7562 when constructing dfs_tree, back_edges, mult_edges
7563 - we NEED to record the index in A (the adjacency list)
7564 of some of the edges and their twins/inverses
7565 we are currently storing in either of these structures
7566 - we also need to record the number of multiple (directed)
7567 edges we encounter when the graph is not simple
7568
7569 this is easy to do when storing back edges and multiple edges,
7570 and tree edges also: but this lattest set of neighbour lists (dfs_tree)
7571 is subsequently reordered so that DFS children are ordered
7572 wrt lowpoint values;
7573 - consequently the info about position in adjacency list
7574 and edge multiplicity are lost in the ordering process
7575
7576 the two following arrays will remember the info we'll need later
7577 - more about this below
7578 */
7579 TE_in_adjl = (int *) mem_malloc(sizeof(int) * n);
7580 TE_twin_in_adjl = (int *) mem_malloc(sizeof(int) * n);
7581 TE_mult = (int *) mem_malloc(sizeof(int) * n);
7582
7583
7584 /*
7585 initialization of the data structures
7586 */
7587 for (v = 0; v < n; v++)
7588 {
7589 (*dfs_tree)[v] = (*back_edges)[v] = (*mult_edges)[v] = NP;
7590 visited[v] = TE_mult[v] = 0;
7591 (*dfs_parent)[v] = (*least_a)[v] = n;
7592 temp[v] = new_dfs_tree[v] = NP;
7593 TE_in_adjl[v] = TE_twin_in_adjl[v] = NIL;
7594 /*
7595 note that in the 3rd last statement n is considered
7596 as an "invalid" value;
7597 will be if importance in the overall algorithm
7598 */
7599 }
7600
7601 /*
7602 the DFS tree is rooted at vertex 0
7603 */
7604 dfs_n = -1;
7605 pos_v_stack = -1;
7606 pos_e_stack = -1;
7607 *c = 0;
7608 for (v = 0; v < n; v++)
7609 {
7610 if (visited[v])
7611 /*
7612 we come only at this level when looking for
7613 a new subtree (when graph is disconnected)
7614 */
7615 {
7616 continue;
7617 }
7618 else
7619 {
7620 (*c)++;
7621 }
7622
7623 cur = v;
7624 visited[cur] = 1;
7625 (*dfs_nbr)[cur] = ++dfs_n;
7626 (*lowpoint)[(*dfs_nbr)[cur]] = dfs_n;
7627 (*dfs_order)[dfs_n] = cur;
7628
7629 cur_e = V[cur].first_edge == NIL ? NIL : V[cur].first_edge;
7630 while (TRUE)
7631 {
7632 if (cur_e != NIL)
7633 {
7634 t_dlcl *existing_e;
7635
7636 next = A[cur_e].end_vertex;
7637 if (!visited[next])
7638 /*
7639 adding tree edges (careful: directed edges)
7640
7641 AND tree edges are stored as
7642 [dfs_nbr[u], dfs_nbr[cv]]
7643 instead of [u, cv]: that is we store the edges
7644 according to the vertices' DFIs
7645 */
7646 {
7647 IF_DEB_TREE(
7648 io_printf("add tree edge %d\t%d\n",
7649 cur+1, next+1);
7650 );
7651
7652 (*dfs_nbr)[next] = ++dfs_n;
7653 (*lowpoint)[(*dfs_nbr)[next]] = dfs_n;
7654 (*dfs_order)[dfs_n] = next;
7655
7656 sparseg_dlcl_append_to_neigh_list(*dfs_tree, n,
7657 (*dfs_nbr)[cur],
7658 (*dfs_nbr)[next],
7659 NIL);
7660 TE_in_adjl[(*dfs_nbr)[next]] = cur_e;
7661 TE_mult[(*dfs_nbr)[next]]++;
7662
7663 /*
7664 we push cur and the edge (cur, cur_e) on their
7665 respective stacks
7666 */
7667 vertex_stack[++pos_v_stack] = cur;
7668 edge_stack[++pos_e_stack] = cur_e;
7669
7670 /*
7671 and mark next as visited
7672 */
7673 visited[next] = 1;
7674
7675 /*
7676 update dfs_parent (always deal with DFIs rembember!)
7677 */
7678 (*dfs_parent)[(*dfs_nbr)[next]] = (*dfs_nbr)[cur];
7679
7680 /*
7681 the DFS goes one level deeper
7682 */
7683 cur = next;
7684 cur_e = V[cur].first_edge == NIL ?
7685 NIL : V[cur].first_edge;
7686 }
7687 /*
7688 the next three tests deal with multiple edges
7689 and loops: apart from storing these (DIRECTED) edges
7690 in mult_edges, we also need to update
7691 the multipliciaty information about these edges
7692 */
7693 else if (sparseg_dlcl_is_adjacent(*dfs_tree, n,
7694 (*dfs_nbr)[cur],
7695 (*dfs_nbr)[next],
7696 &existing_e))
7697 /*
7698 [cur, next] is a tree edge
7699 */
7700 {
7701 sparseg_dlcl_append_to_neigh_list(*mult_edges, n,
7702 (*dfs_nbr)[cur],
7703 (*dfs_nbr)[next],
7704 cur_e);
7705 TE_mult[(*dfs_nbr)[next]]++;
7706
7707 cur_e = A[cur_e].next; /* next in cur's adjacency list */
7708 }
7709 else if (sparseg_dlcl_is_adjacent(*back_edges, n,
7710 (*dfs_nbr)[next],
7711 (*dfs_nbr)[cur],
7712 &existing_e))
7713 /*
7714 [cur, next] is a back edge
7715 */
7716 {
7717 sparseg_dlcl_append_to_neigh_list(*mult_edges, n,
7718 (*dfs_nbr)[cur],
7719 (*dfs_nbr)[next],
7720 cur_e);
7721 (existing_e->mult)++;
7722
7723 cur_e = A[cur_e].next; /* next in cur's adjacency list */
7724 }
7725 else if (next == cur)
7726 /*
7727 the case of a loop
7728 */
7729 {
7730 if (sparseg_dlcl_is_adjacent(*mult_edges, n,
7731 (*dfs_nbr)[next],
7732 (*dfs_nbr)[cur],
7733 &existing_e))
7734 /*
7735 in this case we must update the multiplicity
7736 of this edge: note that the elt. in cur's
7737 neighbours list that gets updated is the first
7738 in the list
7739
7740 dodgy??? certainly, but can't think
7741 of a better way to do this
7742
7743 eventually it will happen that even myself
7744 won't understand what I am doing..........
7745 */
7746 {
7747 (existing_e->mult)++;
7748 }
7749 sparseg_dlcl_append_to_neigh_list(*mult_edges, n,
7750 (*dfs_nbr)[cur],
7751 (*dfs_nbr)[next],
7752 cur_e);
7753
7754 cur_e = A[cur_e].next; /* next in cur's adjacency list */
7755 }
7756 else if (sparseg_dlcl_is_adjacent(*dfs_tree, n,
7757 (*dfs_nbr)[next],
7758 (*dfs_nbr)[cur],
7759 &existing_e))
7760 /*
7761 [next, cur] is a tree edge:
7762 that is, [cur, next] is [next, cur]'s twin/inverse:
7763
7764 1. if it is the first time one encounters
7765 [cur, next] (as it would always be the case
7766 for a simple graph) then all I need to do
7767 is to update the tree edge's multiplicity,
7768 and the twin info in TE_[]
7769
7770 2. if [cur, next] is actually a multiple edge,
7771 then I'll need to store it in mult_edges;
7772 and I update the tree edge's multiplicity too.
7773 No twin info will be required here.
7774 Why? see how recover.c embeds the multiple
7775 edges in the planar embedding.
7776
7777 3. how do I know it is the first time I encounter
7778 [cur, next]?:
7779 when TE_twin_in_adjl = NIL
7780
7781 4. finally, note that the present counting scheme
7782 implies that the mult field always holds
7783 the number of directed edges:
7784 ie, if [a, b] is a tree edge, [a, b].mult = 2
7785 because we would have counted [a, b] and [b, a]
7786
7787 this applies to tree edges, back edges, and loops
7788 */
7789 {
7790 ASSERT(TE_in_adjl[(*dfs_nbr)[cur]] != NIL);
7791 if (TE_twin_in_adjl[(*dfs_nbr)[cur]] == NIL)
7792 {
7793 TE_twin_in_adjl[(*dfs_nbr)[cur]] = cur_e;
7794 }
7795 else
7796 {
7797 sparseg_dlcl_append_to_neigh_list(*mult_edges, n,
7798 (*dfs_nbr)[cur],
7799 (*dfs_nbr)[next],
7800 cur_e);
7801 }
7802
7803 TE_mult[(*dfs_nbr)[cur]]++;
7804
7805 cur_e = A[cur_e].next; /* next in cur's adjacency list */
7806 }
7807 else if (sparseg_dlcl_is_adjacent(*back_edges, n,
7808 (*dfs_nbr)[cur],
7809 (*dfs_nbr)[next],
7810 &existing_e))
7811 /*
7812 [next, cur] is a back edge: [cur, next] is its inverse:
7813 we proceed as for the tree edge case above
7814 */
7815 {
7816 ASSERT(existing_e->in_adjl != NIL);
7817 if (existing_e->twin_in_adjl == NIL)
7818 {
7819 existing_e->twin_in_adjl = cur_e;
7820 }
7821 else
7822 {
7823 sparseg_dlcl_append_to_neigh_list(*mult_edges, n,
7824 (*dfs_nbr)[cur],
7825 (*dfs_nbr)[next],
7826 cur_e);
7827 }
7828
7829 (existing_e->mult)++;
7830
7831 cur_e = A[cur_e].next; /* next in cur's adjacency list */
7832 }
7833 /*
7834 the next bit concludes the DFS: it deals with the case
7835 where a back edge needs to be added
7836 */
7837 else
7838 /*
7839 that is, next is visited and neither
7840 the tree edge [next, cur] nor
7841 the back edge [next, cur] exist:
7842
7843 this implies that [cur, next] is a back edge
7844 that must be added to the back_edges structure
7845 (with dfs_nbr(next) < dfs_nbr(cur))
7846 */
7847 {
7848 IF_DEB_TREE(
7849 io_printf("add back edge %d\t%d\n",
7850 cur+1, next+1);
7851 );
7852
7853 ASSERT(visited[next]);
7854 ASSERT((*dfs_nbr)[cur] > (*dfs_nbr)[next]);
7855
7856 sparseg_dlcl_append_to_neigh_list(*back_edges, n,
7857 (*dfs_nbr)[next],
7858 (*dfs_nbr)[cur],
7859 cur_e);
7860
7861 /*
7862 update cur's lowpoint
7863 */
7864 (*lowpoint)[(*dfs_nbr)[cur]] =
7865 (*dfs_nbr)[next] < (*lowpoint)[(*dfs_nbr)[cur]] ?
7866 (*dfs_nbr)[next] : (*lowpoint)[(*dfs_nbr)[cur]];
7867
7868 /*
7869 update least_a (of cur)
7870 (always deal with DFIs remember!)
7871 */
7872 (*least_a)[(*dfs_nbr)[cur]] =
7873 (*dfs_nbr)[next] < (*least_a)[(*dfs_nbr)[cur]] ?
7874 (*dfs_nbr)[next] : (*least_a)[(*dfs_nbr)[cur]];
7875
7876 /*
7877 get the next edge in cur's adjacency list
7878 */
7879 cur_e = A[cur_e].next;
7880 }
7881 }
7882
7883 if (cur_e == NIL)
7884 /*
7885 we are either at a leaf or have finished scanning
7886 cur's adjacency list: backtrack
7887 */
7888 {
7889 if (pos_v_stack == -1) /* no previous vertex */
7890 {
7891 /*
7892 no edge left on the stack: DFS ends for
7893 this subtree:
7894 we visit the next vertex
7895 */
7896 ASSERT(pos_e_stack == -1);
7897 break;
7898 }
7899 else
7900 {
7901 int prev_e;
7902 /*
7903 Otherwise backtrack and pop cur from the stack
7904 as well as the last tree edge added to the tree.
7905 We use next to get a new lowpoint value for cur:
7906 This value will be min(lowpoint(cur), lowpoint(next)).
7907 */
7908 cur = vertex_stack[pos_v_stack--];
7909 prev_e = edge_stack[pos_e_stack--];
7910 next = A[prev_e].end_vertex;
7911 (*lowpoint)[(*dfs_nbr)[cur]] =
7912 (*lowpoint)[(*dfs_nbr)[cur]]
7913 < (*lowpoint)[(*dfs_nbr)[next]] ?
7914 (*lowpoint)[(*dfs_nbr)[cur]]
7915 : (*lowpoint)[(*dfs_nbr)[next]];
7916
7917 cur_e = A[prev_e].next;
7918 }
7919 /*
7920 we proceed with DFS
7921 */
7922 }
7923 }
7924 }
7925 mem_free(vertex_stack);
7926 mem_free(edge_stack);
7927
7928 /*
7929 just for the sake of it, check that all vertices have
7930 been visited
7931 */
7932 #ifdef ASSERTIONS
7933 for (v = 0; v < n; v++)
7934 {
7935 ASSERT(visited[v]);
7936 }
7937 #endif
7938 mem_free(visited);
7939
7940 /*
7941 we now order the DFIs wrt lowpoint values:
7942 use bucket sort (linear time)
7943 */
7944 /*
7945 for each lowpoint value, collect the DFIs (in a t_dlcl)
7946 with that lowpoint value
7947 (IMPORTANT: we want the DFIs since the aim is to rewrite dfs_tree
7948 which stores DFIs and not labels!)
7949 */
7950 for (v = 0; v < n; v++)
7951 /*
7952 v is taken as a DFI here
7953 */
7954 {
7955 t_dlcl *r;
7956
7957 r = embedg_dlcl_rec_new(v);
7958 temp[(*lowpoint)[v]] =
7959 embedg_dlcl_rec_append(temp[(*lowpoint)[v]], r);
7960 }
7961
7962 /*
7963 concatenate these lists now
7964 */
7965 lowpoint_list = temp[0];
7966 for (lp = 1; lp < n; lp++)
7967 {
7968 lowpoint_list = embedg_dlcl_cat(lowpoint_list, temp[lp]);
7969 }
7970 ASSERT(embedg_dlcl_length(lowpoint_list) == n);
7971
7972 lowpoint_order[0] = lowpoint_list->info;
7973 for (lp = 1; lp < n; lp++)
7974 {
7975 lowpoint_list = embedg_dlcl_list_next(lowpoint_list);
7976 lowpoint_order[lp] = lowpoint_list->info;
7977 }
7978 embedg_dlcl_delete(lowpoint_list);
7979 mem_free(temp);
7980
7981 IF_DEB(
7982 fprintf(stdout, "dfs_preprocessing, lowpoint_order\n");
7983 for (lp = 0; lp < n; lp++)
7984 fprintf(stdout, "%d ", lowpoint_order[lp]);
7985 fprintf(stdout, "\n");
7986 fprintf(stdout, "dfs_preprocessing, lowpoint\n");
7987 for (lp = 0; lp < n; lp++)
7988 fprintf(stdout, "%d ", (*lowpoint)[lp]);
7989 fprintf(stdout, "\n");
7990 )
7991
7992 /*
7993 we now use this order to rewrite dfs_tree such that
7994 the DFS children of each vertex are ordered wrt lowpoint values
7995 */
7996 for (lp = 0; lp < n; lp ++)
7997 /*
7998 for each DFI in lowpoint_order[] I know its DFS_parent
7999 from dfs_parent[] -- the rest is then trivial
8000 */
8001 {
8002 int parent;
8003
8004 v = lowpoint_order[lp];
8005 /*
8006 lowpoint_order stores DFIs as does dfs_parent, so the lot
8007 makes sense
8008 */
8009 parent = (*dfs_parent)[v];
8010 if (parent != n)
8011 /*
8012 v may be the root of a DFS tree
8013 */
8014 {
8015 t_dlcl *temp;
8016
8017 temp = embedg_dlcl_rec_new(v);
8018
8019 /*
8020 this is where the TE_ holding arrays are useful *sigh*
8021 */
8022 ASSERT(TE_in_adjl[v] != NIL);
8023 temp->in_adjl = TE_in_adjl[v];
8024
8025 ASSERT(TE_twin_in_adjl[v] != NIL);
8026 temp->twin_in_adjl = TE_twin_in_adjl[v];
8027
8028 ASSERT(TE_mult[v] != 0 && TE_mult[v] % 2 == 0);
8029 temp->mult = TE_mult[v];
8030
8031 new_dfs_tree[parent] =
8032 embedg_dlcl_rec_append(new_dfs_tree[parent], temp);
8033 }
8034 }
8035 mem_free(lowpoint_order);
8036 mem_free(TE_in_adjl);
8037 mem_free(TE_twin_in_adjl);
8038 mem_free(TE_mult);
8039
8040 /*
8041 some checks are in order here
8042 */
8043 #ifdef ASSERTIONS
8044 for (v = 0; v < n; v++)
8045 {
8046 ASSERT(embedg_dlcl_length((*dfs_tree)[v])
8047 == embedg_dlcl_length(new_dfs_tree[v]));
8048
8049 IF_DEB(
8050 fprintf(stdout, "dfs_preprocessing dfs_tree for %d\n", v);
8051 embedg_dlcl_print((*dfs_tree)[v]);
8052 fprintf(stdout, "dfs_preprocessing new_dfs_tree for %d\n", v);
8053 embedg_dlcl_print(new_dfs_tree[v]);
8054 );
8055 }
8056 #endif
8057
8058 sparseg_dlcl_delete(*dfs_tree, n);
8059 *dfs_tree = new_dfs_tree;
8060 }
8061
8062 /*
8063 * embedding.c
8064 */
8065
8066 /*
8067 What:
8068 *****
8069
8070 Implementing:
8071
8072 The graph is planar: we recover the embedding from the VES structure
8073 and check it as well.
8074 (Some of these checks will disappear later)
8075
8076
8077 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8078 from
8079
8080 Simplified O(n) Planarity Algorithms (draft)
8081 ************************************
8082
8083 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
8084 Wendy Myrvold wendym@csr.uvic.ca
8085
8086
8087 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8088 authors:
8089 ********
8090
8091 Paulette Lieby (Magma), Brendan McKay (ANU)
8092
8093 Started October 2001
8094 */
8095
8096
8097 #include "planarity.h"
8098
8099 #define IF_DEB(x) {}
8100 #define IF_DEB_EMBED(x) {}
8101 #define IF_DEB_CHECK_EMBED(x) {}
8102 #define IF_DEB_FACES(x) {}
8103 #define IF_VERB(x) {}
8104 #define IF_DEB_SCE(x) {}
8105 #define IF_CPU(x) {}
8106
8107
8108 /* aproto: header embed_graph_protos.h */
8109
8110
8111 #ifndef PLANAR_IN_MAGMA
8112 #endif
8113
8114 void
embedg_embedding(t_ver_sparse_rep * V,t_adjl_sparse_rep * A,t_ver_edge * embed_graph,int n,int e,int nbr_c,int edge_pos,t_dlcl ** mult_edges,t_ver_sparse_rep ** vertices,t_embed_sparse_rep ** embedding)8115 embedg_embedding (t_ver_sparse_rep *V, t_adjl_sparse_rep *A,
8116 t_ver_edge *embed_graph, int n, int e, int nbr_c,
8117 int edge_pos, t_dlcl **mult_edges, t_ver_sparse_rep **vertices,
8118 t_embed_sparse_rep **embedding)
8119 /*
8120 recovering the embedding for the (planar) graph
8121
8122 - the embedding is returned in vertices and embedding, vertices
8123 indexes embedding, the ordered list of edges
8124 - edges in the embedding are given as their index in A, the graph's
8125 adajacency list
8126 - the nbr of edges in the embedding is given as nbr_e_embed:
8127 this may be different form the original number of edges when the graph
8128 iss not simple
8129 */
8130 {
8131 int *ver_orient, nbr_comp, nbr_e_embed;
8132
8133 IF_CPU(
8134 float sttime; float time_to_now;
8135
8136 sttime = time_current_user();
8137 )
8138
8139 IF_DEB(
8140 fprintf(stdout, "embedding, begin, which edges have been flipped\n");
8141 embedg_VES_print_flipped_edges(embed_graph, n, edge_pos);
8142 )
8143
8144 IF_DEB(
8145 fprintf(stdout, "embedding, before removing SCE\n");
8146 embedg_VES_print_bigcomps(embed_graph, n);
8147 )
8148
8149 /*
8150 several things to do:
8151 1. removing the short-cut edges
8152 */
8153 embedg_remove_SCE(embed_graph, n, edge_pos);
8154
8155 IF_DEB(
8156 fprintf(stdout, "embedding, after removing SCE\n");
8157 embedg_VES_print_bigcomps(embed_graph, n);
8158 )
8159
8160 /*
8161 2. computing each vertex's orientation (wrt flipped bicomps)
8162 */
8163 ver_orient = embedg_vertices_orientation(embed_graph, n);
8164
8165
8166 /*
8167 3. merging the remaining virtual vertices with their
8168 non-virtual counterpart
8169 */
8170 nbr_comp = embedg_merge_remaining_virtual(embed_graph, n);
8171 /*
8172 actually there is no need to return the nbr of components
8173 from the above function
8174 but let's do it for the sake of it and for possible checking
8175 */
8176 ASSERT(nbr_c == nbr_comp);
8177
8178 IF_DEB(
8179 fprintf(stdout, "embedding, after merging of remaining vertices\n");
8180 )
8181
8182 /*
8183 4. to be on the safe side: check that the embedding is a valid one
8184
8185 for now, we DIE if not
8186 */
8187
8188 if (!embedg_is_embed_valid(embed_graph, n, nbr_comp, edge_pos,
8189 ver_orient, &nbr_e_embed))
8190 {
8191 mem_free(ver_orient);
8192 DIE();
8193 }
8194 mem_free(ver_orient);
8195
8196 ASSERT(nbr_e_embed <= e);
8197 /*
8198 when the graph is not simple, multiple edges and loops are
8199 not in embed_graph[]: they will be added to the final
8200 embedding in embedg_recover_embedding below
8201 */
8202
8203 /*
8204 5. recover the embedding in preparation for the Magma type,
8205 and check it as well
8206 */
8207 embedg_recover_embedding(V, A, embed_graph, n, e,
8208 mult_edges, vertices, embedding);
8209 if (!embedg_check_recov_embedding(n, e, nbr_comp,
8210 *vertices, A, *embedding))
8211 {
8212 mem_free(*vertices);
8213 mem_free(*embedding);
8214
8215 IF_CPU(
8216 fprintf(stdout, "CPU for embedding recovering %f\n",
8217 time_current_user() - sttime);
8218 )
8219
8220 DIE();
8221 }
8222
8223 IF_DEB_EMBED(
8224 fprintf(stdout, "embedding, original graph and embedding\n");
8225 sparseg_adjl_print(V, n, A, FALSE);
8226 fprintf(stdout, "\n");
8227 sparseg_adjl_embed_print(*vertices, n, A, *embedding,
8228 FALSE);
8229 )
8230
8231 IF_CPU(
8232 fprintf(stdout, "CPU for embedding recovering %f\n",
8233 time_current_user() - sttime);
8234 )
8235 }
8236
8237
8238 void
embedg_remove_SCE(t_ver_edge * embed_graph,int n,int edge_pos)8239 embedg_remove_SCE (t_ver_edge *embed_graph, int n, int edge_pos)
8240 /*
8241 remove all the short-cut edges from the embedding
8242 */
8243 {
8244 int i, c;
8245
8246 c = 0;
8247 for (i = 2*n; i <= edge_pos; i += 2)
8248 /*
8249 and edge and its twin occupy consecutive positions in embed_graph:
8250 need only to examine one out of two
8251 (removing an edge also entails removing its twin of course
8252 */
8253 {
8254 if (embedg_VES_is_short_cut_edge(embed_graph, n, i))
8255 {
8256 IF_DEB_SCE(
8257 fprintf(stdout, "remove SCE\n");
8258 embedg_VES_print_edge(embed_graph, n, i);
8259 )
8260
8261 embedg_VES_remove_edge(embed_graph, n, i);
8262 c++;
8263 }
8264 }
8265
8266 IF_DEB_SCE(
8267 fprintf(stdout, "nbr of SCE edges removed %d\n", c);
8268 )
8269 }
8270
8271
8272 int *
embedg_vertices_orientation(t_ver_edge * embed_graph,int n)8273 embedg_vertices_orientation (t_ver_edge *embed_graph, int n)
8274 /*
8275 for each vertex return its orientation from the
8276 bicomps in embed_graph:
8277 perform a DFS of each bicomp
8278 */
8279 {
8280 int i, vv, prod_sign;
8281 int *stack, *ver_orient, to_prev;
8282
8283 /*
8284 the whole lot makes sense iff the adjacency lists are consistent:
8285 this is a very important issue and it might be the case
8286 that the ASSERT warrants replacement by a DIE
8287 (the check is linear - I think)
8288 */
8289 ASSERT(embedg_VES_are_adj_lists_consistent(embed_graph, n));
8290
8291 ver_orient = (int *) mem_malloc(sizeof(int) * n);
8292 for (i = 0; i < n; i++)
8293 {
8294 ver_orient[i] = CCLOCKW;
8295 }
8296
8297 /*
8298 create the stack for the DFS
8299 */
8300 stack = (int *) mem_malloc(sizeof(int) * 3*n);
8301 to_prev = -1;
8302
8303 IF_DEB(
8304 fprintf(stdout, "vertex orientation, one line (of vert.) for each bicomp\n");
8305 )
8306
8307 /*
8308 now visit all the bicomps, ie, all the virtual vertices
8309 in embed_graph
8310 */
8311 for (vv = n; vv < 2*n; vv++)
8312 {
8313 int c, cur, cur_e;
8314 boolean NEW_BICOMP;
8315
8316 if (embed_graph[vv].link[0] == vv)
8317 /*
8318 means that vv is disabled and is not the root of a bicomp
8319 */
8320 {
8321 continue;
8322 }
8323
8324 c = vv - n;
8325 IF_DEB(
8326 fprintf(stdout, "%d ", c);
8327 )
8328 /*
8329 orientation for c (vv is as yet unembedded) is CCLOCKW
8330
8331 now find the orientation of all its DFS descendants
8332 */
8333
8334 if (embed_graph[c].DFS_parent == n)
8335 /*
8336 this means that actually c is an isolated vertex:
8337 we initialise the sign to CCLOCKW
8338 */
8339 {
8340 prod_sign = CCLOCKW;
8341 }
8342 else
8343 /*
8344 we initialise the sign to CCLOCKW to the sign of c's parent
8345 */
8346 {
8347 prod_sign = ver_orient[embed_graph[c].DFS_parent];
8348 }
8349
8350 /*
8351 we must not forget to set c's sign!!
8352 (won't be done below)
8353 */
8354 ver_orient[c] = prod_sign;
8355
8356 NEW_BICOMP = FALSE;
8357 cur = c;
8358 cur_e = embed_graph[cur].link[0];
8359 ASSERT(embedg_VES_is_edge(n, cur_e));
8360
8361 ASSERT(to_prev == -1);
8362 while (TRUE)
8363 {
8364 while (!embedg_VES_is_tree_edge(embed_graph, n, cur_e)
8365 || !embedg_VES_is_vertex(n,
8366 embed_graph[cur_e].neighbour)
8367 || embed_graph[cur_e].neighbour <= cur)
8368 /*
8369 want to find a tree edge [cur, u]
8370 where u is a descendant of cur
8371 */
8372 {
8373 cur_e = embed_graph[cur_e].link[0];
8374
8375 while (cur_e == cur)
8376 /*
8377 back to the vertex where we started from:
8378 no edge has been found:
8379 cur is a leaf, backtrack
8380 */
8381 {
8382 if (to_prev == -1)
8383 {
8384 NEW_BICOMP = TRUE;
8385 break;
8386 }
8387 prod_sign = stack[to_prev--];
8388 cur_e = stack[to_prev--];
8389 /*
8390 must advance one more edge
8391 */
8392 cur_e = embed_graph[cur_e].link[0];
8393 cur = stack[to_prev--];
8394 }
8395 if (NEW_BICOMP)
8396 {
8397 break;
8398 }
8399 }
8400
8401 if (NEW_BICOMP)
8402 {
8403 break;
8404 }
8405 else
8406 /*
8407 now cur_e is the edge we were looking for, get its sign
8408 */
8409 {
8410 /*
8411 push on stack the current vertex, the edge where we
8412 stopped the DFS, AND the sign carried by that vertex
8413
8414 and go down one level in the DFS
8415 */
8416 stack[++to_prev] = cur;
8417 stack[++to_prev] = cur_e;
8418 stack[++to_prev] = prod_sign;
8419
8420 cur = embed_graph[cur_e].neighbour;
8421 prod_sign *= embed_graph[cur_e].sign;
8422 ver_orient[cur] = prod_sign;
8423
8424 cur_e = embed_graph[cur].link[0];
8425 ASSERT(embedg_VES_is_edge(n, cur_e));
8426
8427 IF_DEB(
8428 fprintf(stdout, "%d with sign %d\n", cur, prod_sign);
8429 )
8430 }
8431 }
8432
8433 IF_DEB(
8434 fprintf(stdout, "\n");
8435 )
8436 }
8437
8438 IF_DEB(
8439 fprintf(stdout, "vertex orientation\n");
8440 for (i = 0; i < n; i++)
8441 {
8442 fprintf(stdout, "%d ", ver_orient[i]);
8443 }
8444 fprintf(stdout, "\n");
8445 )
8446
8447 mem_free(stack);
8448 return ver_orient;
8449 }
8450
8451
8452 int
embedg_merge_remaining_virtual(t_ver_edge * embed_graph,int n)8453 embedg_merge_remaining_virtual (t_ver_edge *embed_graph, int n)
8454 /*
8455 after the short-cut edges have been removed and the vertices'
8456 orientation computed, one finishes by merging all
8457 remaining virtual vertices with their virtual counterpart
8458 (without flip of course)
8459
8460 and use this routine to return the number of disconnected
8461 components of the graph
8462 */
8463 {
8464 /*
8465 at this stage it is easy to see that all remaining
8466 virtual vertices are DFS roots (if the graph is not connected)
8467 or cut vertices
8468 */
8469
8470 int vv, nbr_comp;
8471
8472 nbr_comp = 0;
8473 for (vv = n; vv < 2*n; vv++)
8474 {
8475 int v, c;
8476
8477
8478 c = vv - n;
8479 v = embed_graph[c].DFS_parent;
8480
8481 /*
8482 must fish out which virtual vertices are actual roots
8483 of DFS trees (esp. for the disconnected graph case):
8484 roots of DFS trees are those virtual vertices for which
8485 v = embed_graph[c].DFS_parent = n
8486 */
8487 if (v == n)
8488 {
8489 nbr_comp++;
8490 continue;
8491 }
8492
8493 if (embed_graph[vv].link[0] == vv)
8494 /*
8495 means that vv is disabled and is not the root of a bicomp
8496 */
8497 {
8498 continue;
8499 }
8500
8501 embedg_VES_merge_simple_bicomps(embed_graph, n,
8502 vv, 1, v, 0);
8503 /*
8504 note:
8505 since v is a cut vertex in this intance the bicomp
8506 rooted by vv will be merged without flip;
8507 therefore we could have done
8508 embedg_VES_merge_simple_bicomps(embed_graph, n,
8509 vv, 0, v, 1)
8510 as well, the important thing being that vin != vvout
8511 (see embedg_VES_merge_simple_bicomps)
8512 */
8513 }
8514
8515 return nbr_comp;
8516 }
8517
8518
8519 int
embedg_nbr_faces(t_ver_edge * embed_graph,int n,int edge_pos,int * ver_orient,int * nbr_e_embed)8520 embedg_nbr_faces (t_ver_edge *embed_graph, int n, int edge_pos,
8521 int *ver_orient, int *nbr_e_embed)
8522 /*
8523 count the number of faces and the number of edges of the embedding
8524 */
8525 {
8526 int v, e, f, total_e;
8527
8528 IF_DEB_FACES(
8529 int v;
8530
8531 fprintf(stdout, "nbr of faces, the vertices' adj. lists\n");
8532 for (v = 0; v < n; v++)
8533 embedg_VES_print_adj_list(embed_graph, n,
8534 v, TRUE);
8535 )
8536
8537 /*
8538 the following is no more than a quick check -- certainly
8539 not very useful -- or could be done elsewhere
8540 */
8541 total_e = 0;
8542 for (e = 2*n; e <= edge_pos; e++)
8543 {
8544 if (!embedg_VES_is_short_cut_edge(embed_graph, n, e))
8545 {
8546 total_e++;
8547 }
8548 }
8549 ASSERT(total_e % 2 == 0);
8550 *nbr_e_embed = total_e / 2;
8551
8552 /*
8553 I now set each edge's orientation
8554
8555 QUESTION: do I really need to do this???
8556 so far, when doing a proper face traversal, the way in which
8557 the adjacency list of an edge must be traversed is given
8558 by the vertex's (in that list) orientation...
8559 So this seems sensible to me huh?
8560 */
8561 embedg_VES_set_orientation(embed_graph, n, ver_orient);
8562
8563 /*
8564 I will be using the visited field to enable me to check
8565 if all edges have been traversed
8566
8567 let's be smart (?!): so far the visited field has been used
8568 and set in the following circumstances:
8569 + initialisation: set to n
8570 + walkup: set to whatever DFI of interest
8571
8572 so here we set it to MARK_EMBED(n)
8573 */
8574 f = 0;
8575 for (e = 2*n; e <= edge_pos; e++)
8576 {
8577 if (!embedg_VES_is_short_cut_edge(embed_graph, n, e)
8578 /*
8579 arrghh!!! I must also skip the SCE!!!
8580 */
8581 && embed_graph[e].visited != MARK_EMBED(n))
8582 {
8583 int ein;
8584
8585 IF_DEB_FACES(
8586 fprintf(stdout, "nbr of faces, edges not visited\n");
8587 embedg_VES_print_edge(embed_graph, n, e);
8588 )
8589
8590 ein = embed_graph[e].sign == CCLOCKW ? 0 : 1;
8591 /*
8592 the way I enter e in dependent on its sign:
8593 all the proper face traversal must obviously be done
8594 with the same orientation!
8595 */
8596 embedg_VES_walk_proper_face(embed_graph, n, e,
8597 ein,
8598 TRUE,
8599 MARK_EMBED(n));
8600 f++;
8601 }
8602 }
8603
8604 /*
8605 counting the faces by traversing all the edges does not
8606 account of the face defined by isolated vertices
8607 -- we do that now
8608
8609 we only need to check which vertices refer to self, ie with
8610 no incident edges
8611 */
8612 for (v = 0; v < n; v++)
8613 {
8614 if (embed_graph[v].link[0] == v)
8615 {
8616 ASSERT(embed_graph[v].link[1] == v);
8617 f++;
8618 }
8619 }
8620
8621 return f;
8622 }
8623
8624
8625 boolean
embedg_is_embed_valid(t_ver_edge * embed_graph,int n,int nbr_comp,int edge_pos,int * ver_orient,int * nbr_e_embed)8626 embedg_is_embed_valid (t_ver_edge *embed_graph, int n, int nbr_comp,
8627 int edge_pos, int *ver_orient, int *nbr_e_embed)
8628 /*
8629 use Euler's formula to assertain that the embedding is a valid
8630 embedding:
8631
8632 f = 2 * nbr_comp + nbr_e_embed - n
8633
8634 */
8635 {
8636 int v, f;
8637
8638 f = embedg_nbr_faces(embed_graph, n, edge_pos, ver_orient, nbr_e_embed);
8639
8640 IF_DEB_CHECK_EMBED(
8641 fprintf(stdout, "embedding, n: %d\t e: %d\t C: %d\t f: %d\n",
8642 n, nbr_e, nbr_comp, f);
8643 )
8644
8645 return f == 2 * nbr_comp + *nbr_e_embed - n ? TRUE : FALSE;
8646 }
8647 /*
8648 * ext_face_walk.c
8649 */
8650
8651 /*
8652 What:
8653 *****
8654
8655 Implementing the external face walk of a bicomponent.
8656 The concept of an external face --in the context of the VES
8657 data structure-- makes only sense when talking
8658 about a bicomp.
8659
8660 Recall that a vertex is linked together with the edges
8661 incident from it in a circular (doubly) linked list
8662 (this is the VES structure).
8663
8664 One particular feature is that if a vertex v is on
8665 the external face of a component and if in the list
8666 we have edges e1, e2 such as e1 -> v -> e2
8667 then e1 and e2 border the external face.
8668
8669 In other words, in the circular list of vertex v and edges,
8670 v is ALWAYS between the two edges bordering the external face
8671
8672 Of course, when v is (maybe) pushed into the internal face
8673 (by embedding of some edge) then we don't care about this any more
8674 (for v that is).
8675
8676
8677
8678 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8679 from
8680
8681 Simplified O(n) Planarity Algorithms (draft)
8682 ************************************
8683
8684 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
8685 Wendy Myrvold wendym@csr.uvic.ca
8686
8687
8688 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8689 authors:
8690 ********
8691
8692 Paulette Lieby (Magma), Brendan McKay (ANU)
8693
8694 Started October 2001
8695 */
8696
8697
8698 #include "planarity.h"
8699
8700 #define IF_DEB(x) {}
8701 #define IF_VERB(x) {}
8702
8703
8704 /* aproto: header embed_graph_protos.h */
8705
8706
8707 void
embedg_VES_get_succ_on_ext_face(t_ver_edge * embed_graph,int n,int v,int vin,boolean MARK,int mark,int * s,int * sin)8708 embedg_VES_get_succ_on_ext_face (t_ver_edge *embed_graph, int n, int v,
8709 int vin, boolean MARK, int mark, int *s, int *sin)
8710 /*
8711 find the successor s of v (entered via vin) on the external face
8712 -- also return the direction in which s has been entered
8713
8714 if MARK true mark the succ. vertex and the edges traversed
8715 with mark (the visited field)
8716 */
8717 {
8718 int e, twin;
8719 int vout, ein, eout, tout;
8720
8721 ASSERT(embedg_VES_is_vertex(n, v)
8722 || embedg_VES_is_virtual_vertex(n, v));
8723
8724 IF_DEB(
8725 fprintf(stdout, "get_succ_on_ext_face, of %d:%d\n", v, vin);
8726 )
8727
8728 /*
8729 find the direction out of the vertex, and get the edge
8730 */
8731 vout = vin == 0 ? 1 : 0;
8732 e = embed_graph[v].link[vout];
8733 if (embedg_VES_is_virtual_vertex(n, v) && e == v)
8734 /*
8735 this can happen if a virtual vertex has been "disabled"
8736
8737 -- this should not never happen since we can only walk
8738 on the external face of a bicomp!
8739 */
8740 {
8741 *s = v;
8742 *sin = vin;
8743 return;
8744 }
8745
8746 /*
8747 otherwise we must have an edge:
8748 note that it is entirely irrelevant if I walk SCEs:
8749 those are precisely there to "jump" over inactive vertices
8750 */
8751 ASSERT(embedg_VES_is_edge(n, e));
8752
8753 /*
8754 get the twin edge
8755 */
8756 twin = embedg_VES_get_twin_edge(embed_graph, n, e);
8757
8758 IF_DEB(
8759 fprintf(stdout, "get_succ_on_ext_face, edge [%d, %d]\n",
8760 v, embed_graph[e].neighbour);
8761 fprintf(stdout, "get_succ_on_ext_face, twin edge [%d, %d]\n",
8762 embed_graph[e].neighbour, embed_graph[twin].neighbour);
8763 )
8764 /*
8765 find which of twin's link links a vertex
8766 */
8767 tout = embedg_VES_is_vertex(n, embed_graph[twin].link[0])
8768 || embedg_VES_is_virtual_vertex(n,
8769 embed_graph[twin].link[0])
8770 ?
8771 0 : 1;
8772
8773 /*
8774 get this vertex: this is v's successor on the external face
8775 */
8776 *s = embed_graph[twin].link[tout];
8777
8778 /*
8779 one more thing to do: find the direction in which s was entered
8780 */
8781 *sin = embed_graph[*s].link[0] == twin ? 0 : 1;
8782
8783 IF_DEB(
8784 fprintf(stdout, "get_succ_on_ext_face, succ is %d:%d\n",
8785 *s, *sin);
8786 )
8787 /*
8788 a special case: when the bicomp is a singleton bicomp
8789 (ie a single edge)
8790 */
8791 if (embed_graph[*s].link[0] == (embed_graph[*s].link[1]))
8792 {
8793 ASSERT(embed_graph[*s].link[0] = twin);
8794 *sin = vin;
8795 }
8796
8797 /*
8798 finally, mark the vertex and edges if so requested
8799 */
8800 if (MARK)
8801 {
8802 embed_graph[*s].visited = mark;
8803 embed_graph[e].visited = mark;
8804 embed_graph[twin].visited = mark;
8805 }
8806 }
8807
8808 void
embedg_VES_get_succ_active_on_ext_face(t_ver_edge * embed_graph,int n,int v,int w,int win,boolean MARK,int mark,int * s,int * sin)8809 embedg_VES_get_succ_active_on_ext_face (t_ver_edge *embed_graph, int n,
8810 int v, int w, int win, boolean MARK, int mark, int *s, int *sin)
8811 /*
8812 find the ACTIVE (wrt v) successor s of w (entered via win)
8813 on the external face
8814 -- also return the direction in which s has been entered
8815
8816 if MARK true mark the succ. vertex (and the edge)
8817 with mark (the visited field)
8818 */
8819 {
8820 /*
8821 simply repeatedly calls embedg_VES_get_succ_on_ext_face
8822 until an active vertex is found
8823 */
8824 ASSERT(embedg_VES_is_vertex(n, w)
8825 || embedg_VES_is_virtual_vertex(n, w));
8826
8827 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8828 w, win, MARK, mark, s, sin);
8829 while (embedg_VES_is_ver_inactive(embed_graph, n, v, *s))
8830 {
8831 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8832 *s, *sin, MARK, mark, s, sin);
8833 }
8834 ASSERT(!embedg_VES_is_ver_inactive(embed_graph, n, v, *s));
8835 }
8836
8837 void
embedg_VES_get_succ_ext_active_on_ext_face(t_ver_edge * embed_graph,int n,int v,int w,int win,boolean MARK,int mark,int * s,int * sin)8838 embedg_VES_get_succ_ext_active_on_ext_face (t_ver_edge *embed_graph, int n,
8839 int v, int w, int win, boolean MARK, int mark, int *s, int *sin)
8840 /*
8841 find the externally active (wrt v) successor s of w (entered via win)
8842 on the external face
8843 -- also return the direction in which s has been entered
8844
8845 if MARK true mark the succ. vertex (and the edge)
8846 with mark (the visited field)
8847 */
8848 {
8849 ASSERT(embedg_VES_is_vertex(n, w)
8850 || embedg_VES_is_virtual_vertex(n, w));
8851
8852 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8853 w, win, MARK, mark, s, sin);
8854 while (!embedg_VES_is_ver_ext_active(embed_graph, n, v, *s))
8855 {
8856 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8857 *s, *sin, MARK, mark, s, sin);
8858 }
8859 ASSERT(embedg_VES_is_ver_ext_active(embed_graph, n, v, *s));
8860 }
8861
8862 void
embedg_VES_get_succ_pertinent_on_ext_face(t_ver_edge * embed_graph,int n,int v,int w,int win,boolean MARK,int mark,int * s,int * sin)8863 embedg_VES_get_succ_pertinent_on_ext_face (t_ver_edge *embed_graph, int n,
8864 int v, int w, int win, boolean MARK, int mark, int *s, int *sin)
8865 /*
8866 find the pertinent (wrt v) successor s of w (entered via win)
8867 on the external face
8868 -- also return the direction in which s has been entered
8869
8870 if MARK true mark the succ. vertex (and the edge)
8871 with mark (the visited field)
8872 */
8873 {
8874 ASSERT(embedg_VES_is_vertex(n, w)
8875 || embedg_VES_is_virtual_vertex(n, w));
8876
8877 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8878 w, win, MARK, mark, s, sin);
8879 while (!embedg_VES_is_ver_pertinent(embed_graph, n, v, *s))
8880 {
8881 embedg_VES_get_succ_on_ext_face(embed_graph, n,
8882 *s, *sin, MARK, mark, s, sin);
8883 }
8884 ASSERT(embedg_VES_is_ver_pertinent(embed_graph, n, v, *s));
8885 }
8886
8887 /*
8888 * mark_kur.c
8889 */
8890
8891 /*
8892 What:
8893 *****
8894
8895 Implementing:
8896
8897 Marking the Kuratowski obstruction (in the VES structure):
8898 this we do once we know which minor we are talking about
8899 (see isolator.c).
8900
8901
8902 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8903 from
8904
8905 Simplified O(n) Planarity Algorithms (draft)
8906 ************************************
8907
8908 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
8909 Wendy Myrvold wendym@csr.uvic.ca
8910
8911
8912 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
8913 authors:
8914 ********
8915
8916 Paulette Lieby (Magma), Brendan McKay (ANU)
8917
8918 Started October 2001
8919 */
8920
8921
8922 #include "planarity.h"
8923
8924 #define IF_DEB(x) {}
8925 #define IF_VERB(x) {}
8926 #define IF_DEB_TREE(x) {}
8927 #define IF_DEB_EDGES(x) {}
8928 #define IF_CPU(x) {}
8929
8930
8931
8932 /* aproto: header embed_graph_protos.h */
8933
8934 /* aproto: beginstatic -- don't touch this!! */
8935 static void embedg_VES_walk_mark_part_ext_face (t_ver_edge *, int, int, int, int, int, int);
8936 static void embedg_VES_walk_mark_ext_face (t_ver_edge *, int, int, int);
8937 static void embedg_VES_walk_mark_part_proper_face (t_ver_edge *, int, int, int, int, int);
8938 static boolean embedg_VES_is_part_ext_face_marked (t_ver_edge *, int, int, int, int, int, int);
8939 static void embedg_get_u_x (t_ver_edge *, int, int, int, int *);
8940 static int embedg_get_least_neigh (t_dlcl **, t_dlcl **, int, int, int);
8941 static void embedg_add_mark_u_x (t_dlcl **, t_dlcl **, t_ver_edge *, int, int *, int, int, int *, int);
8942 static void embedg_mark_tree_path (t_ver_edge *, int, int, int, int);
8943 static void embedg_add_mark_v_w (t_dlcl **, t_dlcl **, t_ver_edge *, int, int *, int, int, int);
8944 static void embedg_add_mark_v_w_for_B (t_dlcl **, t_dlcl **, t_ver_edge *, int, int *, int, int, int *, int);
8945 static void embedg_mark_x_y_path (t_ver_edge *, int, int *, int *, int, int);
8946 /* aproto: endstatic -- don't touch this!! */
8947
8948 #ifndef PLANAR_IN_MAGMA
8949 #endif
8950
8951
8952
8953 static void
embedg_VES_walk_mark_part_ext_face(t_ver_edge * embed_graph,int n,int v,int vin,int from,int to,int mark)8954 embedg_VES_walk_mark_part_ext_face (t_ver_edge *embed_graph, int n,
8955 int v, int vin, int from, int to, int mark)
8956 /*
8957 walk & mark the external face:
8958 walk in the direction vin -> v -> vout and mark <from> <to>
8959 */
8960 {
8961 int cur, curin, next, nextin;
8962
8963 embed_graph[from].visited = mark;
8964 embed_graph[to].visited = mark;
8965
8966 IF_DEB(
8967 fprintf(stdout, "part. ext face marked\t");
8968 fprintf(stdout, "%d\t", from);
8969 )
8970
8971 next = cur = v;
8972 curin = vin;
8973 while (next != from)
8974 {
8975 embedg_VES_get_succ_on_ext_face(embed_graph, n, cur, curin,
8976 FALSE, 0, &next, &nextin);
8977 cur = next;
8978 curin = nextin;
8979 }
8980 next = n;
8981 while (next != to)
8982 {
8983 embedg_VES_get_succ_on_ext_face(embed_graph, n, cur, curin,
8984 TRUE, mark, &next, &nextin);
8985 cur = next;
8986 curin = nextin;
8987
8988 IF_DEB(
8989 fprintf(stdout, "%d\t", next);
8990 )
8991 }
8992 IF_DEB(
8993 fprintf(stdout, "\n");
8994 )
8995 }
8996
8997 static void
embedg_VES_walk_mark_ext_face(t_ver_edge * embed_graph,int n,int v,int mark)8998 embedg_VES_walk_mark_ext_face (t_ver_edge *embed_graph, int n, int v, int mark)
8999 /*
9000 walk & mark the external face, starting & ending at vertex v
9001 */
9002 {
9003 embedg_VES_walk_mark_part_ext_face(embed_graph, n, v, 0, v, v,
9004 mark);
9005 }
9006
9007
9008
9009 static void
embedg_VES_walk_mark_part_proper_face(t_ver_edge * embed_graph,int n,int from_e,int from_ein,int to,int mark)9010 embedg_VES_walk_mark_part_proper_face (t_ver_edge *embed_graph, int n,
9011 int from_e, int from_ein, int to, int mark)
9012 /*
9013 walk & mark a proper face starting at EDGE from_e and ending
9014 at VERTEX to
9015
9016 walk in the direction from_ein -> from_e -> to and mark
9017 everything in between
9018 */
9019 {
9020 int s, cur_e, cur_ein, next_e, next_ein;
9021
9022 next_e = s = n; /* this is an invalid value for an edge/vertex */
9023
9024 cur_e = from_e;
9025 cur_ein = from_ein;
9026 while (s != to)
9027 {
9028 ASSERT(embedg_VES_is_edge(n, cur_e));
9029 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph,
9030 n, cur_e));
9031
9032 embedg_VES_get_succ_on_proper_face(embed_graph, n,
9033 cur_e, cur_ein,
9034 TRUE, mark,
9035 &s, &next_e, &next_ein);
9036 cur_e = next_e;
9037 cur_ein = next_ein;
9038 }
9039 }
9040
9041
9042
9043 static boolean
embedg_VES_is_part_ext_face_marked(t_ver_edge * embed_graph,int n,int v,int vin,int from,int to,int mark)9044 embedg_VES_is_part_ext_face_marked (t_ver_edge *embed_graph, int n, int v,
9045 int vin, int from, int to, int mark)
9046 /*
9047 simple check to see if all the vertices on the external
9048 face walk starting at vin -> v -> vout <from> <to> are marked
9049 (with mark)
9050 */
9051 {
9052 int cur, curin, next, nextin;
9053
9054 if (embed_graph[from].visited != mark || embed_graph[to].visited != mark)
9055 return FALSE;
9056
9057 cur = v;
9058 curin = vin;
9059 next = n;
9060 while (next != from)
9061 {
9062 embedg_VES_get_succ_on_ext_face(embed_graph, n, cur, curin,
9063 FALSE, 0, &next, &nextin);
9064 cur = next;
9065 curin = nextin;
9066 }
9067 while (next != to)
9068 {
9069 embedg_VES_get_succ_on_ext_face(embed_graph, n, cur, curin,
9070 FALSE, 0, &next, &nextin);
9071 if (embed_graph[next].visited != mark)
9072 return FALSE;
9073
9074 cur = next;
9075 curin = nextin;
9076 }
9077
9078 return TRUE;
9079 }
9080
9081
9082 boolean
embedg_VES_is_ext_face_marked(t_ver_edge * embed_graph,int n,int v,int mark)9083 embedg_VES_is_ext_face_marked (t_ver_edge *embed_graph, int n, int v, int mark)
9084 /*
9085 simple check to see if all the vertices on the external
9086 face walk starting/ending at v are marked (with mark)
9087 */
9088 {
9089 return embedg_VES_is_part_ext_face_marked(embed_graph, n, v, 0,
9090 v, v, mark);
9091 }
9092
9093
9094 static void
embedg_get_u_x(t_ver_edge * embed_graph,int n,int v,int x,int * u_x)9095 embedg_get_u_x (t_ver_edge *embed_graph, int n, int v, int x, int *u_x)
9096 /*
9097 x is an externally active vertex (wrt v):
9098 we want u_x, the lowest point of "attachement" for
9099 the unembedded directed edge [x, u_x]
9100 */
9101 {
9102 int c;
9103 t_dlcl *child_list;
9104
9105 ASSERT(embedg_VES_is_ver_ext_active(embed_graph, n, v, x));
9106 if (embed_graph[x].least_ancestor < v)
9107 /*
9108 then there is a single unembedded back edge (u_x, x),
9109 u_x an ancestor of v
9110 */
9111 {
9112 *u_x = embed_graph[x].least_ancestor;
9113 return;
9114 }
9115
9116 /*
9117 else there is a tree path x to d_x and an
9118 unembedded back edge (u_x, d_x)
9119
9120 get the lowpoint of the first elt. in separated_DFS_child_list of x
9121 */
9122 child_list = embed_graph[x].separated_DFS_child_list;
9123 ASSERT(!embedg_dlcl_is_empty(child_list));
9124 c = child_list->info;
9125 *u_x = embed_graph[c].lowpoint;
9126 }
9127
9128 static int
embedg_get_least_neigh(t_dlcl ** dfs_tree,t_dlcl ** back_edges,int n,int v,int c)9129 embedg_get_least_neigh (t_dlcl **dfs_tree, t_dlcl **back_edges,
9130 int n, int v, int c)
9131 /*
9132 get the least neighbour of v >= c, ie a vertex in the sub tree
9133 rooted by c
9134
9135 somehow this must always succeed
9136 */
9137 {
9138 int least_n;
9139 t_dlcl *tree_l, *back_l, *p;
9140
9141 /*
9142 neighbours are found in either dfs_tree[v] or back_edges[v]
9143 */
9144
9145 tree_l = dfs_tree[v];
9146 back_l = back_edges[v];
9147 ASSERT(!embedg_dlcl_is_empty(tree_l) || !embedg_dlcl_is_empty(back_l));
9148
9149 least_n = n; /* ok, invalid value for any neighbour */
9150 p = tree_l;
9151 if (!embedg_dlcl_is_empty(p))
9152 {
9153 if (p->info >= c)
9154 {
9155 least_n = p->info < least_n ? p->info : least_n;
9156 }
9157 p = embedg_dlcl_list_next(p);
9158 while (p != tree_l)
9159 {
9160 if (p->info >= c)
9161 {
9162 least_n = p->info < least_n ? p->info : least_n;
9163 }
9164 p = embedg_dlcl_list_next(p);
9165 }
9166 }
9167 p = back_l;
9168 if (!embedg_dlcl_is_empty(p))
9169 {
9170 if (p->info >= c)
9171 {
9172 least_n = p->info < least_n ? p->info : least_n;
9173 }
9174 p = embedg_dlcl_list_next(p);
9175 while (p != back_l)
9176 {
9177 if (p->info >= c)
9178 {
9179 least_n = p->info < least_n ? p->info : least_n;
9180 }
9181 p = embedg_dlcl_list_next(p);
9182 }
9183 }
9184
9185 ASSERT(least_n >= c);
9186 /*
9187 this is so because of the context where this function is called from
9188 */
9189 return least_n;
9190 }
9191
9192 static void
embedg_add_mark_u_x(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int x,int * u_x,int mark)9193 embedg_add_mark_u_x (t_dlcl **dfs_tree, t_dlcl **back_edges,
9194 t_ver_edge *embed_graph, int n, int *edge_pos, int v,
9195 int x, int *u_x, int mark)
9196 /*
9197 marking a Kuratowski homeomorph:
9198
9199 marking and adding the unembedded dotted edge (u, x),
9200 x an ext. active vertex wrt v
9201 */
9202 {
9203 int c, d_x;
9204 t_dlcl *child_list;
9205
9206 ASSERT(embedg_VES_is_ver_ext_active(embed_graph, n, v, x));
9207 if (embed_graph[x].least_ancestor < v)
9208 /*
9209 then there is a single unembedded back edge (u_x, x),
9210 u_x an ancestor of v
9211 */
9212 {
9213 *u_x = embed_graph[x].least_ancestor;
9214 embed_graph[x].visited = mark;
9215 embed_graph[*u_x].visited = mark;
9216 embedg_VES_add_edge(embed_graph, n, edge_pos, *u_x, x,
9217 TRUE, mark);
9218 return;
9219 }
9220
9221 /*
9222 else there is a tree path x to d_x and an
9223 unembedded back edge (u_x, d_x)
9224
9225 get the lowpoint of the first elt. in separated_DFS_child_list of x
9226 */
9227 child_list = embed_graph[x].separated_DFS_child_list;
9228 ASSERT(!embedg_dlcl_is_empty(child_list));
9229 c = child_list->info;
9230 *u_x = embed_graph[c].lowpoint;
9231
9232 /*
9233 search for the least neighbour of *u_x >= c,
9234 that is in the subtree rooted by c
9235 */
9236 d_x = embedg_get_least_neigh(dfs_tree, back_edges, n, *u_x, c);
9237 ASSERT(d_x >= c);
9238 /*
9239 this must be true since u_x is incident to a descendant of x
9240 (remember: x is externally active)
9241 */
9242
9243 /*
9244 mark the DFS tree path from d_x to x
9245 */
9246 embedg_mark_tree_path(embed_graph, n, d_x, x, mark);
9247 /*
9248 add the unembedded (u_x, d_x) edge
9249 */
9250 embedg_VES_add_edge(embed_graph, n, edge_pos, *u_x, d_x,
9251 TRUE, mark);
9252 }
9253
9254 static void
embedg_mark_tree_path(t_ver_edge * embed_graph,int n,int d_x,int x,int mark)9255 embedg_mark_tree_path (t_ver_edge *embed_graph, int n, int d_x, int x, int mark)
9256 /*
9257 marking the DFS tree path d_x...x where x is an ancestor of d_x
9258 */
9259 {
9260 int cur_v, te, twe;
9261
9262 ASSERT(d_x >= x);
9263
9264 cur_v = d_x;
9265
9266 while (cur_v != x)
9267 {
9268 embed_graph[cur_v].visited = mark;
9269 te = embed_graph[cur_v].link[0];
9270 ASSERT(embedg_VES_is_edge(n, te));
9271 while (!embedg_VES_is_tree_edge(embed_graph, n, te)
9272 || (embed_graph[te].neighbour > cur_v
9273 && embed_graph[te].neighbour != cur_v + n))
9274 /*
9275 want to find a tree edge incident to an ancestor of d_x:
9276 given that d_x..x is a tree path, we MUST find such an edge!
9277
9278 note also that I must take account of the fact that
9279 [te].neighbour could be a virtual vertex, in which case
9280 it can only be cur_v + n!
9281 */
9282 {
9283 te = embed_graph[te].link[0];
9284 }
9285 ASSERT(embedg_VES_is_tree_edge(embed_graph, n, te));
9286 ASSERT(embed_graph[te].neighbour == embed_graph[cur_v].DFS_parent
9287 || embed_graph[te].neighbour == cur_v + n);
9288
9289 embed_graph[te].visited = mark;
9290 twe = embedg_VES_get_twin_edge(embed_graph, n, te);
9291 embed_graph[twe].visited = mark;
9292
9293 /*
9294 want only to deal with real vertices instead of virtual vertices
9295 */
9296 cur_v = embed_graph[te].neighbour < cur_v ?
9297 embed_graph[te].neighbour : embed_graph[cur_v].DFS_parent;
9298 }
9299 embed_graph[x].visited = MARK_MINORS(n);
9300 }
9301
9302
9303 static void
embedg_add_mark_v_w(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int w,int mark)9304 embedg_add_mark_v_w (t_dlcl **dfs_tree, t_dlcl **back_edges,
9305 t_ver_edge *embed_graph, int n, int *edge_pos, int v, int w, int mark)
9306 /*
9307 marking a Kuratowski homeomorph:
9308
9309 marking and adding the unembedded dotted edge (v, w),
9310 w is pertinent wrt v
9311 */
9312 {
9313 int vw, c, d_w;
9314 t_dlcl *bicomp_list;
9315
9316 if (embed_graph[w].adjacent_to == v)
9317 /*
9318 then there is a single unembedded back edge (v, w)
9319 w an ancestor of w
9320 */
9321 {
9322 embed_graph[v].visited = mark;
9323 embed_graph[w].visited = mark;
9324 embedg_VES_add_edge(embed_graph, n, edge_pos, v, w,
9325 TRUE, mark);
9326 return;
9327 }
9328
9329 /*
9330 else there is a tree path w to d_w and an
9331 unembedded back edge (v, d_w)
9332
9333 get the last elt in w's bicomp list
9334 */
9335 bicomp_list = embed_graph[w].pertinent_bicomp_list;
9336 ASSERT(!embedg_dlcl_is_empty(bicomp_list));
9337 vw = (embedg_dlcl_list_last(bicomp_list))->info;
9338 c = vw - n;
9339
9340 /*
9341 search for the least neighbour of v >= c,
9342 that is in the subtree rooted by c
9343 */
9344 d_w = embedg_get_least_neigh(dfs_tree, back_edges, n, v, c);
9345 ASSERT(d_w >= c);
9346 /*
9347 this must be true since v is incident to a descendant of w
9348 (remember: w is pertinent)
9349 */
9350
9351 /*
9352 mark the DFS tree path from d_w to w
9353 */
9354 embedg_mark_tree_path(embed_graph, n, d_w, w, mark);
9355 /*
9356 add the unembedded (d_w, v) edge
9357 */
9358 embedg_VES_add_edge(embed_graph, n, edge_pos, d_w, v,
9359 TRUE, mark);
9360 }
9361
9362
9363 static void
embedg_add_mark_v_w_for_B(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int w,int * u_z,int mark)9364 embedg_add_mark_v_w_for_B (t_dlcl **dfs_tree, t_dlcl **back_edges,
9365 t_ver_edge *embed_graph, int n, int *edge_pos, int v, int w,
9366 int *u_z, int mark)
9367 /*
9368 marking a Kuratowski homeomorph:
9369
9370 marking and adding the unembedded dotted edge (v, w) for minor B:
9371 w is pertinent wrt v
9372 */
9373 {
9374 int vz, z, d_z, d_w;
9375 t_dlcl *bicomp_list;
9376
9377 /*
9378 get the last elt in w's bicomp list
9379 */
9380 bicomp_list = embed_graph[w].pertinent_bicomp_list;
9381 ASSERT(!embedg_dlcl_is_empty(bicomp_list));
9382 vz = (embedg_dlcl_list_last(bicomp_list))->info;
9383 z = vz - n;
9384
9385 /*
9386 get the lowpoint of z
9387 */
9388 *u_z = embed_graph[z].lowpoint;
9389
9390 /*
9391 search for the least neighbour of *u_z >= z,
9392 that is in the subtree rooted by c
9393 */
9394 d_z = embedg_get_least_neigh(dfs_tree, back_edges, n, *u_z, z);
9395 ASSERT(d_z >= z);
9396 /*
9397 this must be true since u_z is incident to z or a descendant of z
9398 */
9399
9400 /*
9401 now do the same for neighbours of v
9402 */
9403 d_w = embedg_get_least_neigh(dfs_tree, back_edges, n, v, z);
9404 ASSERT(d_w >= z);
9405 /*
9406 this must be true since v is incident to a descendant of w
9407 (remember: w is pertinent)
9408 */
9409
9410 /*
9411 mark the DFS tree path from d_w to w
9412 */
9413 embedg_mark_tree_path(embed_graph, n, d_w, w, mark);
9414 /*
9415 mark the DFS tree path from d_z to z
9416 */
9417 embedg_mark_tree_path(embed_graph, n, d_z, z, mark);
9418 /*
9419 add & mark the edges (u_z, d_z), (v, d_w)
9420 */
9421 embedg_VES_add_edge(embed_graph, n, edge_pos, *u_z, d_z,
9422 TRUE, mark);
9423 embedg_VES_add_edge(embed_graph, n, edge_pos, v, d_w,
9424 TRUE, mark);
9425 }
9426
9427 static void
embedg_mark_x_y_path(t_ver_edge * embed_graph,int n,int * path_v,int * path_e,int nbr_v,int mark)9428 embedg_mark_x_y_path (t_ver_edge *embed_graph, int n, int *path_v,
9429 int *path_e, int nbr_v, int mark)
9430 {
9431 int i;
9432
9433 /*
9434 have a look at embedg_iso_get_highest_x_y_path
9435 to see that path_e[0] is a dummy
9436
9437 (note: path_v and path_e contain nbr_v + 1 elts!)
9438 */
9439 embed_graph[path_v[0]].visited = mark;
9440 for (i = 1; i <= nbr_v; i++)
9441 {
9442 int e, twin;
9443
9444 embed_graph[path_v[i]].visited = mark;
9445 e = path_e[i];
9446 twin = embedg_VES_get_twin_edge(embed_graph, n, e);
9447 embed_graph[e].visited =
9448 embed_graph[twin].visited = mark;
9449 }
9450 }
9451
9452 void
embedg_mark_minor_A(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int vr)9453 embedg_mark_minor_A (t_dlcl **dfs_tree, t_dlcl **back_edges,
9454 t_ver_edge *embed_graph, int n, int *edge_pos, int v, int c, int vr)
9455 {
9456 int r, r_c, x, y, w, u_x, u_y, u;
9457
9458 ASSERT(embedg_VES_is_virtual_vertex(n, vr));
9459 r_c = vr - n;
9460 r = embed_graph[r_c].DFS_parent;
9461
9462 /*
9463 find the ext. active x & y, and the pertinent w,
9464 and mark the external face of the bicomp rooted at vr
9465 */
9466 embedg_iso_get_x_y_w(embed_graph, n, v, r, r_c,
9467 MARK_MINORS(n),
9468 MARK_MINORS(n), MARK_MINORS(n), &x, &y, &w);
9469
9470 /*
9471 mark the edges (u, x), (u, y), (v, w)
9472 */
9473 embedg_add_mark_u_x(dfs_tree, back_edges,
9474 embed_graph, n, edge_pos, v, x, &u_x,
9475 MARK_MINORS(n));
9476 embedg_add_mark_u_x(dfs_tree, back_edges,
9477 embed_graph, n, edge_pos, v, y, &u_y,
9478 MARK_MINORS(n));
9479 embedg_add_mark_v_w(dfs_tree, back_edges,
9480 embed_graph, n, edge_pos, v, w,
9481 MARK_MINORS(n));
9482
9483 /*
9484 mark the tree path from r to min(u_x, u_y)
9485 */
9486 u = u_x <= u_y ? u_x : u_y;
9487 embedg_mark_tree_path(embed_graph, n, r, u, MARK_MINORS(n));
9488
9489 IF_DEB(
9490 fprintf(stdout, "mark minor A\n");
9491 fprintf(stdout, "v %d\t c %d\t r %d\t r_c %d\t x %d\t y %d\t w %d\t u_x %d\t u_y %d\n",
9492 v, c, r, r_c, x, y, w, u_x, u_y);
9493 )
9494 }
9495
9496 void
embedg_mark_minor_B(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int x,int y,int w)9497 embedg_mark_minor_B (t_dlcl **dfs_tree, t_dlcl **back_edges,
9498 t_ver_edge *embed_graph, int n, int *edge_pos, int v,
9499 int c, int x, int y, int w)
9500 {
9501 int vv, u_x, u_y, vz, u_z, u_max, u_min;
9502
9503 vv = c + n;
9504
9505 /*
9506 mark the external face of the bicomp rooted by v^c
9507 */
9508 embedg_VES_walk_mark_ext_face(embed_graph, n, vv, MARK_MINORS(n));
9509 ASSERT(embedg_VES_is_ext_face_marked(embed_graph, n, vv,
9510 MARK_MINORS(n)));
9511
9512 /*
9513 mark the edges (u, x), (u, y)
9514 */
9515 embedg_add_mark_u_x(dfs_tree, back_edges,
9516 embed_graph, n, edge_pos, v, x, &u_x,
9517 MARK_MINORS(n));
9518 embedg_add_mark_u_x(dfs_tree, back_edges,
9519 embed_graph, n, edge_pos, v, y, &u_y,
9520 MARK_MINORS(n));
9521
9522 /*
9523 mark the dotted edges (v, w), (v, u)
9524 */
9525 embedg_add_mark_v_w_for_B(dfs_tree, back_edges,
9526 embed_graph, n, edge_pos, v, w,
9527 &u_z, MARK_MINORS(n));
9528
9529 /*
9530 mark the tree path from max(u_x, u_y, u_z) to min(u_x, u_y, u_z)
9531 */
9532 u_max = u_x > u_y ? u_x : u_y;
9533 u_max = u_max > u_z ? u_max : u_z;
9534 u_min = u_x < u_y ? u_x : u_y;
9535 u_min = u_min < u_z ? u_min : u_z;
9536 embedg_mark_tree_path(embed_graph, n, u_max, u_min, MARK_MINORS(n));
9537
9538 IF_DEB(
9539 fprintf(stdout, "mark minor B\n");
9540 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t u_x %d\t u_y %d\t u_z %d\n",
9541 v, c, x, y, w, u_x, u_y, u_z);
9542 )
9543 }
9544
9545 void
embedg_mark_minor_C(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int x,int y,int w,int * path_v,int * path_e,int nbr_v,boolean px_attached_high,boolean py_attached_high)9546 embedg_mark_minor_C (t_dlcl **dfs_tree, t_dlcl **back_edges,
9547 t_ver_edge *embed_graph, int n, int *edge_pos, int v,
9548 int c, int x, int y, int w, int *path_v, int *path_e,
9549 int nbr_v, boolean px_attached_high, boolean py_attached_high)
9550 {
9551 int vv, p_x, p_y, u_x, u_y, u;
9552
9553 vv = c + n;
9554 p_x = path_v[0];
9555 p_y = path_v[nbr_v];
9556 /*
9557 see embedg_iso_get_highest_x_y_path for the above
9558 */
9559
9560 if (px_attached_high)
9561 /*
9562 mark the external face:
9563 - from v^c to p_y if py_attached_high
9564 - from v^c to y if !py_attached_high
9565
9566 not too sure about that one....
9567
9568 from v^c to p_y: so vvin = 0,
9569 in x's direction
9570 */
9571 {
9572 if (py_attached_high)
9573 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9574 vv, p_y, MARK_MINORS(n));
9575 else
9576 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9577 vv, y, MARK_MINORS(n));
9578 }
9579 else
9580 /*
9581 symmetric case:
9582 mark the external face from v^c to p_x: so vvin = 1,
9583 in y's direction
9584 */
9585 {
9586 if (px_attached_high)
9587 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9588 vv, p_x, MARK_MINORS(n));
9589 else
9590 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9591 vv, x, MARK_MINORS(n));
9592 }
9593
9594 /*
9595 mark the edges (u, x), (u, y), (v, w)
9596 */
9597 embedg_add_mark_u_x(dfs_tree, back_edges,
9598 embed_graph, n, edge_pos, v, x, &u_x,
9599 MARK_MINORS(n));
9600 embedg_add_mark_u_x(dfs_tree, back_edges,
9601 embed_graph, n, edge_pos, v, y, &u_y,
9602 MARK_MINORS(n));
9603 embedg_add_mark_v_w(dfs_tree, back_edges,
9604 embed_graph, n, edge_pos, v, w,
9605 MARK_MINORS(n));
9606
9607 /*
9608 mark the tree path from v to min(u_x, u_y)
9609 */
9610 u = u_x <= u_y ? u_x : u_y;
9611 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9612
9613 /*
9614 finally, mark the x-y path, ie the vertices in path_v
9615 and the edges in path_e
9616 */
9617 embedg_mark_x_y_path(embed_graph, n, path_v, path_e, nbr_v,
9618 MARK_MINORS(n));
9619
9620 IF_DEB(
9621 fprintf(stdout, "mark minor C p_x high %d\t p_y high %d\n",
9622 px_attached_high, py_attached_high);
9623 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\n",
9624 v, c, x, y, w, p_x, p_y, u_x, u_y);
9625 )
9626 }
9627
9628 void
embedg_mark_minor_D(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int x,int y,int w,int * path_v,int * path_e,int nbr_v,int entry_in_path_e)9629 embedg_mark_minor_D (t_dlcl **dfs_tree, t_dlcl **back_edges,
9630 t_ver_edge *embed_graph, int n, int *edge_pos, int v,
9631 int c, int x, int y, int w, int *path_v, int *path_e,
9632 int nbr_v, int entry_in_path_e)
9633 {
9634 int i, vv, p_x, p_y, u_x, u_y, u;
9635
9636 vv = c + n;
9637 p_x = path_v[0];
9638 p_y = path_v[nbr_v];
9639 /*
9640 see embedg_iso_get_highest_x_y_path for the above
9641 */
9642
9643 /*
9644 mark the lower external face from x to y: we can walk in
9645 either direction
9646 */
9647 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9648 x, y, MARK_MINORS(n));
9649
9650 /*
9651 mark the internal path which goes from the x-y path to v
9652 - since I haven't stored those vertices/edges I assume
9653 that a proper face walk should suffice
9654
9655 BUT a walk that say starts at p_x and ends at vv,
9656 that is, a walk starting at path_e[1] entered from entry_in_path_e
9657 (recall that path_e[0] is a dummy)
9658 */
9659 embedg_VES_walk_mark_part_proper_face(embed_graph, n,
9660 path_e[1], entry_in_path_e,
9661 vv, MARK_MINORS(n));
9662
9663 /*
9664 a note of caution here:
9665 ALWAYS mark external/internal faces before adding any other edges:
9666 since adding edges destroys the faces' consistency
9667 (adding edges makes no sense of face since we are in a non-planar
9668 situation)
9669 */
9670 /*
9671 mark the edges (u, x), (u, y), (v, w)
9672 */
9673 embedg_add_mark_u_x(dfs_tree, back_edges,
9674 embed_graph, n, edge_pos, v, x, &u_x,
9675 MARK_MINORS(n));
9676 embedg_add_mark_u_x(dfs_tree, back_edges,
9677 embed_graph, n, edge_pos, v, y, &u_y,
9678 MARK_MINORS(n));
9679 embedg_add_mark_v_w(dfs_tree, back_edges,
9680 embed_graph, n, edge_pos, v, w,
9681 MARK_MINORS(n));
9682
9683 /*
9684 mark the tree path from v to min(u_x, u_y)
9685 */
9686 u = u_x <= u_y ? u_x : u_y;
9687 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9688
9689 /*
9690 mark the x-y path, ie the vertices in path_v
9691 and the edges in path_e
9692 */
9693 embedg_mark_x_y_path(embed_graph, n, path_v, path_e, nbr_v,
9694 MARK_MINORS(n));
9695
9696 IF_DEB(
9697 fprintf(stdout, "mark minor D\n");
9698 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\n",
9699 v, c, x, y, w, p_x, p_y, u_x, u_y);
9700 )
9701 }
9702
9703
9704
9705
9706 minor
embedg_mark_minor_E(t_dlcl ** dfs_tree,t_dlcl ** back_edges,t_ver_edge * embed_graph,int n,int * edge_pos,int v,int c,int x,int y,int w,int * path_v,int * path_e,int nbr_v)9707 embedg_mark_minor_E (t_dlcl **dfs_tree, t_dlcl **back_edges,
9708 t_ver_edge *embed_graph, int n, int *edge_pos, int v,
9709 int c, int x, int y, int w, int *path_v, int *path_e, int nbr_v)
9710 /*
9711 while marking minor E return which of the minors we are dealing with
9712 */
9713 {
9714 int vv, p_x, p_y, u_x, u_y, u_w, u, u_max, u_min;
9715
9716 vv = c + n;
9717 p_x = path_v[0];
9718 p_y = path_v[nbr_v];
9719 /*
9720 see embedg_iso_get_highest_x_y_path for the above
9721 */
9722
9723 if (!embedg_VES_is_ver_ext_active(embed_graph, n, v, w))
9724 /*
9725 minor E1 case: we must find an ext. active z, distinct from w,
9726 on the external face p_x..w..p_y
9727 */
9728 {
9729 int s, sin, cur, curin, z, u_z, u_xy;
9730
9731 s = n;
9732 /*
9733 start searching at vv entered from 0 (in x's direction)
9734 -- we MUST reach p_x - hopefully! :)
9735 */
9736 cur = vv;
9737 curin = 0;
9738 while (s != p_x)
9739 /*
9740 first advance to p_x: we are sure of reaching it
9741 */
9742 {
9743 embedg_VES_get_succ_on_ext_face(embed_graph, n,
9744 cur, curin,
9745 FALSE, 0, &s, &sin);
9746 cur = s;
9747 curin = sin;
9748 }
9749
9750 /*
9751 continue the walk on the external face:
9752 stop if either s is ext. active OR s == w
9753
9754 we'll mark the lot later on
9755 */
9756 while (
9757 !(embedg_VES_is_ver_ext_active(embed_graph, n, v,
9758 s)
9759 && s != p_x)
9760 && s != w)
9761 {
9762 embedg_VES_get_succ_on_ext_face(embed_graph, n, cur, curin,
9763 FALSE, 0, &s, &sin);
9764 cur = s;
9765 curin = sin;
9766 }
9767 /*
9768 now we must decide which symmetry we are in
9769 */
9770 if (embedg_VES_is_ver_ext_active(embed_graph, n, v, s))
9771 /*
9772 z is between x and w (recall that w is NOT ext. active)
9773 */
9774 {
9775 z = s;
9776 ASSERT(z != w);
9777
9778 /*
9779 mark the external face from v^c to y in x's direction
9780 */
9781 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9782 vv, y, MARK_MINORS(n));
9783 /*
9784 add/mark dotted edge (u, y)
9785 */
9786 embedg_add_mark_u_x(dfs_tree, back_edges,
9787 embed_graph, n, edge_pos,
9788 v, y, &u_xy, MARK_MINORS(n));
9789 }
9790 else
9791 /*
9792 this is the symmetric case: must find z between w and p_y
9793 */
9794 {
9795 ASSERT(s == w);
9796 embedg_VES_get_succ_ext_active_on_ext_face(embed_graph, n,
9797 v, cur, curin,
9798 FALSE, 0,
9799 &s, &sin);
9800 /*
9801 and z is distinct from p_y!
9802 */
9803 z = s;
9804 ASSERT(z != p_y);
9805
9806 /*
9807 mark the external face from v^c to x in y's direction
9808 */
9809 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9810 vv, x, MARK_MINORS(n));
9811 /*
9812 add/mark dotted edge (u, x)
9813 */
9814 embedg_add_mark_u_x(dfs_tree, back_edges,
9815 embed_graph, n, edge_pos,
9816 v, x, &u_xy, MARK_MINORS(n));
9817 }
9818 /*
9819 now the marked bits which are common to both cases:
9820 dotted edges (u, z), (v, w), the x-y path,
9821 the tree path (v, min(u_xy, u_z))
9822 */
9823 embedg_add_mark_u_x(dfs_tree, back_edges,
9824 embed_graph, n, edge_pos,
9825 v, z, &u_z, MARK_MINORS(n));
9826 embedg_add_mark_v_w(dfs_tree, back_edges,
9827 embed_graph, n, edge_pos, v, w,
9828 MARK_MINORS(n));
9829
9830 embedg_mark_x_y_path(embed_graph, n, path_v, path_e, nbr_v,
9831 MARK_MINORS(n));
9832
9833 u = u_z <= u_xy ? u_z : u_xy;
9834 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9835
9836 IF_DEB(
9837 fprintf(stdout, "mark minor E1\n");
9838 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t z %d\t w %d\t p_x %d\t p_y %d\t u_xy %d\t u_z %d\n",
9839 v, c, x, y, z, w, p_x, p_y, u_xy, u_z);
9840 )
9841
9842 return MINOR_E1;
9843 }
9844
9845 /*
9846 in all other cases we get u_x, u_y, u_w back
9847 from the ext. active vertices x, y, w resp.
9848
9849 again, I CANNOT embed these edges now since that would destroy
9850 my external/internal faces
9851 */
9852
9853 embedg_get_u_x(embed_graph, n, v, x, &u_x);
9854 embedg_get_u_x(embed_graph, n, v, y, &u_y);
9855 embedg_get_u_x(embed_graph, n, v, w, &u_w);
9856
9857 if (u_w > u_x && u_w > u_y)
9858 /*
9859 minor E2 case:
9860 we mark the whole external face rooted by v^c
9861 and the tree path (v, min(u_x, u_y))
9862 */
9863 {
9864 embedg_VES_walk_mark_ext_face(embed_graph, n, vv,
9865 MARK_MINORS(n));
9866 u = u_x <= u_y ? u_x : u_y;
9867 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9868
9869 /*
9870 embed dotted edges (u, x), (u, y) & (u, w)
9871 */
9872 embedg_add_mark_u_x(dfs_tree, back_edges,
9873 embed_graph, n, edge_pos,
9874 v, x, &u_x, MARK_MINORS(n));
9875 embedg_add_mark_u_x(dfs_tree, back_edges,
9876 embed_graph, n, edge_pos,
9877 v, y, &u_y, MARK_MINORS(n));
9878 embedg_add_mark_u_x(dfs_tree, back_edges,
9879 embed_graph, n, edge_pos,
9880 v, w, &u_w, MARK_MINORS(n));
9881
9882 IF_DEB(
9883 fprintf(stdout, "mark minor E2\n");
9884 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
9885 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
9886 )
9887
9888 return MINOR_E2;
9889 }
9890
9891 /*
9892 two more things common to all remaining cases:
9893
9894 mark the dotted edge (v, w) (but we MUST do that later)
9895
9896 mark the x-y path
9897 */
9898 embedg_mark_x_y_path(embed_graph, n, path_v, path_e, nbr_v,
9899 MARK_MINORS(n));
9900
9901 if (u_x < u_y && u_w < u_y)
9902 /*
9903 minor E3 case: one of the symmetric cases:
9904 the external face rooted at v_c from vv to x (in x's direction)
9905 the external face rooted at v_c from y to w (in y's direction)
9906 the (v, min(u_w, u_x)) tree path
9907 */
9908 {
9909 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9910 vv, p_x, MARK_MINORS(n));
9911 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9912 y, w, MARK_MINORS(n));
9913
9914 u = u_x <= u_w ? u_x : u_w;
9915 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9916
9917 /*
9918 embed dotted edges (u, x), (u, y), (u, w), (v, w)
9919 */
9920 embedg_add_mark_u_x(dfs_tree, back_edges,
9921 embed_graph, n, edge_pos,
9922 v, x, &u_x, MARK_MINORS(n));
9923 embedg_add_mark_u_x(dfs_tree, back_edges,
9924 embed_graph, n, edge_pos,
9925 v, y, &u_y, MARK_MINORS(n));
9926 embedg_add_mark_u_x(dfs_tree, back_edges,
9927 embed_graph, n, edge_pos,
9928 v, w, &u_w, MARK_MINORS(n));
9929 embedg_add_mark_v_w(dfs_tree, back_edges,
9930 embed_graph, n, edge_pos, v, w,
9931 MARK_MINORS(n));
9932
9933 IF_DEB(
9934 fprintf(stdout, "mark minor E3/a\n");
9935 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
9936 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
9937 )
9938
9939 return MINOR_E3;
9940 }
9941 if (u_y < u_x && u_w < u_x)
9942 /*
9943 minor E3 case: the other symmetric case:
9944 the external face rooted at v_c from vv to y (in y's direction)
9945 the external face rooted at v_c from x to w (in x's direction)
9946 the (v, min(u_w, u_y)) tree path
9947 */
9948 {
9949 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9950 vv, p_y, MARK_MINORS(n));
9951 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9952 x, w, MARK_MINORS(n));
9953
9954 u = u_y <= u_w ? u_y : u_w;
9955 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
9956
9957 /*
9958 embed dotted edges (u, x), (u, y), (u, w), (v, w)
9959 */
9960 embedg_add_mark_u_x(dfs_tree, back_edges,
9961 embed_graph, n, edge_pos,
9962 v, x, &u_x, MARK_MINORS(n));
9963 embedg_add_mark_u_x(dfs_tree, back_edges,
9964 embed_graph, n, edge_pos,
9965 v, y, &u_y, MARK_MINORS(n));
9966 embedg_add_mark_u_x(dfs_tree, back_edges,
9967 embed_graph, n, edge_pos,
9968 v, w, &u_w, MARK_MINORS(n));
9969 embedg_add_mark_v_w(dfs_tree, back_edges,
9970 embed_graph, n, edge_pos, v, w,
9971 MARK_MINORS(n));
9972
9973 IF_DEB(
9974 fprintf(stdout, "mark minor E3/b\n");
9975 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
9976 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
9977 )
9978
9979 return MINOR_E3;
9980 }
9981
9982 if (p_x != x)
9983 /*
9984 minor E4 case: one of the symmetric cases:
9985 the external face rooted at v_c from vv to w (in x's direction)
9986 the external face rooted at v_c from vv to p_y (in y's direction)
9987 the tree path from max(u_x, u_y, u_w) to min(u_x, u_y, u_w)
9988 */
9989 {
9990 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
9991 vv, w, MARK_MINORS(n));
9992 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
9993 vv, p_y, MARK_MINORS(n));
9994
9995 u_max = u_x > u_y ? u_x : u_y;
9996 u_max = u_max > u_w ? u_max : u_w;
9997 u_min = u_x < u_y ? u_x : u_y;
9998 u_min = u_min < u_w ? u_min : u_w;
9999 embedg_mark_tree_path(embed_graph, n, u_max, u_min, MARK_MINORS(n));
10000
10001 /*
10002 embed dotted edges (u, x), (u, y), (u, w), (v, w)
10003 */
10004 embedg_add_mark_u_x(dfs_tree, back_edges,
10005 embed_graph, n, edge_pos,
10006 v, x, &u_x, MARK_MINORS(n));
10007 embedg_add_mark_u_x(dfs_tree, back_edges,
10008 embed_graph, n, edge_pos,
10009 v, y, &u_y, MARK_MINORS(n));
10010 embedg_add_mark_u_x(dfs_tree, back_edges,
10011 embed_graph, n, edge_pos,
10012 v, w, &u_w, MARK_MINORS(n));
10013 embedg_add_mark_v_w(dfs_tree, back_edges,
10014 embed_graph, n, edge_pos, v, w,
10015 MARK_MINORS(n));
10016
10017 IF_DEB(
10018 fprintf(stdout, "mark minor E4/a\n");
10019 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
10020 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
10021 )
10022
10023 return MINOR_E4;
10024 }
10025 if (p_y != y)
10026 /*
10027 minor E4 case: the other symmetric case:
10028 the external face rooted at v_c from vv to w (in y's direction)
10029 the external face rooted at v_c from vv to x (in x's direction)
10030 (here p_x = x!)
10031 the tree path from max(u_x, u_y, u_w) to min(u_x, u_y, u_w)
10032 */
10033 {
10034 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 1,
10035 vv, w, MARK_MINORS(n));
10036 embedg_VES_walk_mark_part_ext_face(embed_graph, n, vv, 0,
10037 vv, x, MARK_MINORS(n));
10038
10039 u_max = u_x > u_y ? u_x : u_y;
10040 u_max = u_max > u_w ? u_max : u_w;
10041 u_min = u_x < u_y ? u_x : u_y;
10042 u_min = u_min < u_w ? u_min : u_w;
10043 embedg_mark_tree_path(embed_graph, n, u_max, u_min, MARK_MINORS(n));
10044
10045 /*
10046 embed dotted edges (u, x), (u, y), (u, w), (v, w)
10047 */
10048 embedg_add_mark_u_x(dfs_tree, back_edges,
10049 embed_graph, n, edge_pos,
10050 v, x, &u_x, MARK_MINORS(n));
10051 embedg_add_mark_u_x(dfs_tree, back_edges,
10052 embed_graph, n, edge_pos,
10053 v, y, &u_y, MARK_MINORS(n));
10054 embedg_add_mark_u_x(dfs_tree, back_edges,
10055 embed_graph, n, edge_pos,
10056 v, w, &u_w, MARK_MINORS(n));
10057 embedg_add_mark_v_w(dfs_tree, back_edges,
10058 embed_graph, n, edge_pos, v, w,
10059 MARK_MINORS(n));
10060
10061 IF_DEB(
10062 fprintf(stdout, "mark minor E$/b\n");
10063 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
10064 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
10065 )
10066
10067 return MINOR_E4;
10068 }
10069
10070 /*
10071 this is the last case for minor E: when the homeomorph is K5
10072
10073 mark the whole external face rooted at v^c
10074 mark the tree path from v to min(u_x, u_y, u_w)
10075 */
10076
10077 embedg_VES_walk_mark_ext_face(embed_graph, n, vv, MARK_MINORS(n));
10078
10079 u = u_x < u_y ? u_x : u_y;
10080 u = u < u_w ? u : u_w;
10081 embedg_mark_tree_path(embed_graph, n, v, u, MARK_MINORS(n));
10082
10083 /*
10084 embed dotted edges (u, x), (u, y), (u, w), (v, w)
10085 */
10086 embedg_add_mark_u_x(dfs_tree, back_edges,
10087 embed_graph, n, edge_pos,
10088 v, x, &u_x, MARK_MINORS(n));
10089 embedg_add_mark_u_x(dfs_tree, back_edges,
10090 embed_graph, n, edge_pos,
10091 v, y, &u_y, MARK_MINORS(n));
10092 embedg_add_mark_u_x(dfs_tree, back_edges,
10093 embed_graph, n, edge_pos,
10094 v, w, &u_w, MARK_MINORS(n));
10095 embedg_add_mark_v_w(dfs_tree, back_edges,
10096 embed_graph, n, edge_pos, v, w,
10097 MARK_MINORS(n));
10098
10099 IF_DEB(
10100 fprintf(stdout, "mark minor E5\n");
10101 fprintf(stdout, "v %d\t c %d\t x %d\t y %d\t w %d\t p_x %d\t p_y %d\t u_x %d\t u_y %d\t u_w %d\n",
10102 v, c, x, y, w, p_x, p_y, u_x, u_y, u_w);
10103 )
10104
10105 return MINOR_E5;
10106 }
10107 /*
10108 * proper_face_walk.c
10109 */
10110
10111 /*
10112 What:
10113 *****
10114
10115 Implementing a proper face walk within the VES structure.
10116 This is obviously not the same as an external face walk,
10117 but is simply the standard face walk in a planar embedding.
10118
10119 Not much to say, if only to emphasize that for our
10120 purposes here we assume:
10121
10122 1. the short-cut edges have been removed from the VES structure
10123 2. each vertex/edge has been given its orientation
10124 2. the adjacency lists (vertex + plus its incident edges)
10125 are consistent: (and this is IMPORTANT)
10126 that is, the way to traverse an adj. list (ie what
10127 constitute previous and next in the list which actually
10128 is a planar embedding at this stage) is indicated
10129 by the vertex/edge's orientation
10130
10131
10132 try to explain this better another time.... sorry...
10133
10134
10135
10136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
10137 from
10138
10139 Simplified O(n) Planarity Algorithms (draft)
10140 ************************************
10141
10142 John Boyer JBoyer@PureEdge.com, jboyer@acm.org
10143 Wendy Myrvold wendym@csr.uvic.ca
10144
10145
10146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
10147 authors:
10148 ********
10149
10150 Paulette Lieby (Magma), Brendan McKay (ANU)
10151
10152 Started October 2001
10153 */
10154
10155
10156 #include "planarity.h"
10157
10158 #define IF_DEB(x) {}
10159 #define IF_DEB_PROPER_FACE(x) {}
10160 #define IF_VERB(x) {}
10161
10162
10163
10164 /* aproto: header embed_graph_protos.h */
10165
10166
10167
10168
10169 boolean
embedg_VES_get_succ_on_proper_face_with_avoidance(t_ver_edge * embed_graph,int n,int e,int ein,int a,boolean MARK,int mark,int * s,int * next_e,int * next_ein)10170 embedg_VES_get_succ_on_proper_face_with_avoidance (t_ver_edge *embed_graph,
10171 int n, int e, int ein, int a, boolean MARK, int mark, int *s,
10172 int *next_e, int *next_ein)
10173 /*
10174 find the successor s of embed_graph[e].neighbour
10175 (entered via ein) on a proper face traversal
10176 which avoids (the vertex) a if a != n
10177
10178 also returns the edge next_e such that
10179 embed_graph[next_e].neighbour = s (to allow for continuation
10180 of the walk)
10181
10182 assumes that short-cut edges have been removed and that each
10183 edge/vertex has been given its orientation
10184
10185 and (more importantly) assumes that adjacency lists are consistent
10186
10187 this function has been written especially to retrieve the highest
10188 x-y path for the isolator;
10189 (see embedg_iso_get_highest_x_y_path)
10190 but as I discovered later (when marking an internal face
10191 as for minor D) this function is general purpose
10192
10193 PLUS: return true if the proper face walk has to skip an edge
10194 incident to a (ie had to "avoid" a)
10195
10196 PLUS: mark s & next_e if so requested
10197 */
10198 {
10199 int eout;
10200 int twin, twinout;
10201 boolean avoid_a;
10202
10203 ASSERT(embedg_VES_is_edge(n, e));
10204 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph, n, e));
10205
10206 IF_DEB(
10207 fprintf(stdout, "get_succ_on_proper_face, \n");
10208 )
10209
10210 avoid_a = FALSE;
10211 /*
10212 find the direction out of the edge
10213 */
10214 eout = 1 ^ ein;
10215
10216 /*
10217 get the twin edge
10218 */
10219 twin = embedg_VES_get_twin_edge(embed_graph, n, e);
10220
10221 /*
10222 for each edge we must set the way to get to the next
10223 in the adjacency list:
10224 adjacency lists are traversed according to the vertex/edges
10225 orientation (one unique orientation per list of course)
10226 */
10227 if (embed_graph[e].sign != embed_graph[twin].sign)
10228 /*
10229 invert traversal
10230 */
10231 {
10232 twinout = 1 ^ eout;
10233 }
10234 else
10235 /*
10236 traversal is identical
10237 */
10238 {
10239 twinout = eout;
10240 }
10241
10242 /*
10243 now, we want the edge previous to twin in twin's adjacency list,
10244 ie link[1 ^ twinout]
10245 */
10246 *next_e = embed_graph[twin].link[1 ^ twinout];
10247 /*
10248 next_e could be a vertex, I need an edge
10249 */
10250 if (embedg_VES_is_vertex(n, *next_e)
10251 || embedg_VES_is_virtual_vertex(n, *next_e))
10252 /*
10253 at this stage all virtual vertices should have
10254 been disabled BUT the vertices rooting the bicomps!!!
10255 */
10256 {
10257 *next_e = embed_graph[*next_e].link[1 ^ twinout];
10258 }
10259 ASSERT(embedg_VES_is_edge(n, *next_e));
10260 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph, n, e));
10261 *s = embed_graph[*next_e].neighbour;
10262
10263 if (*s == a)
10264 /*
10265 want to avoid this vertex, so must get yet previous
10266 edge in adjacency list
10267 */
10268 {
10269 avoid_a = TRUE;
10270
10271 *next_e = embed_graph[*next_e].link[1 ^ twinout];
10272 if (embedg_VES_is_vertex(n, *next_e)
10273 || embedg_VES_is_virtual_vertex(n, *next_e))
10274 {
10275 *next_e = embed_graph[*next_e].link[1 ^ twinout];
10276 }
10277 ASSERT(embedg_VES_is_edge(n, *next_e));
10278 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph, n, e));
10279 }
10280 *s = embed_graph[*next_e].neighbour;
10281 ASSERT(*s != a);
10282
10283 /*
10284 finally (again, because lists are consistent)
10285 */
10286 *next_ein = 1 ^ twinout;
10287
10288 /*
10289 now mark s and next_e if required
10290 */
10291 if (MARK)
10292 {
10293 embed_graph[*s].visited =
10294 embed_graph[*next_e].visited = mark;
10295 /*
10296 ouuh... must mark the twin as well....
10297 but ONLY when we mark the minors....
10298 that is poor design, can we do better????
10299 -- don't think so...
10300
10301 (when we mark when counting the faces, we MUST only
10302 mark the edge and NOT its twin)
10303 */
10304 if (mark == MARK_MINORS(n))
10305 {
10306 twin =
10307 embedg_VES_get_twin_edge(embed_graph, n, *next_e);
10308 embed_graph[twin].visited = mark;
10309 }
10310 }
10311
10312 return avoid_a;
10313 }
10314
10315
10316
10317 void
embedg_VES_get_succ_on_proper_face(t_ver_edge * embed_graph,int n,int e,int ein,int MARK,int mark,int * s,int * next_e,int * next_ein)10318 embedg_VES_get_succ_on_proper_face (t_ver_edge *embed_graph, int n, int e,
10319 int ein, int MARK, int mark, int *s, int *next_e, int *next_ein)
10320 /*
10321 same as above but without avoidance
10322 */
10323 {
10324 boolean avoid;
10325
10326 avoid =
10327 embedg_VES_get_succ_on_proper_face_with_avoidance(
10328 embed_graph, n,
10329 e, ein, n,
10330 MARK, mark,
10331 s, next_e, next_ein);
10332 ASSERT(avoid == FALSE);
10333 }
10334
10335
10336 void
embedg_VES_walk_proper_face(t_ver_edge * embed_graph,int n,int e,int ein,boolean MARK,int mark)10337 embedg_VES_walk_proper_face (t_ver_edge *embed_graph, int n, int e,
10338 int ein, boolean MARK, int mark)
10339 /*
10340 traversing a proper face starting at edge e which has been entered
10341 via ein
10342
10343 -- we mark the visited edges with mark if so requested
10344
10345 assumes that short-cut edges have been removed and that each
10346 edge/vertex has been given its orientation
10347 */
10348 {
10349 int s, cur_e, cur_ein, next_e, next_ein;
10350
10351 next_e = n; /* this is an invalid value for an edge */
10352
10353 IF_DEB_PROPER_FACE(
10354 fprintf(stdout, "proper face traversal\n");
10355 )
10356
10357 cur_e = e;
10358 cur_ein = ein;
10359 while (next_e != e)
10360 {
10361 ASSERT(embedg_VES_is_edge(n, cur_e));
10362 ASSERT(!embedg_VES_is_short_cut_edge(embed_graph,
10363 n, cur_e));
10364 IF_DEB_PROPER_FACE(
10365 embedg_VES_print_edge(embed_graph, n, cur_e);
10366 )
10367
10368 embedg_VES_get_succ_on_proper_face(embed_graph, n,
10369 cur_e, cur_ein,
10370 MARK, mark,
10371 &s, &next_e, &next_ein);
10372 cur_e = next_e;
10373 cur_ein = next_ein;
10374 }
10375
10376 /*
10377 note that by doing so we would have marked e and the first of e's
10378 endpoints since by exiting the loop e = next_e and s is the
10379 actual starting vertex of the walk
10380 */
10381 }
10382
10383
10384
10385
10386
10387