Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/planarity/graphK33Search_Extensions.c
4069 views
1
/*
2
Planarity-Related Graph Algorithms Project
3
Copyright (c) 1997-2010, John M. Boyer
4
All rights reserved. Includes a reference implementation of the following:
5
6
* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,
7
Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,
8
University of Victoria, 2001.
9
10
* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)
11
Planarity by Edge Addition". Journal of Graph Algorithms and Applications,
12
Vol. 8, No. 3, pp. 241-273, 2004.
13
14
* John M. Boyer. "A New Method for Efficiently Generating Planar Graph
15
Visibility Representations". In P. Eades and P. Healy, editors,
16
Proceedings of the 13th International Conference on Graph Drawing 2005,
17
Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.
18
19
Redistribution and use in source and binary forms, with or without modification,
20
are permitted provided that the following conditions are met:
21
22
* Redistributions of source code must retain the above copyright notice, this
23
list of conditions and the following disclaimer.
24
25
* Redistributions in binary form must reproduce the above copyright notice, this
26
list of conditions and the following disclaimer in the documentation and/or
27
other materials provided with the distribution.
28
29
* Neither the name of the Planarity-Related Graph Algorithms Project nor the names
30
of its contributors may be used to endorse or promote products derived from this
31
software without specific prior written permission.
32
33
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
37
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
40
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
*/
44
45
#include <stdlib.h>
46
47
#include "graphK33Search.private.h"
48
#include "graphK33Search.h"
49
50
extern int _SearchForMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int *pMergeBlocker);
51
extern int _SearchForK33(graphP theGraph, int I);
52
53
extern int _TestForK33GraphObstruction(graphP theGraph, int *degrees, int *imageVerts);
54
extern int _getImageVertices(graphP theGraph, int *degrees, int maxDegree,
55
int *imageVerts, int maxNumImageVerts);
56
extern int _TestSubgraph(graphP theSubgraph, graphP theGraph);
57
58
/* Forward declarations of local functions */
59
60
void _K33Search_ClearStructures(K33SearchContext *context);
61
int _K33Search_CreateStructures(K33SearchContext *context);
62
int _K33Search_InitStructures(K33SearchContext *context);
63
64
/* Forward declarations of overloading functions */
65
66
int _K33Search_CreateFwdArcLists(graphP theGraph);
67
void _K33Search_CreateDFSTreeEmbedding(graphP theGraph);
68
void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink);
69
int _K33Search_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink);
70
int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant);
71
int _K33Search_HandleBlockedEmbedIteration(graphP theGraph, int I);
72
int _K33Search_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult);
73
int _K33Search_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph);
74
int _K33Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph);
75
76
void _K33Search_InitGraphNode(graphP theGraph, int I);
77
void _InitK33SearchGraphNode(K33SearchContext *context, int I);
78
void _K33Search_InitVertexRec(graphP theGraph, int I);
79
void _InitK33SearchVertexRec(K33SearchContext *context, int I);
80
81
int _K33Search_InitGraph(graphP theGraph, int N);
82
void _K33Search_ReinitializeGraph(graphP theGraph);
83
int _K33Search_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity);
84
85
/* Forward declarations of functions used by the extension system */
86
87
void *_K33Search_DupContext(void *pContext, void *theGraph);
88
void _K33Search_FreeContext(void *);
89
90
/****************************************************************************
91
* K33SEARCH_ID - the variable used to hold the integer identifier for this
92
* extension, enabling this feature's extension context to be distinguished
93
* from other features' extension contexts that may be attached to a graph.
94
****************************************************************************/
95
96
int K33SEARCH_ID = 0;
97
98
/****************************************************************************
99
gp_AttachK33Search()
100
101
This function adjusts the graph data structure to attach the K3,3 search
102
feature.
103
****************************************************************************/
104
105
int gp_AttachK33Search(graphP theGraph)
106
{
107
K33SearchContext *context = NULL;
108
109
// If the K3,3 search feature has already been attached to the graph,
110
// then there is no need to attach it again
111
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
112
if (context != NULL)
113
{
114
return OK;
115
}
116
117
// Allocate a new extension context
118
context = (K33SearchContext *) malloc(sizeof(K33SearchContext));
119
if (context == NULL)
120
{
121
return NOTOK;
122
}
123
124
// First, tell the context that it is not initialized
125
context->initialized = 0;
126
127
// Save a pointer to theGraph in the context
128
context->theGraph = theGraph;
129
130
// Put the overload functions into the context function table.
131
// gp_AddExtension will overload the graph's functions with these, and
132
// return the base function pointers in the context function table
133
memset(&context->functions, 0, sizeof(graphFunctionTable));
134
135
context->functions.fpCreateFwdArcLists = _K33Search_CreateFwdArcLists;
136
context->functions.fpCreateDFSTreeEmbedding = _K33Search_CreateDFSTreeEmbedding;
137
context->functions.fpEmbedBackEdgeToDescendant = _K33Search_EmbedBackEdgeToDescendant;
138
context->functions.fpMergeBicomps = _K33Search_MergeBicomps;
139
context->functions.fpMarkDFSPath = _K33Search_MarkDFSPath;
140
context->functions.fpHandleBlockedEmbedIteration = _K33Search_HandleBlockedEmbedIteration;
141
context->functions.fpEmbedPostprocess = _K33Search_EmbedPostprocess;
142
context->functions.fpCheckEmbeddingIntegrity = _K33Search_CheckEmbeddingIntegrity;
143
context->functions.fpCheckObstructionIntegrity = _K33Search_CheckObstructionIntegrity;
144
145
context->functions.fpInitGraphNode = _K33Search_InitGraphNode;
146
context->functions.fpInitVertexRec = _K33Search_InitVertexRec;
147
148
context->functions.fpInitGraph = _K33Search_InitGraph;
149
context->functions.fpReinitializeGraph = _K33Search_ReinitializeGraph;
150
context->functions.fpEnsureArcCapacity = _K33Search_EnsureArcCapacity;
151
152
_K33Search_ClearStructures(context);
153
154
// Store the K33 search context, including the data structure and the
155
// function pointers, as an extension of the graph
156
if (gp_AddExtension(theGraph, &K33SEARCH_ID, (void *) context,
157
_K33Search_DupContext, _K33Search_FreeContext,
158
&context->functions) != OK)
159
{
160
_K33Search_FreeContext(context);
161
return NOTOK;
162
}
163
164
// Create the K33-specific structures if the size of the graph is known
165
// Attach functions are always invoked after gp_New(), but if a graph
166
// extension must be attached before gp_Read(), then the attachment
167
// also happens before gp_InitGraph(), which means N==0.
168
// However, sometimes a feature is attached after gp_InitGraph(), in
169
// which case N > 0
170
if (theGraph->N > 0)
171
{
172
if (_K33Search_CreateStructures(context) != OK ||
173
_K33Search_InitStructures(context) != OK)
174
{
175
_K33Search_FreeContext(context);
176
return NOTOK;
177
}
178
}
179
180
return OK;
181
}
182
183
/********************************************************************
184
gp_DetachK33Search()
185
********************************************************************/
186
187
int gp_DetachK33Search(graphP theGraph)
188
{
189
return gp_RemoveExtension(theGraph, K33SEARCH_ID);
190
}
191
192
/********************************************************************
193
_K33Search_ClearStructures()
194
********************************************************************/
195
196
void _K33Search_ClearStructures(K33SearchContext *context)
197
{
198
if (!context->initialized)
199
{
200
// Before initialization, the pointers are stray, not NULL
201
// Once NULL or allocated, free() or LCFree() can do the job
202
context->sortedDFSChildLists = NULL;
203
context->G = NULL;
204
context->V = NULL;
205
206
context->initialized = 1;
207
}
208
else
209
{
210
LCFree(&context->sortedDFSChildLists);
211
if (context->G != NULL)
212
{
213
free(context->G);
214
context->G = NULL;
215
}
216
if (context->V != NULL)
217
{
218
free(context->V);
219
context->V = NULL;
220
}
221
}
222
}
223
224
/********************************************************************
225
_K33Search_CreateStructures()
226
Create uninitialized structures for the vertex and graph node
227
levels, and initialized structures for the graph level
228
********************************************************************/
229
int _K33Search_CreateStructures(K33SearchContext *context)
230
{
231
int N = context->theGraph->N;
232
int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;
233
234
if (N <= 0)
235
return NOTOK;
236
237
if ((context->sortedDFSChildLists = LCNew(context->theGraph->N)) == NULL ||
238
(context->G = (K33Search_GraphNodeP) malloc(Gsize*sizeof(K33Search_GraphNode))) == NULL ||
239
(context->V = (K33Search_VertexRecP) malloc(N*sizeof(K33Search_VertexRec))) == NULL
240
)
241
{
242
return NOTOK;
243
}
244
245
return OK;
246
}
247
248
/********************************************************************
249
_K33Search_InitStructures()
250
********************************************************************/
251
int _K33Search_InitStructures(K33SearchContext *context)
252
{
253
int I, N = context->theGraph->N;
254
int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;
255
256
if (N <= 0)
257
return OK;
258
259
for (I = 0; I < Gsize; I++)
260
_InitK33SearchGraphNode(context, I);
261
262
for (I = 0; I < N; I++)
263
_InitK33SearchVertexRec(context, I);
264
265
return OK;
266
}
267
268
/********************************************************************
269
********************************************************************/
270
271
int _K33Search_InitGraph(graphP theGraph, int N)
272
{
273
K33SearchContext *context = NULL;
274
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
275
276
if (context == NULL)
277
return NOTOK;
278
{
279
theGraph->N = N;
280
theGraph->edgeOffset = 2*N;
281
if (theGraph->arcCapacity == 0)
282
theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N;
283
284
if (_K33Search_CreateStructures(context) != OK)
285
return NOTOK;
286
287
// This call initializes the base graph structures, but it also
288
// initializes the custom graphnode and vertex level structures
289
// due to the overloads of InitGraphNode and InitVertexRec
290
context->functions.fpInitGraph(theGraph, N);
291
}
292
293
return OK;
294
}
295
296
/********************************************************************
297
********************************************************************/
298
299
void _K33Search_ReinitializeGraph(graphP theGraph)
300
{
301
K33SearchContext *context = NULL;
302
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
303
304
if (context != NULL)
305
{
306
// Reinitialization can go much faster if the underlying
307
// init graph node and vertex rec functions are called,
308
// rather than the overloads of this module, because it
309
// avoids lots of unnecessary gp_FindExtension() calls.
310
if (theGraph->functions.fpInitGraphNode == _K33Search_InitGraphNode &&
311
theGraph->functions.fpInitVertexRec == _K33Search_InitVertexRec)
312
{
313
// Restore the graph function pointers
314
theGraph->functions.fpInitGraphNode = context->functions.fpInitGraphNode;
315
theGraph->functions.fpInitVertexRec = context->functions.fpInitVertexRec;
316
317
// Reinitialize the graph
318
context->functions.fpReinitializeGraph(theGraph);
319
320
// Restore the function pointers that attach this feature
321
theGraph->functions.fpInitGraphNode = _K33Search_InitGraphNode;
322
theGraph->functions.fpInitVertexRec = _K33Search_InitVertexRec;
323
324
// Do the reinitialization that is specific to this module
325
_K33Search_InitStructures(context);
326
LCReset(context->sortedDFSChildLists);
327
}
328
329
// If optimization is not possible, then just stick with what works.
330
// Reinitialize the graph-level structure and then invoke the
331
// reinitialize function.
332
else
333
{
334
LCReset(context->sortedDFSChildLists);
335
336
// The underlying function fpReinitializeGraph() implicitly initializes the K33
337
// structures due to the overloads of fpInitGraphNode() and fpInitVertexRec().
338
// It just does so less efficiently because each invocation of InitGraphNode
339
// and InitVertexRec has to look up the extension again.
340
//// _K33Search_InitStructures(context);
341
context->functions.fpReinitializeGraph(theGraph);
342
}
343
}
344
}
345
346
/********************************************************************
347
The current implementation does not support an increase of arc
348
(edge record) capacity once the extension is attached to the graph
349
data structure. This is only due to not being necessary to support.
350
For now, it is easy to ensure the correct capacity before attaching
351
the extension, but support could be added later if there is some
352
reason to do so.
353
********************************************************************/
354
355
int _K33Search_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)
356
{
357
return NOTOK;
358
}
359
360
/********************************************************************
361
_K33Search_DupContext()
362
********************************************************************/
363
364
void *_K33Search_DupContext(void *pContext, void *theGraph)
365
{
366
K33SearchContext *context = (K33SearchContext *) pContext;
367
K33SearchContext *newContext = (K33SearchContext *) malloc(sizeof(K33SearchContext));
368
369
if (newContext != NULL)
370
{
371
int N = ((graphP) theGraph)->N;
372
int Gsize = ((graphP) theGraph)->edgeOffset + ((graphP) theGraph)->arcCapacity;
373
374
*newContext = *context;
375
376
newContext->theGraph = (graphP) theGraph;
377
378
newContext->initialized = 0;
379
_K33Search_ClearStructures(newContext);
380
if (N > 0)
381
{
382
if (_K33Search_CreateStructures(newContext) != OK)
383
{
384
_K33Search_FreeContext(newContext);
385
return NULL;
386
}
387
388
LCCopy(newContext->sortedDFSChildLists, context->sortedDFSChildLists);
389
memcpy(newContext->G, context->G, Gsize*sizeof(K33Search_GraphNode));
390
memcpy(newContext->V, context->V, N*sizeof(K33Search_VertexRec));
391
}
392
}
393
394
return newContext;
395
}
396
397
/********************************************************************
398
_K33Search_FreeContext()
399
********************************************************************/
400
401
void _K33Search_FreeContext(void *pContext)
402
{
403
K33SearchContext *context = (K33SearchContext *) pContext;
404
405
_K33Search_ClearStructures(context);
406
free(pContext);
407
}
408
409
/********************************************************************
410
_K33Search_CreateFwdArcLists()
411
412
Puts the forward arcs (back edges from a vertex to its descendants)
413
into a circular list indicated by the fwdArcList member, a task
414
simplified by the fact that they have already been placed in
415
succession at the end of the adjacency list.
416
417
For K3,3 search, the forward edges must be sorted. The sort is linear
418
time, but it is a little slower, so we avoid this cost for the other
419
planarity-related algorithms.
420
421
Returns OK on success, NOTOK on internal code failure
422
********************************************************************/
423
424
int _K33Search_CreateFwdArcLists(graphP theGraph)
425
{
426
K33SearchContext *context = NULL;
427
428
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
429
if (context == NULL)
430
return NOTOK;
431
432
// For isolating a K_{3,3} homeomorph, we need the forward edges
433
// of each vertex to be in sorted order by DFI of descendants.
434
// Otherwise we just drop through to the normal processing...
435
436
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
437
{
438
int I, Jcur, Jnext, ancestor;
439
440
// for each vertex v in order, we follow each of its back edges
441
// to the twin forward edge in an ancestor u, then we move
442
// the forward edge to the fwdArcList of u. Since this loop
443
// processes vertices in order, the fwdArcList of each vertex
444
// will be in order by the neighbor indicated by the forward edges.
445
446
for (I=0; I < theGraph->N; I++)
447
{
448
// Skip this vertex if it has no edges
449
Jnext = gp_GetLastArc(theGraph, I);
450
if (!gp_IsArc(theGraph, Jnext))
451
continue;
452
453
// Skip the forward edges, which are in succession at the
454
// end of the arc list (last and its predecessors)
455
while (theGraph->G[Jnext].type == EDGE_FORWARD)
456
Jnext = gp_GetPrevArc(theGraph, Jnext);
457
458
// Now we want to put all the back arcs in a backArcList, too.
459
// Since we've already skipped past the forward arcs, we continue
460
// with the predecessor arcs until we either run out of arcs or
461
// we find a DFS child arc (the DFS child arcs are in succession
462
// at the beginning of the arc list, so when a child arc is
463
// encountered in the predecessor direction, then there won't be
464
// any more back arcs.
465
while (gp_IsArc(theGraph, Jnext) &&
466
theGraph->G[Jnext].type != EDGE_DFSCHILD)
467
{
468
Jcur = Jnext;
469
Jnext = gp_GetPrevArc(theGraph, Jnext);
470
471
if (theGraph->G[Jcur].type == EDGE_BACK)
472
{
473
// Remove the back arc from I's adjacency list
474
gp_DetachArc(theGraph, Jcur);
475
476
// Put the back arc in the backArcList
477
if (context->V[I].backArcList == NIL)
478
{
479
context->V[I].backArcList = Jcur;
480
gp_SetPrevArc(theGraph, Jcur, Jcur);
481
gp_SetNextArc(theGraph, Jcur, Jcur);
482
}
483
else
484
{
485
gp_AttachArc(theGraph, NIL, context->V[I].backArcList, 1, Jcur);
486
}
487
488
// Determine the ancestor of vertex I to which Jcur connects
489
ancestor = theGraph->G[Jcur].v;
490
491
// Go to the forward arc in the ancestor
492
Jcur = gp_GetTwinArc(theGraph, Jcur);
493
494
// Remove the forward arc from the ancestor's adjacency list
495
gp_DetachArc(theGraph, Jcur);
496
497
// Add the forward arc to the end of the fwdArcList.
498
if (theGraph->V[ancestor].fwdArcList == NIL)
499
{
500
theGraph->V[ancestor].fwdArcList = Jcur;
501
gp_SetPrevArc(theGraph, Jcur, Jcur);
502
gp_SetNextArc(theGraph, Jcur, Jcur);
503
}
504
else
505
{
506
gp_AttachArc(theGraph, NIL, theGraph->V[ancestor].fwdArcList, 1, Jcur);
507
}
508
}
509
}
510
}
511
512
// Since the fwdArcLists have been created, we do not fall through
513
// to run the superclass implementation
514
return OK;
515
}
516
517
// If we're not actually running a K3,3 search, then we just run the
518
// superclass implementation
519
return context->functions.fpCreateFwdArcLists(theGraph);
520
}
521
522
/********************************************************************
523
_K33Search_CreateDFSTreeEmbedding()
524
525
This function overloads the basic planarity version in the manner
526
explained by the comments below. Once the extra behavior is
527
performed, the basic planarity version is invoked.
528
********************************************************************/
529
530
void _K33Search_CreateDFSTreeEmbedding(graphP theGraph)
531
{
532
K33SearchContext *context = NULL;
533
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
534
535
if (context != NULL)
536
{
537
// When searching for K_{3,3} homeomorphs, we need the
538
// list of DFS children for each vertex, which gets lost
539
// during the initial tree embedding (each DFS tree child
540
// arc is moved to the root copy of the vertex)
541
542
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
543
{
544
int I, J, N;
545
546
N = theGraph->N;
547
548
for (I=0; I<N; I++)
549
{
550
J = gp_GetFirstArc(theGraph, I);
551
552
// If a vertex has any DFS children, the edges
553
// to them are stored in descending order of
554
// the DFI's along the successor arc pointers, so
555
// we traverse them and prepend each to the
556
// ascending order sortedDFSChildList
557
558
while (theGraph->G[J].type == EDGE_DFSCHILD)
559
{
560
context->V[I].sortedDFSChildList =
561
LCPrepend(context->sortedDFSChildLists,
562
context->V[I].sortedDFSChildList,
563
theGraph->G[J].v);
564
565
J = gp_GetNextArc(theGraph, J);
566
}
567
}
568
}
569
570
// Invoke the superclass version of the function
571
context->functions.fpCreateDFSTreeEmbedding(theGraph);
572
}
573
}
574
575
/********************************************************************
576
_K33Search_EmbedBackEdgeToDescendant()
577
578
The forward and back arcs of the cycle edge are embedded by the planarity
579
version of this function.
580
However, for K_{3,3} subgraph homeomorphism, we also maintain the
581
list of unembedded back arcs, so we need to remove the back arc from
582
that list since it is now being put back into the adjacency list.
583
********************************************************************/
584
585
void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink)
586
{
587
K33SearchContext *context = NULL;
588
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
589
590
if (context != NULL)
591
{
592
// K33 search may have been attached, but not enabled
593
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
594
{
595
// Get the fwdArc from the adjacentTo field, and use it to get the backArc
596
int backArc = gp_GetTwinArc(theGraph, theGraph->V[W].adjacentTo);
597
598
// Remove the backArc from the backArcList
599
if (context->V[W].backArcList == backArc)
600
{
601
if (gp_GetNextArc(theGraph, backArc) == backArc)
602
context->V[W].backArcList = NIL;
603
else context->V[W].backArcList = gp_GetNextArc(theGraph, backArc);
604
}
605
606
gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, backArc), gp_GetNextArc(theGraph, backArc));
607
gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, backArc), gp_GetPrevArc(theGraph, backArc));
608
}
609
610
// Invoke the superclass version of the function
611
context->functions.fpEmbedBackEdgeToDescendant(theGraph, RootSide, RootVertex, W, WPrevLink);
612
}
613
}
614
615
/********************************************************************
616
617
This override of _MergeBicomps() detects a special merge block
618
that indicates a K3,3 can be found. The merge blocker is an
619
optimization needed for one case for which detecting a K3,3
620
could not be done in linear time.
621
622
Returns OK for a successful merge, NOTOK on an internal failure,
623
or NONEMBEDDABLE if the merge is blocked
624
********************************************************************/
625
626
int _K33Search_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink)
627
{
628
K33SearchContext *context = NULL;
629
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
630
631
if (context != NULL)
632
{
633
/* If the merge is blocked, then the Walkdown is terminated so a
634
K3,3 can be isolated by _SearchForK33() */
635
636
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
637
{
638
int mergeBlocker;
639
640
// We want to test all merge points on the stack
641
// as well as W, since the connection will go
642
// from W. So we push W as a 'degenerate' merge point.
643
sp_Push2(theGraph->theStack, W, WPrevLink);
644
sp_Push2(theGraph->theStack, NIL, NIL);
645
646
_SearchForMergeBlocker(theGraph, context, I, &mergeBlocker);
647
648
// If we find a merge blocker, then we return with
649
// the stack intact including W so that the merge
650
// blocked vertex can be easily found.
651
if (mergeBlocker != NIL)
652
return NONEMBEDDABLE;
653
654
// If no merge blocker was found, then remove
655
// W from the stack.
656
sp_Pop2(theGraph->theStack, W, WPrevLink);
657
sp_Pop2(theGraph->theStack, W, WPrevLink);
658
}
659
660
// If the merge was not blocked, then we perform the merge
661
// When not doing a K3,3 search, then the merge is not
662
// blocked as far as the K3,3 search method is concerned
663
// Another algorithms could overload MergeBicomps and block
664
// merges under certain conditions, but those would be based
665
// on data maintained by the extension that implements the
666
// other algorithm-- if *that* algorithm is the one being run
667
return context->functions.fpMergeBicomps(theGraph, I, RootVertex, W, WPrevLink);
668
}
669
670
return NOTOK;
671
}
672
673
/********************************************************************
674
********************************************************************/
675
676
void _K33Search_InitGraphNode(graphP theGraph, int I)
677
{
678
K33SearchContext *context = NULL;
679
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
680
681
if (context != NULL)
682
{
683
context->functions.fpInitGraphNode(theGraph, I);
684
_InitK33SearchGraphNode(context, I);
685
}
686
}
687
688
void _InitK33SearchGraphNode(K33SearchContext *context, int I)
689
{
690
context->G[I].noStraddle = NIL;
691
context->G[I].pathConnector = NIL;
692
}
693
694
/********************************************************************
695
********************************************************************/
696
697
void _K33Search_InitVertexRec(graphP theGraph, int I)
698
{
699
K33SearchContext *context = NULL;
700
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
701
702
if (context != NULL)
703
{
704
context->functions.fpInitVertexRec(theGraph, I);
705
_InitK33SearchVertexRec(context, I);
706
}
707
}
708
709
void _InitK33SearchVertexRec(K33SearchContext *context, int I)
710
{
711
context->V[I].sortedDFSChildList = NIL;
712
context->V[I].backArcList = NIL;
713
context->V[I].externalConnectionAncestor = NIL;
714
context->V[I].mergeBlocker = NIL;
715
}
716
717
/********************************************************************
718
// This function used to be implemented by going to each
719
// vertex, asking for its DFS parent, then finding the
720
// edge that lead to that DFS parent and marking it.
721
// However, the K3,3 search performs a certain bicomp
722
// reduction that is required to preserve the essential
723
// structure of the DFS tree. As a result, sometimes a
724
// DFSParent has been reduced out of the graph, but the
725
// tree edge leads to the nearest ancestor still in the
726
// graph. So, when we want to leave a vertex, we search
727
// for the DFS tree edge to the "parent" (nearest ancestor).
728
// then we mark the edge and use it to go up to the "parent".
729
********************************************************************/
730
731
int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant)
732
{
733
int J, parent, N;
734
735
N = theGraph->N;
736
737
/* If we are marking from a root vertex upward, then go up to the parent
738
copy before starting the loop */
739
740
if (descendant >= N)
741
descendant = theGraph->V[descendant-N].DFSParent;
742
743
/* Mark the lowest vertex (the one with the highest number). */
744
745
theGraph->G[descendant].visited = 1;
746
747
/* Mark all ancestors of the lowest vertex, and the edges used to reach
748
them, up to the given ancestor vertex. */
749
750
while (descendant != ancestor)
751
{
752
if (descendant == NIL)
753
return NOTOK;
754
755
/* If we are at a bicomp root, then ascend to its parent copy and
756
mark it as visited. */
757
758
if (descendant >= N)
759
{
760
parent = theGraph->V[descendant-N].DFSParent;
761
}
762
763
/* If we are on a regular, non-virtual vertex then get the edge to
764
the parent, mark the edge, then fall through to the code
765
that marks the parent vertex. */
766
else
767
{
768
769
/* Scan the edges for the one marked as the DFS parent */
770
771
parent = NIL;
772
J = gp_GetFirstArc(theGraph, descendant);
773
while (gp_IsArc(theGraph, J))
774
{
775
if (theGraph->G[J].type == EDGE_DFSPARENT)
776
{
777
parent = theGraph->G[J].v;
778
break;
779
}
780
J = gp_GetNextArc(theGraph, J);
781
}
782
783
/* If the desired edge was not found, then the data structure is
784
corrupt, so bail out. */
785
786
if (parent == NIL)
787
return NOTOK;
788
789
/* Mark the edge */
790
791
theGraph->G[J].visited = 1;
792
theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1;
793
}
794
795
/* Mark the parent, then hop to the parent and reiterate */
796
797
theGraph->G[parent].visited = 1;
798
descendant = parent;
799
}
800
801
return OK;
802
}
803
804
/********************************************************************
805
********************************************************************/
806
807
int _K33Search_HandleBlockedEmbedIteration(graphP theGraph, int I)
808
{
809
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
810
return _SearchForK33(theGraph, I);
811
812
else
813
{
814
K33SearchContext *context = NULL;
815
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
816
817
if (context != NULL)
818
{
819
return context->functions.fpHandleBlockedEmbedIteration(theGraph, I);
820
}
821
}
822
823
return NOTOK;
824
}
825
826
/********************************************************************
827
********************************************************************/
828
829
int _K33Search_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult)
830
{
831
// For K3,3 search, we just return the edge embedding result because the
832
// search result has been obtained already.
833
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
834
{
835
return edgeEmbeddingResult;
836
}
837
838
// When not searching for K3,3, we let the superclass do the work
839
else
840
{
841
K33SearchContext *context = NULL;
842
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
843
844
if (context != NULL)
845
{
846
return context->functions.fpEmbedPostprocess(theGraph, I, edgeEmbeddingResult);
847
}
848
}
849
850
return NOTOK;
851
}
852
853
/********************************************************************
854
********************************************************************/
855
856
int _K33Search_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph)
857
{
858
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
859
{
860
return OK;
861
}
862
863
// When not searching for K3,3, we let the superclass do the work
864
else
865
{
866
K33SearchContext *context = NULL;
867
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
868
869
if (context != NULL)
870
{
871
return context->functions.fpCheckEmbeddingIntegrity(theGraph, origGraph);
872
}
873
}
874
875
return NOTOK;
876
}
877
878
/********************************************************************
879
********************************************************************/
880
881
int _K33Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph)
882
{
883
// When searching for K3,3, we ensure that theGraph is a subgraph of
884
// the original graph and that it contains a K3,3 homeomorph
885
if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)
886
{
887
int degrees[5], imageVerts[6];
888
889
if (_TestSubgraph(theGraph, origGraph) != TRUE)
890
{
891
return NOTOK;
892
}
893
894
if (_getImageVertices(theGraph, degrees, 4, imageVerts, 6) != OK)
895
{
896
return NOTOK;
897
}
898
899
if (_TestForK33GraphObstruction(theGraph, degrees, imageVerts) == TRUE)
900
{
901
return OK;
902
}
903
904
return NOTOK;
905
}
906
907
// When not searching for K3,3, we let the superclass do the work
908
else
909
{
910
K33SearchContext *context = NULL;
911
gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
912
913
if (context != NULL)
914
{
915
return context->functions.fpCheckObstructionIntegrity(theGraph, origGraph);
916
}
917
}
918
919
return NOTOK;
920
}
921
922
923