Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/planarity/graphUtils.c
4077 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
#define GRAPHSTRUCTURE_C
46
47
#include <stdlib.h>
48
49
#include "graphStructures.h"
50
#include "graph.h"
51
52
/* Imported functions for FUNCTION POINTERS */
53
54
extern int _CreateFwdArcLists(graphP);
55
extern void _CreateDFSTreeEmbedding(graphP theGraph);
56
extern int _SortVertices(graphP theGraph);
57
extern void _EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink);
58
extern void _WalkUp(graphP theGraph, int I, int J);
59
extern int _WalkDown(graphP theGraph, int I, int RootVertex);
60
extern int _MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink);
61
extern int _HandleBlockedDescendantBicomp(graphP theGraph, int I, int RootVertex, int R, int *pRout, int *pW, int *pWPrevLink);
62
extern int _HandleInactiveVertex(graphP theGraph, int BicompRoot, int *pW, int *pWPrevLink);
63
extern int _MarkDFSPath(graphP theGraph, int ancestor, int descendant);
64
extern int _HandleBlockedEmbedIteration(graphP theGraph, int I);
65
extern int _EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult);
66
extern int _CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph);
67
extern int _CheckObstructionIntegrity(graphP theGraph, graphP origGraph);
68
extern int _ReadPostprocess(graphP theGraph, void *extraData, long extraDataSize);
69
extern int _WritePostprocess(graphP theGraph, void **pExtraData, long *pExtraDataSize);
70
71
/* Internal util functions for FUNCTION POINTERS */
72
73
int _HideVertex(graphP theGraph, int vertex);
74
void _HideEdge(graphP theGraph, int arcPos);
75
void _RestoreEdge(graphP theGraph, int arcPos);
76
int _ContractEdge(graphP theGraph, int e);
77
int _IdentifyVertices(graphP theGraph, int u, int v, int eBefore);
78
int _RestoreVertex(graphP theGraph);
79
80
/********************************************************************
81
Private functions, except exported within library
82
********************************************************************/
83
84
void _ClearIsolatorContext(graphP theGraph);
85
void _FillVisitedFlags(graphP theGraph, int FillValue);
86
int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue);
87
int _FillVisitedFlagsInOtherBicomps(graphP theGraph, int BicompRoot, int FillValue);
88
void _FillVisitedFlagsInUnembeddedEdges(graphP theGraph, int FillValue);
89
int _SetVertexTypeInBicomp(graphP theGraph, int BicompRoot, int theType);
90
91
int _HideInternalEdges(graphP theGraph, int vertex);
92
int _RestoreInternalEdges(graphP theGraph, int stackBottom);
93
int _RestoreHiddenEdges(graphP theGraph, int stackBottom);
94
95
int _GetBicompSize(graphP theGraph, int BicompRoot);
96
int _DeleteUnmarkedEdgesInBicomp(graphP theGraph, int BicompRoot);
97
int _ClearInvertedFlagsInBicomp(graphP theGraph, int BicompRoot);
98
99
void _InitFunctionTable(graphP theGraph);
100
101
/********************************************************************
102
Private functions.
103
********************************************************************/
104
105
void _ClearGraph(graphP theGraph);
106
107
int _GetRandomNumber(int NMin, int NMax);
108
109
/* Private functions for which there are FUNCTION POINTERS */
110
111
void _InitGraphNode(graphP theGraph, int I);
112
void _InitVertexRec(graphP theGraph, int I);
113
114
int _InitGraph(graphP theGraph, int N);
115
void _ReinitializeGraph(graphP theGraph);
116
int _EnsureArcCapacity(graphP theGraph, int requiredArcCapacity);
117
118
/********************************************************************
119
gp_New()
120
Constructor for graph object.
121
Can create two graphs if restricted to no dynamic memory.
122
********************************************************************/
123
124
graphP gp_New()
125
{
126
graphP theGraph = (graphP) malloc(sizeof(baseGraphStructure));
127
128
if (theGraph != NULL)
129
{
130
theGraph->G = NULL;
131
theGraph->V = NULL;
132
133
theGraph->BicompLists = NULL;
134
theGraph->DFSChildLists = NULL;
135
theGraph->theStack = NULL;
136
137
theGraph->buckets = NULL;
138
theGraph->bin = NULL;
139
140
theGraph->extFace = NULL;
141
142
theGraph->edgeHoles = NULL;
143
144
theGraph->extensions = NULL;
145
146
_InitFunctionTable(theGraph);
147
148
_ClearGraph(theGraph);
149
}
150
151
return theGraph;
152
}
153
154
/********************************************************************
155
_InitFunctionTable()
156
157
If you add functions to the function table, then they must be
158
initialized here, but you must also add the new function pointer
159
to the definition of the graphFunctionTable in graphFunctionTable.h
160
161
Function headers for the functions used to initialize the table are
162
classified at the top of this file as either imported from other
163
compilation units (extern) or private to this compilation unit.
164
Search for FUNCTION POINTERS in this file to see where to add the
165
function header.
166
********************************************************************/
167
168
void _InitFunctionTable(graphP theGraph)
169
{
170
theGraph->functions.fpCreateFwdArcLists = _CreateFwdArcLists;
171
theGraph->functions.fpCreateDFSTreeEmbedding = _CreateDFSTreeEmbedding;
172
theGraph->functions.fpEmbedBackEdgeToDescendant = _EmbedBackEdgeToDescendant;
173
theGraph->functions.fpWalkUp = _WalkUp;
174
theGraph->functions.fpWalkDown = _WalkDown;
175
theGraph->functions.fpMergeBicomps = _MergeBicomps;
176
theGraph->functions.fpHandleBlockedDescendantBicomp = _HandleBlockedDescendantBicomp;
177
theGraph->functions.fpHandleInactiveVertex = _HandleInactiveVertex;
178
theGraph->functions.fpHandleBlockedEmbedIteration = _HandleBlockedEmbedIteration;
179
theGraph->functions.fpEmbedPostprocess = _EmbedPostprocess;
180
theGraph->functions.fpMarkDFSPath = _MarkDFSPath;
181
theGraph->functions.fpCheckEmbeddingIntegrity = _CheckEmbeddingIntegrity;
182
theGraph->functions.fpCheckObstructionIntegrity = _CheckObstructionIntegrity;
183
184
theGraph->functions.fpInitGraphNode = _InitGraphNode;
185
theGraph->functions.fpInitVertexRec = _InitVertexRec;
186
187
theGraph->functions.fpInitGraph = _InitGraph;
188
theGraph->functions.fpReinitializeGraph = _ReinitializeGraph;
189
theGraph->functions.fpEnsureArcCapacity = _EnsureArcCapacity;
190
theGraph->functions.fpSortVertices = _SortVertices;
191
192
theGraph->functions.fpReadPostprocess = _ReadPostprocess;
193
theGraph->functions.fpWritePostprocess = _WritePostprocess;
194
195
theGraph->functions.fpHideVertex = _HideVertex;
196
theGraph->functions.fpHideEdge = _HideEdge;
197
theGraph->functions.fpRestoreEdge = _RestoreEdge;
198
theGraph->functions.fpContractEdge = _ContractEdge;
199
theGraph->functions.fpIdentifyVertices = _IdentifyVertices;
200
theGraph->functions.fpRestoreVertex = _RestoreVertex;
201
}
202
203
/********************************************************************
204
gp_InitGraph()
205
Allocates memory for vertex and edge records now that N is known.
206
The arcCapacity is set to (2 * DEFAULT_EDGE_LIMIT * N) unless it
207
has already been set by gp_EnsureArcCapacity()
208
209
For G, we need N vertex nodes, N more vertex nodes for root copies,
210
and arcCapacity edge records.
211
212
For V, we need N vertex records.
213
214
The BicompLists and DFSChildLists are of size N and start out empty.
215
216
The stack, initially empty, is made big enough for a pair of integers
217
per edge record, or 2 * arcCapacity.
218
219
The edgeHoles stack, initially empty, is set to arcCapacity / 2,
220
which is big enough to push every edge (to indicate an edge
221
you only need to indicate one of its two edge records)
222
223
buckets and bin are both O(N) in size. They are used by
224
CreateSortedSeparatedDFSChildLists()
225
226
Returns OK on success, NOTOK on all failures.
227
On NOTOK, graph extensions are freed so that the graph is
228
returned to the post-condition of gp_New().
229
********************************************************************/
230
231
int gp_InitGraph(graphP theGraph, int N)
232
{
233
// valid params check
234
if (theGraph == NULL || N <= 0)
235
return NOTOK;
236
237
// Should not call init a second time; use reinit
238
if (theGraph->N > 0)
239
return NOTOK;
240
241
return theGraph->functions.fpInitGraph(theGraph, N);
242
}
243
244
int _InitGraph(graphP theGraph, int N)
245
{
246
int I, edgeOffset, arcCapacity, Gsize, Vsize, stackSize;
247
248
/* Compute the vertex and edge capacities of the graph */
249
250
Vsize = 2*N;
251
edgeOffset = Vsize;
252
arcCapacity = theGraph->arcCapacity > 0 ? theGraph->arcCapacity : 2*DEFAULT_EDGE_LIMIT*N;
253
Gsize = edgeOffset + arcCapacity;
254
stackSize = 2 * arcCapacity;
255
stackSize = stackSize < 6*N ? 6*N : stackSize;
256
257
/* Allocate memory as described above */
258
259
if ((theGraph->G = (graphNodeP) malloc(Gsize*sizeof(graphNode))) == NULL ||
260
(theGraph->V = (vertexRecP) malloc(N*sizeof(vertexRec))) == NULL ||
261
(theGraph->BicompLists = LCNew(N)) == NULL ||
262
(theGraph->DFSChildLists = LCNew(N)) == NULL ||
263
(theGraph->theStack = sp_New(stackSize)) == NULL ||
264
(theGraph->buckets = (int *) malloc(N * sizeof(int))) == NULL ||
265
(theGraph->bin = LCNew(N)) == NULL ||
266
(theGraph->extFace = (extFaceLinkRecP) malloc(Vsize*sizeof(extFaceLinkRec))) == NULL ||
267
(theGraph->edgeHoles = sp_New(arcCapacity / 2)) == NULL ||
268
0)
269
{
270
_ClearGraph(theGraph);
271
return NOTOK;
272
}
273
274
/* Initialize memory */
275
276
theGraph->N = N;
277
theGraph->edgeOffset = edgeOffset;
278
theGraph->arcCapacity = Gsize - edgeOffset;
279
280
for (I = 0; I < Gsize; I++)
281
theGraph->functions.fpInitGraphNode(theGraph, I);
282
283
for (I = 0; I < N; I++)
284
theGraph->functions.fpInitVertexRec(theGraph, I);
285
286
for (I = 0; I < Vsize; I++)
287
{
288
theGraph->extFace[I].vertex[0] = theGraph->extFace[I].vertex[1] = NIL;
289
theGraph->extFace[I].inversionFlag = 0;
290
}
291
292
_ClearIsolatorContext(theGraph);
293
294
return OK;
295
}
296
297
/********************************************************************
298
gp_ReinitializeGraph()
299
Reinitializes a graph, restoring it to the state it was in immediately
300
after gp_InitGraph() processed it.
301
********************************************************************/
302
303
void gp_ReinitializeGraph(graphP theGraph)
304
{
305
if (theGraph == NULL || theGraph->N <= 0)
306
return;
307
308
theGraph->functions.fpReinitializeGraph(theGraph);
309
}
310
311
void _ReinitializeGraph(graphP theGraph)
312
{
313
int I, N = theGraph->N, edgeOffset = theGraph->edgeOffset;
314
int Vsize = 2*N, Gsize = edgeOffset + theGraph->arcCapacity;
315
316
theGraph->M = 0;
317
theGraph->internalFlags = theGraph->embedFlags = 0;
318
319
for (I = 0; I < Gsize; I++)
320
theGraph->functions.fpInitGraphNode(theGraph, I);
321
322
for (I = 0; I < N; I++)
323
theGraph->functions.fpInitVertexRec(theGraph, I);
324
325
for (I = 0; I < Vsize; I++)
326
{
327
theGraph->extFace[I].vertex[0] = theGraph->extFace[I].vertex[1] = NIL;
328
theGraph->extFace[I].inversionFlag = 0;
329
}
330
331
_ClearIsolatorContext(theGraph);
332
333
LCReset(theGraph->BicompLists);
334
LCReset(theGraph->DFSChildLists);
335
sp_ClearStack(theGraph->theStack);
336
LCReset(theGraph->bin);
337
sp_ClearStack(theGraph->edgeHoles);
338
}
339
340
/********************************************************************
341
gp_GetArcCapacity()
342
Returns the arcCapacity of theGraph, which is twice the maximum
343
number of edges that can be added to the theGraph.
344
********************************************************************/
345
int gp_GetArcCapacity(graphP theGraph)
346
{
347
return theGraph->arcCapacity;
348
}
349
350
/********************************************************************
351
gp_EnsureArcCapacity()
352
This method ensures that theGraph is or will be capable of storing
353
at least requiredArcCapacity edge records. Two edge records are
354
needed per edge.
355
356
This method is most performant when invoked immediately after
357
gp_New(), since it must only set the arcCapacity and then let
358
normal initialization to occur through gp_InitGraph().
359
360
This method is also a constant time operation if the graph already
361
has at least the requiredArcCapacity, since it will return OK
362
without making any structural changes.
363
364
This method is generally more performant if it is invoked before
365
attaching extensions to the graph. Some extensions associate
366
parallel data with edge records, which is a faster operation if
367
the associated data is created and initialized only after the
368
proper arcCapacity is specified.
369
370
If the graph has been initialized and has a lower arc capacity,
371
then the array of edge records is reallocated to satisfy the
372
requiredArcCapacity. The new array contains the old edges and
373
edge holes at the same locations, and all newly created edge records
374
are initialized.
375
376
Also, if the arc capacity must be increased, then the
377
arcCapacity member of theGraph is changed and both
378
theStack and edgeHoles are expanded (since the sizes of both
379
are based on the arc capacity).
380
381
Extensions that add to data associated with edges must overload
382
this method to ensure capacity in the parallel extension data
383
structures. An extension can return NOTOK if it does not
384
support arc capacity expansion. The extension function will
385
not be called if arcCapacity is expanded before the graph is
386
initialized, and it is assumed that extensions will allocate
387
parallel data structures according to the arc capacity.
388
389
If an extension supports arc capacity expansion, then higher
390
performance can be obtained by using the method of unhooking
391
the initializers for individual edge records before invoking
392
the superclass version of fpEnsureArcCapacity(). Ideally,
393
application authors should ensure the proper arc capacity before
394
attaching extensions to achieve better performance.
395
396
Returns NOTOK on failure to reallocate the edge record array to
397
satisfy the requiredArcCapacity, or if the requested
398
capacity is odd
399
OK if reallocation is not required or if reallocation succeeds
400
********************************************************************/
401
int gp_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)
402
{
403
if (theGraph == NULL || requiredArcCapacity <= 0)
404
return NOTOK;
405
406
// Train callers to only ask for an even number of arcs, since
407
// two are required per edge or directed edge.
408
if (requiredArcCapacity & 1)
409
return NOTOK;
410
411
if (theGraph->arcCapacity >= requiredArcCapacity)
412
return OK;
413
414
// In the special case where gp_InitGraph() has not yet been called,
415
// we can simply set the higher arcCapacity since normal initialization
416
// will then allocate the correct number of edge records.
417
if (theGraph->N == 0)
418
{
419
theGraph->arcCapacity = requiredArcCapacity;
420
return OK;
421
}
422
423
// Try to expand the arc capacity
424
return theGraph->functions.fpEnsureArcCapacity(theGraph, requiredArcCapacity);
425
}
426
427
int _EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)
428
{
429
stackP newStack;
430
int J, Gsize=theGraph->edgeOffset + theGraph->arcCapacity;
431
int newGsize = theGraph->edgeOffset + requiredArcCapacity;
432
433
// Expand theStack
434
if (sp_GetCapacity(theGraph->theStack) < 2 * requiredArcCapacity)
435
{
436
int stackSize = 2 * requiredArcCapacity;
437
438
if (stackSize < 6*theGraph->N)
439
{
440
// NOTE: Since this routine only makes the stack bigger, this
441
// calculation is not needed here because we already ensured
442
// we had stack capacity of the greater of 2*arcs and 6*N
443
// But we do it for clarity and consistency (e.g. so this rule
444
// is not forgotten whenever a "SetArcCapacity" method is added)
445
stackSize = 6*theGraph->N;
446
}
447
448
if ((newStack = sp_New(stackSize)) == NULL)
449
return NOTOK;
450
451
sp_CopyContent(newStack, theGraph->theStack);
452
sp_Free(&theGraph->theStack);
453
theGraph->theStack = newStack;
454
}
455
456
// Expand edgeHoles
457
if ((newStack = sp_New(requiredArcCapacity / 2)) == NULL)
458
return NOTOK;
459
460
sp_CopyContent(newStack, theGraph->edgeHoles);
461
sp_Free(&theGraph->edgeHoles);
462
theGraph->edgeHoles = newStack;
463
464
// Reallocate the GraphNode array to the new size,
465
theGraph->G = (graphNodeP) realloc(theGraph->G, newGsize*sizeof(graphNode));
466
if (theGraph->G == NULL)
467
return NOTOK;
468
469
// Initialize the new edge records
470
for (J = Gsize; J < newGsize; J++)
471
theGraph->functions.fpInitGraphNode(theGraph, J);
472
473
// The new arcCapacity has been successfully achieved
474
theGraph->arcCapacity = requiredArcCapacity;
475
return OK;
476
}
477
478
/********************************************************************
479
_InitGraphNode()
480
Sets the fields in a single graph node structure to initial values
481
********************************************************************/
482
483
void _InitGraphNode(graphP theGraph, int J)
484
{
485
theGraph->G[J].v = NIL;
486
gp_SetPrevArc(theGraph, J, NIL);
487
gp_SetNextArc(theGraph, J, NIL);
488
theGraph->G[J].visited = 0;
489
theGraph->G[J].type = TYPE_UNKNOWN;
490
theGraph->G[J].flags = 0;
491
}
492
493
/********************************************************************
494
_InitVertexRec()
495
Sets the fields in a single vertex record to initial values
496
********************************************************************/
497
498
void _InitVertexRec(graphP theGraph, int I)
499
{
500
gp_SetFirstArc(theGraph, I, gp_AdjacencyListEndMark(I));
501
gp_SetLastArc(theGraph, I, gp_AdjacencyListEndMark(I));
502
theGraph->V[I].leastAncestor =
503
theGraph->V[I].Lowpoint = I;
504
theGraph->V[I].DFSParent = NIL;
505
theGraph->V[I].adjacentTo = NIL;
506
theGraph->V[I].pertinentBicompList = NIL;
507
theGraph->V[I].separatedDFSChildList = NIL;
508
theGraph->V[I].fwdArcList = NIL;
509
}
510
511
/********************************************************************
512
_ClearIsolatorContext()
513
********************************************************************/
514
515
void _ClearIsolatorContext(graphP theGraph)
516
{
517
isolatorContextP IC = &theGraph->IC;
518
519
IC->minorType = 0;
520
IC->v = IC->r = IC->x = IC->y = IC->w = IC->px = IC->py = IC->z =
521
IC->ux = IC->dx = IC->uy = IC->dy = IC->dw = IC->uz = IC->dz = NIL;
522
}
523
524
/********************************************************************
525
_FillVisitedFlags()
526
********************************************************************/
527
528
void _FillVisitedFlags(graphP theGraph, int FillValue)
529
{
530
int i;
531
int limit = theGraph->edgeOffset + 2*(theGraph->M + sp_GetCurrentSize(theGraph->edgeHoles));
532
533
for (i=0; i < limit; i++)
534
theGraph->G[i].visited = FillValue;
535
}
536
537
/********************************************************************
538
_FillVisitedFlagsInBicomp()
539
540
Places the FillValue into the 'visited' members of the vertices and
541
arcs in the bicomp rooted by BicompRoot.
542
543
This method uses the stack but preserves whatever may have been
544
on it. In debug mode, it will return NOTOK if the stack overflows.
545
This method pushes at most one integer per vertex in the bicomp.
546
547
Returns OK on success, NOTOK on implementation failure.
548
********************************************************************/
549
550
int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue)
551
{
552
int V, J;
553
int stackBottom = sp_GetCurrentSize(theGraph->theStack);
554
555
sp_Push(theGraph->theStack, BicompRoot);
556
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
557
{
558
sp_Pop(theGraph->theStack, V);
559
theGraph->G[V].visited = FillValue;
560
561
J = gp_GetFirstArc(theGraph, V);
562
while (gp_IsArc(theGraph, J))
563
{
564
theGraph->G[J].visited = FillValue;
565
566
if (theGraph->G[J].type == EDGE_DFSCHILD)
567
sp_Push(theGraph->theStack, theGraph->G[J].v);
568
569
J = gp_GetNextArc(theGraph, J);
570
}
571
}
572
return OK;
573
}
574
575
/********************************************************************
576
_FillVisitedFlagsInOtherBicomps()
577
Typically, we want to clear or set all visited flags in the graph
578
(see _FillVisitedFlags). However, in some algorithms this would be
579
too costly, so it is necessary to clear or set the visited flags only
580
in one bicomp (see _FillVisitedFlagsInBicomp), then do some processing
581
that sets some of the flags then performs some tests. If the tests
582
are positive, then we can clear or set all the visited flags in the
583
other bicomps (the processing may have set the visited flags in the
584
one bicomp in a particular way that we want to retain, so we skip
585
the given bicomp).
586
********************************************************************/
587
588
int _FillVisitedFlagsInOtherBicomps(graphP theGraph, int BicompRoot, int FillValue)
589
{
590
int R, edgeOffset = theGraph->edgeOffset;
591
592
for (R = theGraph->N; R < edgeOffset; R++)
593
{
594
if (R != BicompRoot && gp_IsArc(theGraph, gp_GetFirstArc(theGraph, R)) )
595
{
596
if (_FillVisitedFlagsInBicomp(theGraph, R, FillValue) != OK)
597
return NOTOK;
598
}
599
}
600
return OK;
601
}
602
603
/********************************************************************
604
_FillVisitedFlagsInUnembeddedEdges()
605
Unembedded edges aren't part of any bicomp yet, but it may be
606
necessary to fill their visited flags, typically with zero.
607
********************************************************************/
608
609
void _FillVisitedFlagsInUnembeddedEdges(graphP theGraph, int FillValue)
610
{
611
int I, J;
612
613
for (I = 0; I < theGraph->N; I++)
614
{
615
J = theGraph->V[I].fwdArcList;
616
while (gp_IsArc(theGraph, J))
617
{
618
theGraph->G[J].visited =
619
theGraph->G[gp_GetTwinArc(theGraph, J)].visited = FillValue;
620
621
J = gp_GetNextArc(theGraph, J);
622
if (J == theGraph->V[I].fwdArcList)
623
J = NIL;
624
}
625
}
626
}
627
628
/********************************************************************
629
_SetVertexTypeInBicomp()
630
631
Sets the 'type' member to theType for each vertex in the bicomp
632
rooted by BicompRoot.
633
634
This method uses the stack but preserves whatever may have been
635
on it. In debug mode, it will return NOTOK if the stack overflows.
636
This method pushes at most one integer per vertex in the bicomp.
637
638
Returns OK on success, NOTOK on implementation failure.
639
********************************************************************/
640
641
int _SetVertexTypeInBicomp(graphP theGraph, int BicompRoot, int theType)
642
{
643
int V, J;
644
int stackBottom = sp_GetCurrentSize(theGraph->theStack);
645
646
sp_Push(theGraph->theStack, BicompRoot);
647
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
648
{
649
sp_Pop(theGraph->theStack, V);
650
theGraph->G[V].type = theType;
651
652
J = gp_GetFirstArc(theGraph, V);
653
while (gp_IsArc(theGraph, J))
654
{
655
if (theGraph->G[J].type == EDGE_DFSCHILD)
656
sp_Push(theGraph->theStack, theGraph->G[J].v);
657
658
J = gp_GetNextArc(theGraph, J);
659
}
660
}
661
return OK;
662
}
663
664
/********************************************************************
665
_ClearGraph()
666
Clears all memory used by the graph, restoring it to the state it
667
was in immediately after gp_New() created it.
668
********************************************************************/
669
670
void _ClearGraph(graphP theGraph)
671
{
672
if (theGraph->G != NULL)
673
{
674
free(theGraph->G);
675
theGraph->G = NULL;
676
}
677
if (theGraph->V != NULL)
678
{
679
free(theGraph->V);
680
theGraph->V = NULL;
681
}
682
683
theGraph->N = theGraph->M = theGraph->edgeOffset = theGraph->arcCapacity = 0;
684
theGraph->internalFlags = theGraph->embedFlags = 0;
685
686
_ClearIsolatorContext(theGraph);
687
688
LCFree(&theGraph->BicompLists);
689
LCFree(&theGraph->DFSChildLists);
690
691
sp_Free(&theGraph->theStack);
692
693
if (theGraph->buckets != NULL)
694
{
695
free(theGraph->buckets);
696
theGraph->buckets = NULL;
697
}
698
699
LCFree(&theGraph->bin);
700
701
if (theGraph->extFace != NULL)
702
{
703
free(theGraph->extFace);
704
theGraph->extFace = NULL;
705
}
706
707
sp_Free(&theGraph->edgeHoles);
708
709
gp_FreeExtensions(theGraph);
710
}
711
712
/********************************************************************
713
gp_Free()
714
Frees G and V, then the graph record. Then sets your pointer to NULL
715
(so you must pass the address of your pointer).
716
********************************************************************/
717
718
void gp_Free(graphP *pGraph)
719
{
720
if (pGraph == NULL) return;
721
if (*pGraph == NULL) return;
722
723
_ClearGraph(*pGraph);
724
725
free(*pGraph);
726
*pGraph = NULL;
727
}
728
729
/********************************************************************
730
gp_CopyGraph()
731
Copies the content of the srcGraph into the dstGraph. The dstGraph
732
must have been previously initialized with the same number of
733
vertices as the srcGraph (e.g. gp_InitGraph(dstGraph, srcGraph->N).
734
735
Returns OK for success, NOTOK for failure.
736
********************************************************************/
737
738
int gp_CopyGraph(graphP dstGraph, graphP srcGraph)
739
{
740
int I, N = srcGraph->N, edgeOffset = srcGraph->edgeOffset;
741
int Gsize = edgeOffset + srcGraph->arcCapacity;
742
743
// Parameter checks
744
if (dstGraph == NULL || srcGraph == NULL)
745
{
746
return NOTOK;
747
}
748
749
// The graphs need to be the same order and initialized
750
if (dstGraph->N != srcGraph->N || dstGraph->N == 0)
751
{
752
return NOTOK;
753
}
754
755
// Ensure dstGraph has the required arc capacity; this expands
756
// dstGraph if needed, but does not contract. An error is only
757
// returned if the expansion fails.
758
if (gp_EnsureArcCapacity(dstGraph, srcGraph->arcCapacity) != OK)
759
{
760
return NOTOK;
761
}
762
763
// Copy the basic GraphNode structures. Augmentations to
764
// the graph node structure created by extensions are copied
765
// below by gp_CopyExtensions()
766
for (I = 0; I < Gsize; I++)
767
dstGraph->G[I] = srcGraph->G[I];
768
769
// Copy the basic VertexRec structures. Augmentations to
770
// the vertex structure created by extensions are copied
771
// below by gp_CopyExtensions()
772
for (I = 0; I < N; I++)
773
dstGraph->V[I] = srcGraph->V[I];
774
775
// Copy the external face array
776
for (I = 0; I < edgeOffset; I++)
777
{
778
dstGraph->extFace[I].vertex[0] = srcGraph->extFace[I].vertex[0];
779
dstGraph->extFace[I].vertex[1] = srcGraph->extFace[I].vertex[1];
780
dstGraph->extFace[I].inversionFlag = srcGraph->extFace[I].inversionFlag;
781
}
782
783
// Give the dstGraph the same size and intrinsic properties
784
dstGraph->N = srcGraph->N;
785
dstGraph->M = srcGraph->M;
786
dstGraph->edgeOffset = srcGraph->edgeOffset;
787
dstGraph->internalFlags = srcGraph->internalFlags;
788
dstGraph->embedFlags = srcGraph->embedFlags;
789
790
dstGraph->IC = srcGraph->IC;
791
792
LCCopy(dstGraph->BicompLists, srcGraph->BicompLists);
793
LCCopy(dstGraph->DFSChildLists, srcGraph->DFSChildLists);
794
sp_Copy(dstGraph->theStack, srcGraph->theStack);
795
sp_Copy(dstGraph->edgeHoles, srcGraph->edgeHoles);
796
797
// Copy the set of extensions, which includes copying the
798
// extension data as well as the function overload tables
799
if (gp_CopyExtensions(dstGraph, srcGraph) != OK)
800
return NOTOK;
801
802
// Copy the graph's function table, which has the pointers to
803
// the most recent extension overloads of each function (or
804
// the original function pointer if a particular function has
805
// not been overloaded).
806
// This must be done after copying the extension because the
807
// first step of copying the extensions is to delete the
808
// dstGraph extensions, which clears its function table.
809
// Therefore, no good to assign the srcGraph functions *before*
810
// copying the extensions because the assignment would be wiped out
811
// This, in turn, means that the DupContext function of an extension
812
// *cannot* depend on any extension function overloads; the extension
813
// must directly invoke extension functions only.
814
dstGraph->functions = srcGraph->functions;
815
816
return OK;
817
}
818
819
/********************************************************************
820
gp_DupGraph()
821
********************************************************************/
822
823
graphP gp_DupGraph(graphP theGraph)
824
{
825
graphP result;
826
827
if ((result = gp_New()) == NULL) return NULL;
828
829
if (gp_InitGraph(result, theGraph->N) != OK ||
830
gp_CopyGraph(result, theGraph) != OK)
831
{
832
gp_Free(&result);
833
return NULL;
834
}
835
836
return result;
837
}
838
839
/********************************************************************
840
gp_CreateRandomGraph()
841
842
Creates a randomly generated graph. First a tree is created by
843
connecting each vertex to some successor. Then a random number of
844
additional random edges are added. If an edge already exists, then
845
we retry until a non-existent edge is picked.
846
847
This function assumes the caller has already called srand().
848
849
Returns OK on success, NOTOK on failure
850
********************************************************************/
851
852
int gp_CreateRandomGraph(graphP theGraph)
853
{
854
int N, I, M, u, v;
855
856
N = theGraph->N;
857
858
/* Generate a random tree; note that this method virtually guarantees
859
that the graph will be renumbered, but it is linear time.
860
Also, we are not generating the DFS tree but rather a tree
861
that simply ensures the resulting random graph is connected. */
862
863
for (I=1; I < N; I++)
864
if (gp_AddEdge(theGraph, _GetRandomNumber(0, I-1), 0, I, 0) != OK)
865
return NOTOK;
866
867
/* Generate a random number of additional edges
868
(actually, leave open a small chance that no
869
additional edges will be added). */
870
871
M = _GetRandomNumber(7*N/8, theGraph->arcCapacity/2);
872
873
if (M > N*(N-1)/2) M = N*(N-1)/2;
874
875
for (I=N-1; I<M; I++)
876
{
877
u = _GetRandomNumber(0, N-2);
878
v = _GetRandomNumber(u+1, N-1);
879
880
if (gp_IsNeighbor(theGraph, u, v))
881
I--;
882
else
883
{
884
if (gp_AddEdge(theGraph, u, 0, v, 0) != OK)
885
return NOTOK;
886
}
887
}
888
889
return OK;
890
}
891
892
/********************************************************************
893
_GetRandomNumber()
894
This function generates a random number between NMin and NMax
895
inclusive. It assumes that the caller has called srand().
896
It calls rand(), but before truncating to the proper range,
897
it adds the high bits of the rand() result into the low bits.
898
The result of this is that the randomness appearing in the
899
truncated bits also has an affect on the non-truncated bits.
900
I used the same technique to improve the spread of hashing functions
901
in my Jan.98 Dr. Dobb's Journal article "Resizable Data Structures".
902
********************************************************************/
903
904
int _GetRandomNumber(int NMin, int NMax)
905
{
906
int N = rand();
907
908
if (NMax < NMin) return NMin;
909
910
N += ((N&0xFFFF0000)>>16);
911
N += ((N&0x0000FF00)>>8);
912
N &= 0x7FFFFFF;
913
N %= (NMax-NMin+1);
914
return N+NMin;
915
}
916
917
/********************************************************************
918
_getUnprocessedChild()
919
Support routine for gp_Create RandomGraphEx(), this function
920
obtains a child of the given vertex in the randomly generated
921
tree that has not yet been processed. NIL is returned if the
922
given vertex has no unprocessed children
923
924
********************************************************************/
925
926
int _getUnprocessedChild(graphP theGraph, int parent)
927
{
928
int J = gp_GetFirstArc(theGraph, parent);
929
int JTwin = gp_GetTwinArc(theGraph, J);
930
int child = theGraph->G[J].v;
931
932
// The tree edges were added to the beginning of the adjacency list,
933
// and we move processed tree edge records to the end of the list,
934
// so if the immediate next arc (edge record) is not a tree edge
935
// then we return NIL because the vertex has no remaining
936
// unprocessed children
937
if (theGraph->G[J].type == TYPE_UNKNOWN)
938
return NIL;
939
940
// If the child has already been processed, then all children
941
// have been pushed to the end of the list, and we have just
942
// encountered the first child we processed, so there are no
943
// remaining unprocessed children */
944
if (theGraph->G[J].visited)
945
return NIL;
946
947
// We have found an edge leading to an unprocessed child, so
948
// we mark it as processed so that it doesn't get returned
949
// again in future iterations.
950
theGraph->G[J].visited = 1;
951
theGraph->G[JTwin].visited = 1;
952
953
// Now we move the edge record in the parent vertex to the end
954
// of the adjacency list of that vertex.
955
gp_MoveArcToLast(theGraph, parent, J);
956
957
// Now we move the edge record in the child vertex to the
958
// end of the adjacency list of the child.
959
gp_MoveArcToLast(theGraph, child, JTwin);
960
961
// Now we set the child's parent and return the child.
962
theGraph->V[child].DFSParent = parent;
963
964
return child;
965
}
966
967
/********************************************************************
968
_hasUnprocessedChild()
969
Support routine for gp_Create RandomGraphEx(), this function
970
obtains a child of the given vertex in the randomly generated
971
tree that has not yet been processed. False (0) is returned
972
unless the given vertex has an unprocessed child.
973
********************************************************************/
974
975
int _hasUnprocessedChild(graphP theGraph, int parent)
976
{
977
int J = gp_GetFirstArc(theGraph, parent);
978
979
if (theGraph->G[J].type == TYPE_UNKNOWN)
980
return 0;
981
982
if (theGraph->G[J].visited)
983
return 0;
984
985
return 1;
986
}
987
988
/********************************************************************
989
gp_CreateRandomGraphEx()
990
Given a graph structure with a pre-specified number of vertices N,
991
this function creates a graph with the specified number of edges.
992
993
If numEdges <= 3N-6, then the graph generated is planar. If
994
numEdges is larger, then a maximal planar graph is generated, then
995
(numEdges - 3N + 6) additional random edges are added.
996
997
This function assumes the caller has already called srand().
998
********************************************************************/
999
1000
int gp_CreateRandomGraphEx(graphP theGraph, int numEdges)
1001
{
1002
#define EDGE_TREE_RANDOMGEN (TYPE_UNKNOWN+1)
1003
1004
int N, I, arc, M, root, v, c, p, last, u, J, e;
1005
1006
N = theGraph->N;
1007
1008
if (numEdges > theGraph->arcCapacity/2)
1009
numEdges = theGraph->arcCapacity/2;
1010
1011
/* Generate a random tree. */
1012
1013
for (I=1; I < N; I++)
1014
{
1015
v = _GetRandomNumber(0, I-1);
1016
if (gp_AddEdge(theGraph, v, 0, I, 0) != OK)
1017
return NOTOK;
1018
1019
else
1020
{
1021
arc = theGraph->edgeOffset + 2*theGraph->M - 2;
1022
theGraph->G[arc].type = EDGE_TREE_RANDOMGEN;
1023
theGraph->G[gp_GetTwinArc(theGraph, arc)].type = EDGE_TREE_RANDOMGEN;
1024
theGraph->G[arc].visited = 0;
1025
theGraph->G[gp_GetTwinArc(theGraph, arc)].visited = 0;
1026
}
1027
}
1028
1029
/* Add edges up to the limit or until the graph is maximal planar. */
1030
1031
M = numEdges <= 3*N - 6 ? numEdges : 3*N - 6;
1032
1033
root = 0;
1034
v = last = _getUnprocessedChild(theGraph, root);
1035
1036
while (v != root && theGraph->M < M)
1037
{
1038
c = _getUnprocessedChild(theGraph, v);
1039
1040
if (c != NIL)
1041
{
1042
if (last != v)
1043
{
1044
if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)
1045
return NOTOK;
1046
}
1047
1048
if (gp_AddEdge(theGraph, root, 1, c, 1) != OK)
1049
return NOTOK;
1050
1051
v = last = c;
1052
}
1053
1054
else
1055
{
1056
p = theGraph->V[v].DFSParent;
1057
while (p != NIL && (c = _getUnprocessedChild(theGraph, p)) == NIL)
1058
{
1059
v = p;
1060
p = theGraph->V[v].DFSParent;
1061
if (p != NIL && p != root)
1062
{
1063
if (gp_AddEdge(theGraph, last, 1, p, 1) != OK)
1064
return NOTOK;
1065
}
1066
}
1067
1068
if (p != NIL)
1069
{
1070
if (p == root)
1071
{
1072
if (gp_AddEdge(theGraph, v, 1, c, 1) != OK)
1073
return NOTOK;
1074
1075
if (v != last)
1076
{
1077
if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)
1078
return NOTOK;
1079
}
1080
}
1081
else
1082
{
1083
if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)
1084
return NOTOK;
1085
}
1086
1087
if (p != root)
1088
{
1089
if (gp_AddEdge(theGraph, root, 1, c, 1) != OK)
1090
return NOTOK;
1091
last = c;
1092
}
1093
1094
v = c;
1095
}
1096
}
1097
}
1098
1099
/* Add additional edges if the limit has not yet been reached. */
1100
1101
while (theGraph->M < numEdges)
1102
{
1103
u = _GetRandomNumber(0, N-1);
1104
v = _GetRandomNumber(0, N-1);
1105
1106
if (u != v && !gp_IsNeighbor(theGraph, u, v))
1107
if (gp_AddEdge(theGraph, u, 0, v, 0) != OK)
1108
return NOTOK;
1109
}
1110
1111
/* Clear the edge types back to 'unknown' */
1112
1113
for (e = 0; e < numEdges; e++)
1114
{
1115
J = theGraph->edgeOffset + 2*e;
1116
theGraph->G[J].type = TYPE_UNKNOWN;
1117
theGraph->G[gp_GetTwinArc(theGraph, J)].type = TYPE_UNKNOWN;
1118
theGraph->G[J].visited = 0;
1119
theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 0;
1120
}
1121
1122
/* Put all DFSParent indicators back to NIL */
1123
1124
for (I = 0; I < N; I++)
1125
theGraph->V[I].DFSParent = NIL;
1126
1127
return OK;
1128
1129
#undef EDGE_TREE_RANDOMGEN
1130
}
1131
1132
/********************************************************************
1133
gp_SetDirection()
1134
Behavior depends on edgeFlag_Direction (EDGEFLAG_DIRECTION_INONLY,
1135
EDGEFLAG_DIRECTION_OUTONLY, or 0).
1136
A direction of 0 clears directedness. Otherwise, edge record e is set
1137
to edgeFlag_Direction and e's twin arc is set to the opposing setting.
1138
********************************************************************/
1139
1140
void gp_SetDirection(graphP theGraph, int e, int edgeFlag_Direction)
1141
{
1142
int eTwin = gp_GetTwinArc(theGraph, e);
1143
1144
if (edgeFlag_Direction == EDGEFLAG_DIRECTION_INONLY)
1145
{
1146
theGraph->G[e].flags |= EDGEFLAG_DIRECTION_INONLY;
1147
theGraph->G[eTwin].flags |= EDGEFLAG_DIRECTION_OUTONLY;
1148
}
1149
else if (edgeFlag_Direction == EDGEFLAG_DIRECTION_OUTONLY)
1150
{
1151
theGraph->G[e].flags |= EDGEFLAG_DIRECTION_OUTONLY;
1152
theGraph->G[eTwin].flags |= EDGEFLAG_DIRECTION_INONLY;
1153
}
1154
else
1155
{
1156
theGraph->G[e].flags &= ~(EDGEFLAG_DIRECTION_INONLY|EDGEFLAG_DIRECTION_OUTONLY);
1157
theGraph->G[eTwin].flags &= ~(EDGEFLAG_DIRECTION_INONLY|EDGEFLAG_DIRECTION_OUTONLY);
1158
}
1159
}
1160
1161
/********************************************************************
1162
gp_IsNeighbor()
1163
1164
Checks whether v is already in u's adjacency list, i.e. does the arc
1165
u -> v exist.
1166
If there is an edge record for v in u's list, but it is marked INONLY,
1167
then it represents the arc v->u but not u->v, so it is ignored.
1168
1169
Returns TRUE or FALSE.
1170
********************************************************************/
1171
1172
int gp_IsNeighbor(graphP theGraph, int u, int v)
1173
{
1174
int J;
1175
1176
J = gp_GetFirstArc(theGraph, u);
1177
while (gp_IsArc(theGraph, J))
1178
{
1179
if (theGraph->G[J].v == v)
1180
{
1181
if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY))
1182
return TRUE;
1183
}
1184
J = gp_GetNextArc(theGraph, J);
1185
}
1186
return FALSE;
1187
}
1188
1189
/********************************************************************
1190
gp_GetNeighborEdgeRecord()
1191
Searches the adjacency list of u to obtains the edge record for v.
1192
1193
NOTE: The caller should check whether the edge record is INONLY;
1194
This method returns any edge record representing a connection
1195
between vertices u and v, so this method can return an
1196
edge record even if gp_IsNeighbor(theGraph, u, v) is false (0).
1197
To filter out INONLY edge records, use gp_GetDirection() on
1198
the edge record returned by this method.
1199
1200
Returns NIL if there is no edge record indicating v in u's adjacency
1201
list, or the edge record location otherwise.
1202
********************************************************************/
1203
1204
int gp_GetNeighborEdgeRecord(graphP theGraph, int u, int v)
1205
{
1206
int J;
1207
1208
if (u == NIL || v == NIL)
1209
return NIL + NOTOK;
1210
1211
J = gp_GetFirstArc(theGraph, u);
1212
while (gp_IsArc(theGraph, J))
1213
{
1214
if (theGraph->G[J].v == v)
1215
return J;
1216
1217
J = gp_GetNextArc(theGraph, J);
1218
}
1219
return NIL;
1220
}
1221
1222
/********************************************************************
1223
gp_GetVertexDegree()
1224
1225
Counts the number of edge records in the adjacency list of a given
1226
vertex V. The while loop condition is 2N or higher because our
1227
data structure keeps records at locations 0 to N-1 for vertices
1228
AND N to 2N-1 for copies of vertices. So edge records are stored
1229
at locations 2N and above.
1230
1231
Note: For digraphs, this method returns the total degree of the
1232
vertex, including outward arcs (undirected and OUTONLY)
1233
as well as INONLY arcs. Other functions are defined to get
1234
the in-degree or out-degree of the vertex.
1235
1236
Note: This function determines the degree by counting. An extension
1237
could cache the degree value of each vertex and update the
1238
cached value as edges are added and deleted.
1239
********************************************************************/
1240
1241
int gp_GetVertexDegree(graphP theGraph, int v)
1242
{
1243
int J, degree;
1244
1245
if (theGraph==NULL || v==NIL)
1246
return NOTOK;
1247
1248
degree = 0;
1249
1250
J = gp_GetFirstArc(theGraph, v);
1251
while (gp_IsArc(theGraph, J))
1252
{
1253
degree++;
1254
J = gp_GetNextArc(theGraph, J);
1255
}
1256
1257
return degree;
1258
}
1259
1260
/********************************************************************
1261
gp_GetVertexInDegree()
1262
1263
Counts the number of edge records in the adjacency list of a given
1264
vertex V that represent arcs from another vertex into V.
1265
This includes undirected edges and INONLY arcs, so it only excludes
1266
edges records that are marked as OUTONLY arcs.
1267
1268
Note: This function determines the in-degree by counting. An extension
1269
could cache the in-degree value of each vertex and update the
1270
cached value as edges are added and deleted.
1271
********************************************************************/
1272
1273
int gp_GetVertexInDegree(graphP theGraph, int v)
1274
{
1275
int J, degree;
1276
1277
if (theGraph==NULL || v==NIL)
1278
return NOTOK;
1279
1280
degree = 0;
1281
1282
J = gp_GetFirstArc(theGraph, v);
1283
while (gp_IsArc(theGraph, J))
1284
{
1285
if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_OUTONLY))
1286
degree++;
1287
J = gp_GetNextArc(theGraph, J);
1288
}
1289
1290
return degree;
1291
}
1292
1293
/********************************************************************
1294
gp_GetVertexOutDegree()
1295
1296
Counts the number of edge records in the adjacency list of a given
1297
vertex V that represent arcs from V to another vertex.
1298
This includes undirected edges and OUTONLY arcs, so it only excludes
1299
edges records that are marked as INONLY arcs.
1300
1301
Note: This function determines the out-degree by counting. An extension
1302
could cache the out-degree value of each vertex and update the
1303
cached value as edges are added and deleted.
1304
********************************************************************/
1305
1306
int gp_GetVertexOutDegree(graphP theGraph, int v)
1307
{
1308
int J, degree;
1309
1310
if (theGraph==NULL || v==NIL)
1311
return NOTOK;
1312
1313
degree = 0;
1314
1315
J = gp_GetFirstArc(theGraph, v);
1316
while (gp_IsArc(theGraph, J))
1317
{
1318
if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY))
1319
degree++;
1320
J = gp_GetNextArc(theGraph, J);
1321
}
1322
1323
return degree;
1324
}
1325
1326
/********************************************************************
1327
gp_AttachArc()
1328
1329
This routine adds newArc into v's adjacency list at a position
1330
adjacent to the edge record for e, either before or after e,
1331
depending on link. If e is not an arc (e.g. if e is NIL),
1332
then link is assumed to indicate whether the new arc is to be
1333
placed at the beginning or end of v's adjacency list.
1334
1335
NOTE: The caller can pass NIL for v if e is not NIL, since the
1336
vertex is implied (theGraph->G[eTwin].v)
1337
1338
The arc is assumed to already exist in the data structure (i.e.
1339
the storage of edges), as only a whole edge (two arcs) can be
1340
inserted into or deleted from the data structure. Hence there is
1341
no such thing as gp_InsertArc() or gp_DeleteArc().
1342
1343
See also gp_DetachArc(), gp_InsertEdge() and gp_DeleteEdge()
1344
********************************************************************/
1345
1346
void gp_AttachArc(graphP theGraph, int v, int e, int link, int newArc)
1347
{
1348
if (gp_IsArc(theGraph, e))
1349
{
1350
int e2 = gp_GetAdjacentArc(theGraph, e, link);
1351
1352
// e's link is newArc, and newArc's 1^link is e
1353
gp_SetAdjacentArc(theGraph, e, link, newArc);
1354
gp_SetAdjacentArc(theGraph, newArc, 1^link, e);
1355
1356
// newArcs's link is e2
1357
gp_SetAdjacentArc(theGraph, newArc, link, e2);
1358
1359
// if e2 is an arc, then e2's 1^link is newArc, else v's 1^link is newArc
1360
if (gp_IsArc(theGraph, e2))
1361
gp_SetAdjacentArc(theGraph, e2, 1^link, newArc);
1362
else
1363
gp_SetArc(theGraph, v, 1^link, newArc);
1364
}
1365
else
1366
{
1367
int e2 = gp_GetArc(theGraph, v, link);
1368
1369
// v's link is newArc, and newArc's 1^link is gp_AdjacencyListEndMark(v)
1370
gp_SetArc(theGraph, v, link, newArc);
1371
gp_SetAdjacentArc(theGraph, newArc, 1^link, gp_AdjacencyListEndMark(v));
1372
1373
// newArcs's elink is e2
1374
gp_SetAdjacentArc(theGraph, newArc, link, e2);
1375
1376
// if e2 is an arc, then e2's 1^link is newArc, else v's 1^link is newArc
1377
if (gp_IsArc(theGraph, e2))
1378
gp_SetAdjacentArc(theGraph, e2, 1^link, newArc);
1379
else
1380
gp_SetArc(theGraph, v, 1^link, newArc);
1381
}
1382
}
1383
1384
/****************************************************************************
1385
gp_DetachArc()
1386
1387
This routine detaches arc from its adjacency list, but it does not delete
1388
it from the data structure (only a whole edge can be deleted).
1389
1390
Some algorithms must temporarily detach an edge, perform some calculation,
1391
and eventually put the edge back. This routine supports that operation.
1392
The neighboring adjacency list nodes are cross-linked, but the two link
1393
members of the arc are retained, so the arc can be reattached later by
1394
invoking _RestoreArc(). A sequence of detached arcs can only be restored
1395
in the exact opposite order of their detachment. Thus, algorithms do not
1396
directly use this method to implement the temporary detach/restore method.
1397
Instead, gp_HideEdge() and gp_RestoreEdge are used, and algorithms push
1398
edge hidden edge onto the stack. One example of this stack usage is
1399
provided by detaching edges with gp_ContractEdge() or gp_IdentifyVertices(),
1400
and reattaching with gp_RestoreIdentifications(), which unwinds the stack
1401
by invoking gp_RestoreVertex().
1402
****************************************************************************/
1403
1404
void gp_DetachArc(graphP theGraph, int arc)
1405
{
1406
int nextArc = gp_GetNextArc(theGraph, arc),
1407
prevArc = gp_GetPrevArc(theGraph, arc);
1408
1409
if (gp_IsArc(theGraph, nextArc))
1410
gp_SetPrevArc(theGraph, nextArc, prevArc);
1411
else
1412
gp_SetLastArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, prevArc);
1413
1414
if (gp_IsArc(theGraph, prevArc))
1415
gp_SetNextArc(theGraph, prevArc, nextArc);
1416
else
1417
gp_SetFirstArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, nextArc);
1418
}
1419
1420
/********************************************************************
1421
gp_AddEdge()
1422
Adds the undirected edge (u,v) to the graph by placing edge records
1423
representing u into v's circular edge record list and v into u's
1424
circular edge record list.
1425
1426
upos receives the location in G where the u record in v's list will be
1427
placed, and vpos is the location in G of the v record we placed in
1428
u's list. These are used to initialize the short circuit links.
1429
1430
ulink (0|1) indicates whether the edge record to v in u's list should
1431
become adjacent to u by its 0 or 1 link, i.e. u[ulink] == vpos.
1432
vlink (0|1) indicates whether the edge record to u in v's list should
1433
become adjacent to v by its 0 or 1 link, i.e. v[vlink] == upos.
1434
1435
********************************************************************/
1436
1437
int gp_AddEdge(graphP theGraph, int u, int ulink, int v, int vlink)
1438
{
1439
int upos, vpos;
1440
1441
if (theGraph==NULL || u<0 || v<0 ||
1442
u>=2*theGraph->N || v>=2*theGraph->N)
1443
return NOTOK;
1444
1445
/* We enforce the edge limit */
1446
1447
if (theGraph->M >= theGraph->arcCapacity/2)
1448
return NONEMBEDDABLE;
1449
1450
if (sp_NonEmpty(theGraph->edgeHoles))
1451
{
1452
sp_Pop(theGraph->edgeHoles, vpos);
1453
}
1454
else
1455
vpos = theGraph->edgeOffset + 2*theGraph->M;
1456
1457
upos = gp_GetTwinArc(theGraph, vpos);
1458
1459
theGraph->G[upos].v = v;
1460
gp_AttachArc(theGraph, u, NIL, ulink, upos);
1461
theGraph->G[vpos].v = u;
1462
gp_AttachArc(theGraph, v, NIL, vlink, vpos);
1463
1464
theGraph->M++;
1465
return OK;
1466
}
1467
1468
/********************************************************************
1469
gp_InsertEdge()
1470
1471
This function adds the edge (u, v) such that the edge record added
1472
to the adjacency list of u is adjacent to e_u and the edge record
1473
added to the adjacency list of v is adjacent to e_v.
1474
The direction of adjacency is given by e_ulink for e_u and e_vlink
1475
for e_v. Specifically, the new edge will be comprised of two arcs,
1476
n_u and n_v. In u's (v's) adjacency list, n_u (n_v) will be added
1477
so that it is indicated by e_u's (e_v's) e_ulink (e_vlink).
1478
If e_u (or e_v) is not an arc, then e_ulink (e_vlink) indicates
1479
whether to prepend or append to the adjacency list for u (v).
1480
********************************************************************/
1481
1482
int gp_InsertEdge(graphP theGraph, int u, int e_u, int e_ulink,
1483
int v, int e_v, int e_vlink)
1484
{
1485
int vertMax = 2*theGraph->N - 1,
1486
edgeMax = theGraph->edgeOffset + 2*theGraph->M + 2*sp_GetCurrentSize(theGraph->edgeHoles) - 1,
1487
upos, vpos;
1488
1489
if (theGraph==NULL || u<0 || v<0 || u>vertMax || v>vertMax ||
1490
e_u>edgeMax || (e_u<theGraph->edgeOffset && e_u != gp_AdjacencyListEndMark(u)) ||
1491
e_v>edgeMax || (e_v<theGraph->edgeOffset && e_v != gp_AdjacencyListEndMark(v)) ||
1492
e_ulink<0 || e_ulink>1 || e_vlink<0 || e_vlink>1)
1493
return NOTOK;
1494
1495
if (theGraph->M >= theGraph->arcCapacity/2)
1496
return NONEMBEDDABLE;
1497
1498
if (sp_NonEmpty(theGraph->edgeHoles))
1499
{
1500
sp_Pop(theGraph->edgeHoles, vpos);
1501
}
1502
else
1503
vpos = theGraph->edgeOffset + 2*theGraph->M;
1504
1505
upos = gp_GetTwinArc(theGraph, vpos);
1506
1507
theGraph->G[upos].v = v;
1508
gp_AttachArc(theGraph, u, e_u, e_ulink, upos);
1509
1510
theGraph->G[vpos].v = u;
1511
gp_AttachArc(theGraph, v, e_v, e_vlink, vpos);
1512
1513
theGraph->M++;
1514
1515
return OK;
1516
}
1517
1518
/****************************************************************************
1519
gp_DeleteEdge()
1520
1521
This function deletes the given edge record e and its twin, reducing the
1522
number of edges M in the graph.
1523
Before the e^th record is deleted, its 'nextLink' adjacency list neighbor
1524
is collected as the return result. This is useful when iterating through
1525
an edge list and making deletions because the nextLink arc is the 'next'
1526
arc in the iteration, but it is hard to obtain *after* deleting e.
1527
****************************************************************************/
1528
1529
int gp_DeleteEdge(graphP theGraph, int e, int nextLink)
1530
{
1531
int eTwin = gp_GetTwinArc(theGraph, e);
1532
int M = theGraph->M;
1533
int nextArc, JPos, MPos;
1534
1535
/* Calculate the nextArc after e so that, when e is deleted, the return result
1536
informs a calling loop of the next edge to be processed. */
1537
1538
nextArc = gp_GetAdjacentArc(theGraph, e, nextLink);
1539
1540
/* Delete the edge records J and JTwin from their adjacency lists. */
1541
1542
gp_DetachArc(theGraph, e);
1543
gp_DetachArc(theGraph, eTwin);
1544
1545
/* Clear the edge record contents */
1546
1547
theGraph->functions.fpInitGraphNode(theGraph, e);
1548
theGraph->functions.fpInitGraphNode(theGraph, eTwin);
1549
1550
/* If records e and eTwin are not the last in the edge record array, then
1551
we want to record a new hole in the edge array. */
1552
1553
JPos = (e < eTwin ? e : eTwin);
1554
MPos = theGraph->edgeOffset + 2*(M-1) + 2*sp_GetCurrentSize(theGraph->edgeHoles);
1555
1556
if (JPos < MPos)
1557
{
1558
sp_Push(theGraph->edgeHoles, JPos);
1559
}
1560
1561
/* Now we reduce the number of edges in the data structure, and then
1562
return the previously calculated successor of J. */
1563
1564
theGraph->M--;
1565
return nextArc;
1566
}
1567
1568
/********************************************************************
1569
_RestoreArc()
1570
This routine reinserts an arc into the edge list from which it
1571
was previously removed by gp_DetachArc().
1572
1573
The assumed processing model is that arcs will be restored in reverse
1574
of the order in which they were hidden, i.e. it is assumed that the
1575
hidden arcs will be pushed on a stack and the arcs will be popped
1576
from the stack for restoration.
1577
********************************************************************/
1578
1579
void _RestoreArc(graphP theGraph, int arc)
1580
{
1581
int nextArc = gp_GetNextArc(theGraph, arc),
1582
prevArc = gp_GetPrevArc(theGraph, arc);
1583
1584
if (gp_IsArc(theGraph, nextArc))
1585
gp_SetPrevArc(theGraph, nextArc, arc);
1586
else
1587
gp_SetLastArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, arc);
1588
1589
if (gp_IsArc(theGraph, prevArc))
1590
gp_SetNextArc(theGraph, prevArc, arc);
1591
else
1592
gp_SetFirstArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, arc);
1593
}
1594
1595
/********************************************************************
1596
gp_HideEdge()
1597
This routine removes the two arcs of an edge from the adjacency lists
1598
of its endpoint vertices, but does not delete them from the storage
1599
data structure.
1600
1601
Many algorithms must temporarily remove an edge, perform some
1602
calculation, and eventually put the edge back. This routine supports
1603
that operation.
1604
1605
For each arc, the neighboring adjacency list nodes are cross-linked,
1606
but the links in the arc are retained because they indicate the
1607
neighbor arcs to which the arc can be reattached by gp_RestoreEdge().
1608
********************************************************************/
1609
1610
void gp_HideEdge(graphP theGraph, int e)
1611
{
1612
theGraph->functions.fpHideEdge(theGraph, e);
1613
}
1614
1615
void _HideEdge(graphP theGraph, int e)
1616
{
1617
gp_DetachArc(theGraph, e);
1618
gp_DetachArc(theGraph, gp_GetTwinArc(theGraph, e));
1619
}
1620
1621
/********************************************************************
1622
gp_RestoreEdge()
1623
This routine reinserts two two arcs of an edge into the adjacency
1624
lists of the edge's endpoints, the arcs having been previously
1625
removed by gp_HideEdge().
1626
1627
The assumed processing model is that edges will be restored in
1628
reverse of the order in which they were hidden, i.e. it is assumed
1629
that the hidden edges will be pushed on a stack and the edges will
1630
be popped from the stack for restoration.
1631
1632
Note: Since both arcs of an edge are restored, only one arc need
1633
be pushed on the stack for restoration. This routine
1634
restores the two arcs in the opposite order from the order
1635
in which they are hidden by gp_HideEdge().
1636
********************************************************************/
1637
1638
void gp_RestoreEdge(graphP theGraph, int e)
1639
{
1640
theGraph->functions.fpRestoreEdge(theGraph, e);
1641
}
1642
1643
void _RestoreEdge(graphP theGraph, int e)
1644
{
1645
_RestoreArc(theGraph, gp_GetTwinArc(theGraph, e));
1646
_RestoreArc(theGraph, e);
1647
}
1648
1649
/********************************************************************
1650
_HideInternalEdges()
1651
Pushes onto the graph's stack and hides all arc nodes of the vertex
1652
except the first and last arcs in the adjacency list of the vertex.
1653
This method is typically called on a vertex that is on the external
1654
face of a biconnected component, because the first and last arcs are
1655
the ones that attach the vertex to the external face cycle, and any
1656
other arcs in the adjacency list are inside that cycle.
1657
1658
This method uses the stack. The caller is expected to clear the stack
1659
or save the stack size before invocation, since the stack size is
1660
needed to _RestoreInternalEdges().
1661
********************************************************************/
1662
1663
int _HideInternalEdges(graphP theGraph, int vertex)
1664
{
1665
int J = gp_GetFirstArc(theGraph, vertex);
1666
1667
// If the vertex adjacency list is empty or if it contains
1668
// only one edge, then there are no *internal* edges to hide
1669
if (J == gp_GetLastArc(theGraph, vertex))
1670
return OK;
1671
1672
// Start with the first internal edge
1673
J = gp_GetNextArc(theGraph, J);
1674
1675
// Cycle through all the edges, pushing each except stop
1676
// before pushing the last edge, which is not internal
1677
while (J != gp_GetLastArc(theGraph, vertex))
1678
{
1679
sp_Push(theGraph->theStack, J);
1680
gp_HideEdge(theGraph, J);
1681
J = gp_GetNextArc(theGraph, J);
1682
}
1683
1684
return OK;
1685
}
1686
1687
/********************************************************************
1688
_RestoreInternalEdges()
1689
Reverses the effects of _HideInternalEdges()
1690
********************************************************************/
1691
1692
int _RestoreInternalEdges(graphP theGraph, int stackBottom)
1693
{
1694
return _RestoreHiddenEdges(theGraph, stackBottom);
1695
}
1696
1697
/********************************************************************
1698
_RestoreHiddenEdges()
1699
1700
Each entry on the stack, down to stackBottom, is assumed to be an
1701
edge record (arc) pushed in concert with invoking gp_HideEdge().
1702
Each edge is restored using gp_RestoreEdge() in exact reverse of the
1703
hiding order. The stack is reduced in size to stackBottom.
1704
1705
Returns OK on success, NOTOK on internal failure.
1706
********************************************************************/
1707
1708
int _RestoreHiddenEdges(graphP theGraph, int stackBottom)
1709
{
1710
int e;
1711
1712
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
1713
{
1714
sp_Pop(theGraph->theStack, e);
1715
if (!gp_IsArc(theGraph, e))
1716
return NOTOK;
1717
gp_RestoreEdge(theGraph, e);
1718
}
1719
1720
return OK;
1721
}
1722
1723
/********************************************************************
1724
gp_HideVertex()
1725
1726
Pushes onto the graph's stack and hides all arc nodes of the vertex.
1727
Additional integers are then pushed so that the result is reversible
1728
by gp_RestoreVertex(). See that method for details on the expected
1729
stack segment.
1730
1731
Returns OK for success, NOTOK for internal failure.
1732
********************************************************************/
1733
1734
int gp_HideVertex(graphP theGraph, int vertex)
1735
{
1736
if (vertex == NIL)
1737
return NOTOK;
1738
1739
return theGraph->functions.fpHideVertex(theGraph, vertex);
1740
}
1741
1742
int _HideVertex(graphP theGraph, int vertex)
1743
{
1744
int hiddenEdgeStackBottom = sp_GetCurrentSize(theGraph->theStack);
1745
int J = gp_GetFirstArc(theGraph, vertex);
1746
1747
// Cycle through all the edges, pushing and hiding each
1748
while (gp_IsArc(theGraph, J))
1749
{
1750
sp_Push(theGraph->theStack, J);
1751
gp_HideEdge(theGraph, J);
1752
J = gp_GetNextArc(theGraph, J);
1753
}
1754
1755
// Push the additional integers needed by gp_RestoreVertex()
1756
sp_Push(theGraph->theStack, hiddenEdgeStackBottom);
1757
sp_Push(theGraph->theStack, NIL);
1758
sp_Push(theGraph->theStack, NIL);
1759
sp_Push(theGraph->theStack, NIL);
1760
sp_Push(theGraph->theStack, NIL);
1761
sp_Push(theGraph->theStack, NIL);
1762
sp_Push(theGraph->theStack, vertex);
1763
1764
return OK;
1765
}
1766
1767
/********************************************************************
1768
gp_ContractEdge()
1769
1770
Contracts the edge e=(u,v). This hides the edge (both e and its
1771
twin arc), and it also identifies vertex v with u.
1772
See gp_IdentifyVertices() for further details.
1773
1774
Returns OK for success, NOTOK for internal failure.
1775
********************************************************************/
1776
1777
int gp_ContractEdge(graphP theGraph, int e)
1778
{
1779
if (!gp_IsArc(theGraph, e))
1780
return NOTOK;
1781
1782
return theGraph->functions.fpContractEdge(theGraph, e);
1783
}
1784
1785
int _ContractEdge(graphP theGraph, int e)
1786
{
1787
int eBefore, u, v;
1788
1789
if (!gp_IsArc(theGraph, e))
1790
return NOTOK;
1791
1792
u = theGraph->G[gp_GetTwinArc(theGraph, e)].v;
1793
v = theGraph->G[e].v;
1794
1795
eBefore = gp_GetNextArc(theGraph, e);
1796
sp_Push(theGraph->theStack, e);
1797
gp_HideEdge(theGraph, e);
1798
1799
return gp_IdentifyVertices(theGraph, u, v, eBefore);
1800
}
1801
1802
/********************************************************************
1803
gp_IdentifyVertices()
1804
1805
Identifies vertex v with vertex u by transferring all adjacencies
1806
of v to u. Any duplicate edges are removed as described below.
1807
The non-duplicate edges of v are added to the adjacency list of u
1808
without disturbing their relative order, and they are added before
1809
the edge record eBefore in u's list. If eBefore is NIL, then the
1810
edges are simply appended to u's list.
1811
1812
If u and v are adjacent, then gp_HideEdge() is invoked to remove
1813
the edge e=(u,v). Then, the edges of v that indicate neighbors of
1814
u are also hidden. This is done by setting the visited flags of
1815
u's neighbors, then traversing the adjacency list of v. For each
1816
visited neighbor of v, the edge is hidden because it would duplicate
1817
an adjacency already expressed in u's list. Finally, the remaining
1818
edges of v are moved to u's list, and each twin arc is adjusted
1819
to indicate u as a neighbor rather than v.
1820
1821
This routine assumes that the visited flags are clear beforehand,
1822
and visited flag settings made herein are cleared before returning.
1823
1824
The following are pushed, in order, onto the graph's built-in stack:
1825
1) an integer for each hidden edge
1826
2) the stack size before any hidden edges were pushed
1827
3) six integers that indicate u, v and the edges moved from v to u
1828
1829
An algorithm that identifies a series of vertices, either through
1830
directly calling this method or via gp_ContractEdge(), can unwind
1831
the identifications using gp_RestoreIdentifications(), which
1832
invokes gp_RestoreVertex() repeatedly.
1833
1834
Returns OK on success, NOTOK on internal failure
1835
********************************************************************/
1836
1837
int gp_IdentifyVertices(graphP theGraph, int u, int v, int eBefore)
1838
{
1839
return theGraph->functions.fpIdentifyVertices(theGraph, u, v, eBefore);
1840
}
1841
1842
int _IdentifyVertices(graphP theGraph, int u, int v, int eBefore)
1843
{
1844
int e = gp_GetNeighborEdgeRecord(theGraph, u, v);
1845
int hiddenEdgeStackBottom, eBeforePred, J;
1846
1847
// If the vertices are adjacent, then the identification is
1848
// essentially an edge contraction with a bit of fixup.
1849
if (gp_IsArc(theGraph, e))
1850
{
1851
int result = gp_ContractEdge(theGraph, e);
1852
1853
// The edge contraction operation pushes one hidden edge then
1854
// recursively calls this method. This method then pushes K
1855
// hidden edges then an integer indicating where the top of
1856
// stack was before the edges were hidden. That integer
1857
// indicator must be decremented, thereby incrementing the
1858
// number of hidden edges to K+1.
1859
// After pushing the K hidden edges and the stackBottom of
1860
// the hidden edges, the recursive call to this method pushes
1861
// six more integers to indicate edges that were moved from
1862
// v to u, so the "hidden edges stackBottom" is in the next
1863
// position down.
1864
int hiddenEdgesStackBottomIndex = sp_GetCurrentSize(theGraph->theStack)-7;
1865
int hiddenEdgesStackBottomValue = sp_Get(theGraph->theStack, hiddenEdgesStackBottomIndex);
1866
1867
sp_Set(theGraph->theStack, hiddenEdgesStackBottomIndex, hiddenEdgesStackBottomValue - 1);
1868
1869
return result;
1870
}
1871
1872
// Now, u and v are not adjacent. Before we do any edge hiding or
1873
// moving, we record the current stack size, as this is the
1874
// stackBottom for the edges that will be hidden next.
1875
hiddenEdgeStackBottom = sp_GetCurrentSize(theGraph->theStack);
1876
1877
// Mark as visited all neighbors of u
1878
J = gp_GetFirstArc(theGraph, u);
1879
while (gp_IsArc(theGraph, J))
1880
{
1881
if (theGraph->G[theGraph->G[J].v].visited != 0)
1882
return NOTOK;
1883
1884
theGraph->G[theGraph->G[J].v].visited = 1;
1885
J = gp_GetNextArc(theGraph, J);
1886
}
1887
1888
// For each edge record of v, if the neighbor is visited, then
1889
// push and hide the edge.
1890
J = gp_GetFirstArc(theGraph, v);
1891
while (gp_IsArc(theGraph, J))
1892
{
1893
if (theGraph->G[theGraph->G[J].v].visited)
1894
{
1895
sp_Push(theGraph->theStack, J);
1896
gp_HideEdge(theGraph, J);
1897
}
1898
J = gp_GetNextArc(theGraph, J);
1899
}
1900
1901
// Mark as unvisited all neighbors of u
1902
J = gp_GetFirstArc(theGraph, u);
1903
while (gp_IsArc(theGraph, J))
1904
{
1905
theGraph->G[theGraph->G[J].v].visited = 0;
1906
J = gp_GetNextArc(theGraph, J);
1907
}
1908
1909
// Push the hiddenEdgeStackBottom as a record of how many hidden
1910
// edges were pushed (also, see above for Contract Edge adjustment)
1911
sp_Push(theGraph->theStack, hiddenEdgeStackBottom);
1912
1913
// Moving v's adjacency list to u is aided by knowing the predecessor
1914
// of u's eBefore (the edge record in u's list before which the
1915
// edge records of v will be added).
1916
eBeforePred = gp_IsArc(theGraph, eBefore)
1917
? gp_GetPrevArc(theGraph, eBefore)
1918
: gp_GetLastArc(theGraph, u);
1919
1920
// Turns out we only need to record six integers related to the edges
1921
// being moved in order to easily restore them later.
1922
sp_Push(theGraph->theStack, eBefore);
1923
sp_Push(theGraph->theStack, gp_GetLastArc(theGraph, v));
1924
sp_Push(theGraph->theStack, gp_GetFirstArc(theGraph, v));
1925
sp_Push(theGraph->theStack, eBeforePred);
1926
sp_Push(theGraph->theStack, u);
1927
sp_Push(theGraph->theStack, v);
1928
1929
// For the remaining edge records of v, reassign the 'v' member
1930
// of each twin arc to indicate u rather than v.
1931
J = gp_GetFirstArc(theGraph, v);
1932
while (gp_IsArc(theGraph, J))
1933
{
1934
theGraph->G[gp_GetTwinArc(theGraph, J)].v = u;
1935
J = gp_GetNextArc(theGraph, J);
1936
}
1937
1938
// If v has any edges left after hiding edges, indicating common neighbors with u, ...
1939
if (gp_IsArc(theGraph, gp_GetFirstArc(theGraph, v)))
1940
{
1941
// Then perform the list union of v into u between eBeforePred and eBefore
1942
if (gp_IsArc(theGraph, eBeforePred))
1943
{
1944
if (gp_IsArc(theGraph, gp_GetFirstArc(theGraph, v)))
1945
{
1946
gp_SetNextArc(theGraph, eBeforePred, gp_GetFirstArc(theGraph, v));
1947
gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, v), eBeforePred);
1948
}
1949
}
1950
else
1951
{
1952
gp_SetFirstArc(theGraph, u, gp_GetFirstArc(theGraph, v));
1953
}
1954
1955
if (gp_IsArc(theGraph, eBefore))
1956
{
1957
if (gp_IsArc(theGraph, gp_GetLastArc(theGraph, v)))
1958
{
1959
gp_SetNextArc(theGraph, gp_GetLastArc(theGraph, v), eBefore);
1960
gp_SetPrevArc(theGraph, eBefore, gp_GetLastArc(theGraph, v));
1961
}
1962
}
1963
else
1964
{
1965
gp_SetLastArc(theGraph, u, gp_GetLastArc(theGraph, v));
1966
}
1967
1968
gp_SetFirstArc(theGraph, v, NIL);
1969
gp_SetLastArc(theGraph, v, NIL);
1970
}
1971
1972
return OK;
1973
}
1974
1975
/********************************************************************
1976
gp_RestoreVertex()
1977
1978
This method assumes the built-in graph stack contents are the result
1979
of vertex hide, vertex identify and edge contract operations.
1980
This content consists of segments of integers, each segment
1981
corresponding to the removal of a vertex during an edge contraction
1982
or vertex identification in which a vertex v was merged into a
1983
vertex u. The segment contains two blocks of integers.
1984
The first block contains information about u, v, the edge records
1985
in v's adjacency list that were added to u, and where in u's
1986
adjacency list they were added. The second block of integers
1987
contains a list of edges incident to v that were hidden from the
1988
graph because they were incident to neighbors of v that were also
1989
neighbors of u (so they would have produced duplicate edges had
1990
they been left in v's adjacency list when it was merged with u's
1991
adjacency list).
1992
1993
This method pops the first block of the segment off the stack and
1994
uses the information to help remove v's adjacency list from u and
1995
restore it into v. Then, the second block is removed from the
1996
stack, and each indicated edge is restored from the hidden state.
1997
1998
It is anticipated that this method will be overloaded by extension
1999
algorithms to perform some processing as each vertex is restored.
2000
Before restoration, the topmost segment has the following structure:
2001
2002
... FHE ... LHE HESB e_u_succ e_v_last e_v_first e_u_pred u v
2003
^------------|
2004
2005
FHE = First hidden edge
2006
LHE = Last hidden edge
2007
HESB = Hidden edge stack bottom
2008
e_u_succ, e_u_pred = The edges of u between which the edges of v
2009
were inserted. NIL can appear if the edges of v
2010
were added to the beginning or end of u's list
2011
e_v_first, e_v_last = The first and last edges of v's list, once
2012
the hidden edges were removed
2013
2014
Returns OK for success, NOTOK for internal failure.
2015
********************************************************************/
2016
2017
int gp_RestoreVertex(graphP theGraph)
2018
{
2019
return theGraph->functions.fpRestoreVertex(theGraph);
2020
}
2021
2022
int _RestoreVertex(graphP theGraph)
2023
{
2024
int u, v, e_u_succ, e_u_pred, e_v_first, e_v_last, HESB, J;
2025
2026
if (sp_GetCurrentSize(theGraph->theStack) < 7)
2027
return NOTOK;
2028
2029
sp_Pop(theGraph->theStack, v);
2030
sp_Pop(theGraph->theStack, u);
2031
sp_Pop(theGraph->theStack, e_u_pred);
2032
sp_Pop(theGraph->theStack, e_v_first);
2033
sp_Pop(theGraph->theStack, e_v_last);
2034
sp_Pop(theGraph->theStack, e_u_succ);
2035
2036
// If u is not NIL, then vertex v was identified with u. Otherwise, v was
2037
// simply hidden, so we skip to restoring the hidden edges.
2038
if (u != NIL)
2039
{
2040
// Remove v's adjacency list from u, including accounting for degree 0 case
2041
if (gp_IsArc(theGraph, e_u_pred))
2042
{
2043
gp_SetNextArc(theGraph, e_u_pred, e_u_succ);
2044
// If the successor edge exists, link it to the predecessor,
2045
// otherwise the predecessor is the new last arc
2046
if (gp_IsArc(theGraph, e_u_succ))
2047
gp_SetPrevArc(theGraph, e_u_succ, e_u_pred);
2048
else
2049
gp_SetLastArc(theGraph, u, e_u_pred);
2050
}
2051
else if (gp_IsArc(theGraph, e_u_succ))
2052
{
2053
// The successor arc exists, but not the predecessor,
2054
// so the successor is the new first arc
2055
gp_SetPrevArc(theGraph, e_u_succ, NIL);
2056
gp_SetFirstArc(theGraph, u, e_u_succ);
2057
}
2058
else
2059
{
2060
// Just in case u was degree zero
2061
gp_SetFirstArc(theGraph, u, NIL);
2062
gp_SetLastArc(theGraph, u, NIL);
2063
}
2064
2065
// Place v's adjacency list into v, including accounting for degree 0 case
2066
gp_SetFirstArc(theGraph, v, e_v_first);
2067
gp_SetLastArc(theGraph, v, e_v_last);
2068
if (gp_IsArc(theGraph, e_v_first))
2069
gp_SetPrevArc(theGraph, e_v_first, NIL);
2070
if (gp_IsArc(theGraph, e_v_last))
2071
gp_SetPrevArc(theGraph, e_v_last, NIL);
2072
2073
// For each edge record restored to v's adjacency list, reassign the 'v' member
2074
// of each twin arc to indicate v rather than u.
2075
J = e_v_first;
2076
while (gp_IsArc(theGraph, J))
2077
{
2078
theGraph->G[gp_GetTwinArc(theGraph, J)].v = v;
2079
2080
if (J == e_v_last)
2081
J = NIL;
2082
else
2083
J = gp_GetNextArc(theGraph, J);
2084
}
2085
}
2086
2087
// Restore the hidden edges of v, if any
2088
sp_Pop(theGraph->theStack, HESB);
2089
return _RestoreHiddenEdges(theGraph, HESB);
2090
}
2091
2092
/********************************************************************
2093
gp_RestoreVertices()
2094
2095
This method assumes the built-in graph stack has content consistent
2096
with numerous vertex identification or edge contraction operations.
2097
This method unwinds the stack, moving edges back to their original
2098
vertex owners and restoring hidden edges.
2099
This method is a simple iterator that invokes gp_RestoreVertex()
2100
until the stack is empty, so extension algorithms are more likely
2101
to overload gp_RestoreVertex().
2102
2103
Returns OK for success, NOTOK for internal failure.
2104
********************************************************************/
2105
2106
int gp_RestoreVertices(graphP theGraph)
2107
{
2108
while (sp_NonEmpty(theGraph->theStack))
2109
{
2110
if (gp_RestoreVertex(theGraph) != OK)
2111
return NOTOK;
2112
}
2113
2114
return OK;
2115
}
2116
2117
/****************************************************************************
2118
_ComputeArcType()
2119
This is just a little helper function that automates a sequence of decisions
2120
that has to be made a number of times.
2121
An edge record is being added to the adjacency list of a; it indicates that
2122
b is a neighbor. The edgeType can be either 'tree' (EDGE_DFSPARENT or
2123
EDGE_DFSCHILD) or 'cycle' (EDGE_BACK or EDGE_FORWARD).
2124
If a or b is a root copy, we translate to the non-virtual counterpart,
2125
then wedetermine which has the lesser DFI. If a has the lower DFI then the
2126
edge record is a tree edge to a child (EDGE_DFSCHILD) if edgeType indicates
2127
a tree edge. If edgeType indicates a cycle edge, then it is a forward cycle
2128
edge (EDGE_FORWARD) to a descendant.
2129
Symmetric conditions define the types for a > b.
2130
****************************************************************************/
2131
2132
int _ComputeArcType(graphP theGraph, int a, int b, int edgeType)
2133
{
2134
if (a >= theGraph->N)
2135
a = theGraph->V[a - theGraph->N].DFSParent;
2136
if (b >= theGraph->N)
2137
b = theGraph->V[b - theGraph->N].DFSParent;
2138
2139
if (a < b)
2140
return edgeType == EDGE_DFSPARENT || edgeType == EDGE_DFSCHILD ? EDGE_DFSCHILD : EDGE_FORWARD;
2141
2142
return edgeType == EDGE_DFSPARENT || edgeType == EDGE_DFSCHILD ? EDGE_DFSPARENT : EDGE_BACK;
2143
}
2144
2145
/****************************************************************************
2146
_SetEdgeType()
2147
When we are restoring an edge, we must restore its type (tree edge or cycle edge).
2148
We can deduce what the type was based on other information in the graph. Each
2149
arc of the edge gets the appropriate type setting (parent/child or back/forward).
2150
This method runs in constant time plus the degree of vertex u, or constant
2151
time if u is known to have a degree bound by a constant.
2152
****************************************************************************/
2153
2154
int _SetEdgeType(graphP theGraph, int u, int v)
2155
{
2156
int e, eTwin, u_orig, v_orig, N;
2157
2158
// If u or v is a virtual vertex (a root copy), then get the non-virtual counterpart.
2159
N = theGraph->N;
2160
u_orig = u < N ? u : (theGraph->V[u - N].DFSParent);
2161
v_orig = v < N ? v : (theGraph->V[v - N].DFSParent);
2162
2163
// Get the edge for which we will set the type
2164
2165
e = gp_GetNeighborEdgeRecord(theGraph, u, v);
2166
eTwin = gp_GetTwinArc(theGraph, e);
2167
2168
// If u_orig is the parent of v_orig, or vice versa, then the edge is a tree edge
2169
2170
if (theGraph->V[v_orig].DFSParent == u_orig ||
2171
theGraph->V[u_orig].DFSParent == v_orig)
2172
{
2173
if (u_orig > v_orig)
2174
{
2175
theGraph->G[e].type = EDGE_DFSPARENT;
2176
theGraph->G[eTwin].type = EDGE_DFSCHILD;
2177
}
2178
else
2179
{
2180
theGraph->G[eTwin].type = EDGE_DFSPARENT;
2181
theGraph->G[e].type = EDGE_DFSCHILD;
2182
}
2183
}
2184
2185
// Otherwise it is a back edge
2186
2187
else
2188
{
2189
if (u_orig > v_orig)
2190
{
2191
theGraph->G[e].type = EDGE_BACK;
2192
theGraph->G[eTwin].type = EDGE_FORWARD;
2193
}
2194
else
2195
{
2196
theGraph->G[eTwin].type = EDGE_BACK;
2197
theGraph->G[e].type = EDGE_FORWARD;
2198
}
2199
}
2200
2201
return OK;
2202
}
2203
2204
/********************************************************************
2205
_DeleteUnmarkedEdgesInBicomp()
2206
2207
This function deletes from a given biconnected component all edges
2208
whose visited member is zero.
2209
2210
The stack is used but preserved. In debug mode, NOTOK can result if
2211
there is a stack overflow. This method pushes at most one integer
2212
per vertex in the bicomp.
2213
2214
Returns OK on success, NOTOK on implementation failure
2215
********************************************************************/
2216
2217
int _DeleteUnmarkedEdgesInBicomp(graphP theGraph, int BicompRoot)
2218
{
2219
int V, J;
2220
int stackBottom = sp_GetCurrentSize(theGraph->theStack);
2221
2222
sp_Push(theGraph->theStack, BicompRoot);
2223
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
2224
{
2225
sp_Pop(theGraph->theStack, V);
2226
2227
J = gp_GetFirstArc(theGraph, V);
2228
while (gp_IsArc(theGraph, J))
2229
{
2230
if (theGraph->G[J].type == EDGE_DFSCHILD)
2231
sp_Push(theGraph->theStack, theGraph->G[J].v);
2232
2233
if (!theGraph->G[J].visited)
2234
J = gp_DeleteEdge(theGraph, J, 0);
2235
else J = gp_GetNextArc(theGraph, J);
2236
}
2237
}
2238
return OK;
2239
}
2240
2241
/********************************************************************
2242
_ClearInvertedFlagsInBicomp()
2243
2244
This function clears the inverted flag markers on any edges in a
2245
given biconnected component.
2246
2247
The stack is used but preserved. In debug mode, NOTOK can result if
2248
there is a stack overflow. This method pushes at most one integer
2249
per vertex in the bicomp.
2250
2251
Returns OK on success, NOTOK on implementation failure
2252
********************************************************************/
2253
2254
int _ClearInvertedFlagsInBicomp(graphP theGraph, int BicompRoot)
2255
{
2256
int V, J;
2257
int stackBottom = sp_GetCurrentSize(theGraph->theStack);
2258
2259
sp_Push(theGraph->theStack, BicompRoot);
2260
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
2261
{
2262
sp_Pop(theGraph->theStack, V);
2263
2264
J = gp_GetFirstArc(theGraph, V);
2265
while (gp_IsArc(theGraph, J))
2266
{
2267
if (theGraph->G[J].type == EDGE_DFSCHILD)
2268
{
2269
sp_Push(theGraph->theStack, theGraph->G[J].v);
2270
CLEAR_EDGEFLAG_INVERTED(theGraph, J);
2271
}
2272
2273
J = gp_GetNextArc(theGraph, J);
2274
}
2275
}
2276
return OK;
2277
}
2278
2279
/********************************************************************
2280
_GetBicompSize()
2281
2282
Determine the number of vertices in the bicomp.
2283
2284
The stack is used but preserved. In debug mode, NOTOK can result if
2285
there is a stack overflow. This method pushes at most one integer
2286
per vertex in the bicomp.
2287
2288
Returns a positive number on success, NOTOK on implementation failure
2289
********************************************************************/
2290
2291
int _GetBicompSize(graphP theGraph, int BicompRoot)
2292
{
2293
int V, J;
2294
int theSize = 0;
2295
int stackBottom = sp_GetCurrentSize(theGraph->theStack);
2296
2297
sp_Push(theGraph->theStack, BicompRoot);
2298
while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)
2299
{
2300
sp_Pop(theGraph->theStack, V);
2301
theSize++;
2302
J = gp_GetFirstArc(theGraph, V);
2303
while (gp_IsArc(theGraph, J))
2304
{
2305
if (theGraph->G[J].type == EDGE_DFSCHILD)
2306
sp_Push(theGraph->theStack, theGraph->G[J].v);
2307
2308
J = gp_GetNextArc(theGraph, J);
2309
}
2310
}
2311
return theSize;
2312
}
2313
2314
/********************************************************************
2315
debugNOTOK()
2316
This function provides a non-void wrapper for exit().
2317
This is useful for debugging as it allows compilation of an exit
2318
command in places where NOTOK is returned.
2319
In exhaustive testing, we want to bail on the first NOTOK that occurs.
2320
Comment out the exit() call to get a stack trace.
2321
********************************************************************/
2322
2323
int debugNOTOK()
2324
{
2325
//exit(-1);
2326
return 0; // NOTOK is normally defined to be zero
2327
}
2328
2329