Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/planarity/graphExtensions.c
4057 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
#include <string.h>
47
48
#include "appconst.h"
49
50
#include "graphExtensions.private.h"
51
#include "graphExtensions.h"
52
#include "graphFunctionTable.h"
53
54
/* Imported functions */
55
56
extern void _InitFunctionTable(graphP theGraph);
57
58
/* Private function */
59
60
void _FreeExtension(graphExtensionP extension);
61
void _OverloadFunctions(graphP theGraph, graphFunctionTableP functions);
62
void _FixupFunctionTables(graphP theGraph, graphExtensionP curr);
63
graphExtensionP _FindNearestOverload(graphP theGraph, graphExtensionP target, int functionIndex);
64
65
/********************************************************************
66
* The moduleIDGenerator is used to help ensure that all extensions
67
* added during a run-time have a different integer identifier.
68
* An ID identifies an extension, which may be added to multiple
69
* graphs. It is used in lieu of identifying extensions by a string
70
* name, which is noticeably expensive when a frequently called
71
* overload function seeks the extension context for a graph.
72
********************************************************************/
73
74
static int moduleIDGenerator = 0;
75
76
/********************************************************************
77
The extension mechanism allows new modules to equip a graph with the
78
data structures and functions needed to implement new algorithms
79
without impeding the performance of the core graph planar embedding
80
algorithms on graphs that have not been so equipped.
81
82
The following steps must be used to create a graph extension:
83
84
1) Create a moduleID variable initialized to zero that will be
85
assigned a positive integer the first time the extension is
86
added to a graph by gp_AddExtension()
87
88
2) Define an extension context structure to contain all of the data
89
and function pointers that extend the graph. The context must
90
include a graphFunctionTable to allow overloading of functions.
91
An instance of this context structure is passed to the "context"
92
parameter of gp_AddExtension().
93
94
3) Define a function capable of duplicating your context data
95
structure. It receives a void pointer indicating the context
96
to duplicate and a void pointer that can be cast to a graph
97
pointer indicating the graph for which the context is being
98
duplicated. The void pointer returned indicates the newly
99
allocated context structure. The pointer to this function is
100
passed to the "dupContext" parameter of gp_AddExtension()
101
102
Note: It is useful to store in your context structure a pointer
103
to the graph that the context is extending. There are certain
104
function overloads you will perform that will only receive
105
the context, and you may need to know things about the graph,
106
such as the number of vertices or edges.
107
108
4) Define a function that can free the memory used by your context
109
data structure. It will receive a void pointer indicating the
110
instance of your context data structure that you passed as the
111
"context" parameter to gp_AddExtension().
112
The free function pointer should be passed as the "freeContext"
113
parameter to gp_AddExtension()
114
115
5) The expected method of attaching your feature to a graph is to
116
create a function called gp_AttachFeature(), where 'Feature' is
117
the name of your module. The attach function allocates your context
118
data structure, initializes the extension data, assigns overload
119
function pointers, and invokes gp_AddExtension().
120
121
NOTE: It is advisable to use memset on the context function table
122
before assigning any function overloads because any function not
123
being overloaded must have a NULL pointer.
124
125
NOTE: The gp_AddExtension() method puts the overload function
126
pointers into the graph's function table, and the base function
127
pointers that were overloaded are placed in the context function
128
table. This allows the extension's functions to have access to
129
base function behaviors, since many extension functions will
130
extend rather than replace the base behavior.
131
132
6) There are a few functions that you must overload in order to
133
successfully manage data structures that are parallel to the
134
main graph data structures.
135
136
The core graph data structure has function pointers to functions
137
that can be overloaded. In addition to invoking gp_AddExtension(),
138
you need to set pointers to your own versions of the functions
139
you are overloading. You will also need to store a copy of the
140
prior pointer in your feature's context data structure so that you
141
can invoke the "base" behavior from your function overload, e.g.
142
if your feature is attached but not active or if your feature
143
augments the base behavior rather than replacing it.
144
145
a) If any kind of data structures need to be maintained at
146
the graph, vertex or graph node levels, then an overload
147
of fpInitGraph() will be needed.
148
149
b) If any vertex-level data is needed, then an overload of
150
fpInitVertexRec() is needed.
151
This overload function should be named _Feature_InitVertexRec().
152
It will invoke the base fpVertexRec() and also invoke
153
a second function named_InitFeatureVertexRec() that
154
initializes the custom VertexRec data members
155
156
c) If any graph node level data is needed, then an overload
157
of fpInitGraphNode() is needed.
158
This overload function should be named _Feature_InitGraphNode().
159
It will invoke the base fpInitGraphNode() and also invoke
160
a second function named_InitFeatureGraphNode() that
161
initializes the custom graph node data members
162
163
d) If any graph-level data structures are needed, then an
164
overload of fpReinitializeGraph() will be needed. If only
165
vertex-level or graph node level data members are needed, then
166
the overloads of fpInitGraphNode() and fpInitVertexRec() are
167
invoked by the basic fpReinitializeGraph without needing to
168
overload it as well.
169
170
e) If any data must be persisted in the file format, then overloads
171
of fpReadPostprocess() and fpWritePostprocess() are needed.
172
173
7) Define internal functions for _Feature_ClearStructures(),
174
_Feature_CreateStructures() and _Feature_InitStructures();
175
176
a) The _Feature_ClearStructures() should simply null out pointers
177
to extra structures on its first invocation, but thereafter it
178
should free them and then null them. Since the null-only step
179
is done only once in gp_AttachFeature(), it seems reasonable to
180
not bother with a more complicated _Feature_ClearStructures().
181
But, as an extension is developed, the data structures change,
182
so it is best to keep all this logic in one place.
183
184
b) The _Feature_CreateStructures() should just allocate memory for
185
but not initialize any vertex level and graph node level data
186
structures. Data structures maintained at the graph level, such
187
as a stack or a list collection, should be created and initialized.
188
189
c) The _Feature_InitStructures() should invoke just the functions
190
needed to initialize the custom VertexRec and GraphNode data
191
members, if any.
192
193
8) Define a function gp_DetachFeature() that invokes gp_RemoveExtension()
194
This should be done for consistency, so that users of a feature
195
do not attach it with gp_AttachFeature() and remove it with
196
gp_RemoveExtension(). However, it may sometimes be necessary to
197
run more code than just gp_RemoveExtension() when detaching a feature,
198
e.g. some final result values of a feature may be saved to data
199
available in the core graph or in other features.
200
********************************************************************/
201
202
/********************************************************************
203
gp_AddExtension()
204
205
@param theGraph - pointer to the graph to which the extension is being added
206
@param pModuleID - address of the variable that contains the feature's
207
extension identifier. If the variable is equal to zero,
208
it is assigned a positive number. Thereafter, the variable
209
value can be used to find and remove the extension from any graph
210
@param context - the data storage for the extension being added
211
The context is owned by the extension and freed with freeContext()
212
@param dupContext - a function capable of duplicating the context data
213
@param freeContext - a function capable of freeing the context data
214
@param functions - pointer to a table of functions stored in the data context.
215
The table of functions is an input and output parameter.
216
On input, the table consists of new function pointers
217
for functions being overloaded.
218
Any function not being overloaded must be NULL.
219
The non-NULL function pointers are used to overload
220
the functions in the graph, and the prior pointer values
221
in the graph are stored in the function table as output.
222
The context data therefore has the pointer to the base
223
function corresponding to any function its extension
224
module overloaded.
225
226
The new extension is created and added to the graph.
227
********************************************************************/
228
229
int gp_AddExtension(graphP theGraph,
230
int *pModuleID,
231
void *context,
232
void *(*dupContext)(void *, void *),
233
void (*freeContext)(void *),
234
graphFunctionTableP functions)
235
{
236
graphExtensionP newExtension = NULL;
237
238
if (theGraph == NULL || pModuleID == NULL ||
239
context == NULL || dupContext == NULL || freeContext == NULL ||
240
functions == NULL)
241
{
242
return NOTOK;
243
}
244
245
// If the extension already exists, then don't redefine it.
246
if (gp_FindExtension(theGraph, *pModuleID, NULL) == TRUE)
247
{
248
return NOTOK;
249
}
250
251
// Assign a unique ID to the extension if it does not already have one
252
if (*pModuleID == 0)
253
{
254
*pModuleID = ++moduleIDGenerator;
255
}
256
257
// Allocate the new extension
258
if ((newExtension = (graphExtensionP) malloc(sizeof(graphExtension))) == NULL)
259
{
260
return NOTOK;
261
}
262
263
// Assign the data payload of the extension
264
newExtension->moduleID = *pModuleID;
265
newExtension->context = context;
266
newExtension->dupContext = dupContext;
267
newExtension->freeContext = freeContext;
268
newExtension->functions = functions;
269
270
_OverloadFunctions(theGraph, functions);
271
272
// Make the new linkages
273
newExtension->next = (struct graphExtension *) theGraph->extensions;
274
theGraph->extensions = newExtension;
275
276
// The new extension was successfully added
277
return OK;
278
279
}
280
281
/********************************************************************
282
_OverloadFunctions()
283
For each non-NULL function pointer, the pointer becomes the new value
284
for the function in the graph, and the old function pointer in the graph
285
is placed in the overload table.
286
287
This way, when an extension function is invoked, it can choose to invoke
288
the base function before or after whatever extension behavior it provides.
289
290
Also, when it comes time to remove an extension, this extension system
291
has access to the overload tables of all extensions so that it can unhook
292
the functions of the module being removed from the chains of calls for
293
each overloaded function. This will involve some pointer changes in
294
the overload tables of extensions other than the one being removed.
295
********************************************************************/
296
297
void _OverloadFunctions(graphP theGraph, graphFunctionTableP functions)
298
{
299
void **graphFunctionTable = (void **) &theGraph->functions;
300
void **newFunctionTable = (void **) functions;
301
int numFunctions = sizeof(theGraph->functions) / sizeof(void *);
302
int I;
303
304
for (I = 0; I < numFunctions; I++)
305
{
306
if (newFunctionTable[I] != NULL)
307
{
308
void *fp = graphFunctionTable[I];
309
graphFunctionTable[I] = newFunctionTable[I];
310
newFunctionTable[I] = fp;
311
}
312
}
313
}
314
315
/********************************************************************
316
gp_FindExtension()
317
318
@param theGraph - the graph whose extension list is to be searched
319
@param moduleID - the identifier of the module whose extension context is desired
320
@param pContext - the return parameter that receives the value of the
321
extension, if found. This may be NULL if the extension was
322
not found or if the extension context value was NULL.
323
@return TRUE if the extension was found, NOTOK if not found
324
If FALSE is returned, then the context returned is guaranteed to be NULL
325
If TRUE is returned, the context returned may be NULL if that is the
326
current value of the module extension
327
********************************************************************/
328
329
int gp_FindExtension(graphP theGraph, int moduleID, void **pContext)
330
{
331
graphExtensionP first = NULL, next = NULL;
332
333
if (pContext != NULL)
334
{
335
*pContext = NULL;
336
}
337
338
if (theGraph==NULL || moduleID==0)
339
{
340
return FALSE;
341
}
342
343
first = theGraph->extensions;
344
345
while (first != NULL)
346
{
347
next = (graphExtensionP) first->next;
348
if (first->moduleID == moduleID)
349
{
350
if (pContext != NULL)
351
{
352
*pContext = first->context;
353
}
354
return TRUE;
355
}
356
first = next;
357
}
358
359
return FALSE;
360
}
361
362
/********************************************************************
363
gp_GetExtension()
364
365
Calling this function is equivalent to invoking gp_FindExtension()
366
except that some debuggers have difficulty stepping into a function
367
that (properly) start by setting a local variable pointer to NULL
368
when the debugger has watch expressions that dereference a pointer
369
of the same name. In such cases,
370
371
MyContext *context = NULL;
372
gp_FindExtension(theGraph, MYEXTENSION_ID, &context);
373
374
can be replaced by
375
376
MyContext *context = gp_GetExtension(theGraph, MYEXTENSION_ID);
377
378
@param theGraph - the graph whose extension list is to be searched
379
@param moduleID - the identifier of the module whose extension context is desired
380
@return void pointer to the extension if found, or NULL if not found.
381
********************************************************************/
382
void *gp_GetExtension(graphP theGraph, int moduleID)
383
{
384
void *context = NULL;
385
int result = gp_FindExtension(theGraph, moduleID, &context);
386
return result ? context : NULL;
387
}
388
389
/********************************************************************
390
gp_RemoveExtension()
391
@param theGraph - the graph from which to remove an extension
392
@param moduleID - the ID of the module whose extension context is to be removed
393
@return OK if the module is successfully removed or not in the list
394
NOTOK for internal errors, such as invalid parameters
395
********************************************************************/
396
int gp_RemoveExtension(graphP theGraph, int moduleID)
397
{
398
graphExtensionP prev, curr, next;
399
400
if (theGraph==NULL || moduleID==0)
401
return NOTOK;
402
403
prev = NULL;
404
curr = theGraph->extensions;
405
406
while (curr != NULL)
407
{
408
next = (graphExtensionP) curr->next;
409
410
if (curr->moduleID == moduleID)
411
break;
412
413
prev = curr;
414
curr = next;
415
}
416
417
// An extension can only be removed if it is found. Otherwise,
418
// we return OK because the extension degenerately removed
419
// (since it is already gone)
420
if (curr != NULL)
421
{
422
_FixupFunctionTables(theGraph, curr);
423
424
// Unhook the curr extension
425
if (prev != NULL)
426
prev->next = (struct graphExtension *) next;
427
else theGraph->extensions = next;
428
429
// Free the curr extension
430
_FreeExtension(curr);
431
}
432
433
return OK;
434
}
435
436
437
/********************************************************************
438
_FixupFunctionTables()
439
440
Removes the functions in the curr function table from the function
441
call lists established by the function tables of all extensions and
442
theGraph.
443
444
Since new extensions are prepended, extensions before curr may
445
have further overloaded the functions in the curr function table.
446
447
For a non-NULL function pointer in the curr table, if there is
448
a preceding extension with the same function pointer non-NULL, then
449
the function table of the closest such preceding extension points
450
to the original overload function of the curr extension, and the
451
curr extension contains the pointer to the base function behavior,
452
so now the function table of that preceding extension must be changed
453
to the function pointer value in the curr extension.
454
********************************************************************/
455
456
void _FixupFunctionTables(graphP theGraph, graphExtensionP curr)
457
{
458
void **currFunctionTable = (void **) (curr->functions);
459
int numFunctions = sizeof(*(curr->functions)) / sizeof(void *);
460
int I;
461
462
for (I = 0; I < numFunctions; I++)
463
{
464
if (currFunctionTable[I] != NULL)
465
{
466
void **nearestOverloadFunctionTable = (void **) &theGraph->functions;
467
graphExtensionP pred = _FindNearestOverload(theGraph, curr, I);
468
469
if (pred != NULL)
470
nearestOverloadFunctionTable = (void **) pred->functions;
471
472
nearestOverloadFunctionTable[I] = currFunctionTable[I];
473
}
474
}
475
}
476
477
/********************************************************************
478
_FindNearestOverload()
479
********************************************************************/
480
481
graphExtensionP _FindNearestOverload(graphP theGraph, graphExtensionP target, int functionIndex)
482
{
483
graphExtensionP curr = theGraph->extensions;
484
graphExtensionP found = NULL;
485
void **functionTable;
486
487
while (curr != target)
488
{
489
functionTable = (void **) curr->functions;
490
if (functionTable[functionIndex] != NULL)
491
found = curr;
492
493
curr = (graphExtensionP) curr->next;
494
}
495
496
return found;
497
}
498
499
/********************************************************************
500
gp_CopyExtensions()
501
********************************************************************/
502
503
int gp_CopyExtensions(graphP dstGraph, graphP srcGraph)
504
{
505
graphExtensionP next = NULL, newNext = NULL, newLast = NULL;
506
507
if (srcGraph == NULL || dstGraph == NULL)
508
return NOTOK;
509
510
gp_FreeExtensions(dstGraph);
511
512
next = srcGraph->extensions;
513
514
while (next != NULL)
515
{
516
if ((newNext = (graphExtensionP) malloc(sizeof(graphExtension))) == NULL)
517
{
518
gp_FreeExtensions(dstGraph);
519
return NOTOK;
520
}
521
522
newNext->moduleID = next->moduleID;
523
newNext->context = next->dupContext(next->context, dstGraph);
524
newNext->dupContext = next->dupContext;
525
newNext->freeContext = next->freeContext;
526
newNext->functions = next->functions;
527
newNext->next = NULL;
528
529
if (newLast != NULL)
530
newLast->next = (struct graphExtension *) newNext;
531
else
532
dstGraph->extensions = newNext;
533
534
newLast = newNext;
535
next = (graphExtensionP) next->next;
536
}
537
538
return OK;
539
}
540
541
/********************************************************************
542
gp_FreeExtensions()
543
544
@param pFirst - pointer to head pointer of graph extension list
545
546
Each graph extension is freed, including invoking the freeContext
547
function provided when the extension was added.
548
********************************************************************/
549
550
void gp_FreeExtensions(graphP theGraph)
551
{
552
if (theGraph != NULL)
553
{
554
graphExtensionP curr = theGraph->extensions;
555
graphExtensionP next = NULL;
556
557
while (curr != NULL)
558
{
559
next = (graphExtensionP) curr->next;
560
_FreeExtension(curr);
561
curr = next;
562
}
563
564
theGraph->extensions = NULL;
565
_InitFunctionTable(theGraph);
566
}
567
}
568
569
/********************************************************************
570
_FreeExtension()
571
********************************************************************/
572
void _FreeExtension(graphExtensionP extension)
573
{
574
if (extension->context != NULL && extension->freeContext != NULL)
575
{
576
extension->freeContext(extension->context);
577
}
578
free(extension);
579
}
580
581