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