Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 21 additions & 26 deletions planarity/c/graphLib/extensionSystem/graphExtensions.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand Down Expand Up @@ -108,31 +108,26 @@ static int moduleIDGenerator = 0;
the graph, vertex or edge levels, then an overload of
fpInitGraph() will be needed.

b) If any data must be associated with primary and virtual vertices,
then an overload of fpInitVertexRec() is needed. If data must be
associated only with primary vertices (0 to N-1), then one can
overload fpInitVertexInfo() instead.
The overload function should be named _Feature_InitVertexRec()
or _Feature_InitVertexInfo().
It will invoke the base fpInitVertexRec() or fpInitVertexInfo()
but then also invoke a second function named _InitFeatureVertexRec()
or _InitFeatureVertexInfo() thatinitializes the custom VertexRec
or VertexInfo data members.

c) If any data must be associated with the edges, then an overload
of fpInitEdgeRec() is needed.
This overload function should be named _Feature_InitEdgeRec().
It will invoke the base fpInitEdgeRec() and also invoke
a second function named_InitFeatureEdgeRec() that
initializes the custom EdgeRec data members
b) If any data must be associated with vertices and virtual vertices,
then it is necessary to perform initialization parallel to the
initialization of anyTypeVertexRec instances. Similarly, if data
must be associated only with vertices (and not virtual vertices),
then initialization parallel to VertexInfo initialization is
required. At this time, there do not exist overloadable functions
for fpInitAnyTypeVertexRec() and fpInitVertexInfo().
Instead, overload fpInitGraph() and fpReinitializeGraph(). Also
if an extension must delete an edge, it should have its own

c) If any data must be associated with the edges, then the extension
creates a parallel array that is initialized and reinitialized
in overloads of fpInitGraph() and fpReinitializeGraph().
Also, if the extension deletes edges, then the extension provides
its own _Feature_DeleteEdge() that initializes its edge
extension data along with calling gp_DeleteEdge().

d) If any graph-level data structures are needed, then an
overload of fpReinitializeGraph() will also be needed, not just the
overload of fpInitGraph(). However, if only vertex-level and/or
edge level data members are needed, then the overloads of
fpInitVertexRec(), fpInitVertexInfo() and/or fpInitEdgeRec() are
invoked by the basic fpReinitializeGraph without needing to overload
it as well.
overload of fpInitGraph().

e) If any data must be persisted in the file format, then overloads
of fpReadPostprocess() and fpWritePostprocess() are needed.
Expand All @@ -154,15 +149,15 @@ static int moduleIDGenerator = 0;
list collection, should be created _and_ initialized.

c) The _Feature_InitStructures() should invoke just the functions
needed to initialize the custom VertexRec, VertexInfo and EdgeRec
data members, if any.
needed to initialize the custom AnyTypeVertexRec, VertexInfo and
EdgeRec data members, if any.

8) Define a function gp_DetachFeature() that invokes gp_RemoveExtension()
This should be done for consistency, so that users of a feature
do not attach it with gp_AttachFeature() and remove it with
gp_RemoveExtension(). However, it may sometimes be necessary to
run more code than just gp_RemoveExtension() when detaching a feature,
e.g. some final result values of a feature may be saved to data
e.g., some final result values of a feature may be saved to data
available in the core graph or in other features.
********************************************************************/

Expand Down
2 changes: 1 addition & 1 deletion planarity/c/graphLib/extensionSystem/graphExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define GRAPH_EXTENSIONS_H

/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define GRAPH_EXTENSIONS_PRIVATE_H

/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand Down
2 changes: 1 addition & 1 deletion planarity/c/graphLib/extensionSystem/graphFunctionTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define GRAPHFUNCTIONTABLE_H

/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand Down
12 changes: 6 additions & 6 deletions planarity/c/graphLib/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define GRAPH_H

/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand Down Expand Up @@ -62,12 +62,12 @@ extern "C"
int gp_DynamicAddEdge(graphP theGraph, int u, int ulink, int v, int vlink);
int gp_InsertEdge(graphP theGraph, int u, int e_u, int e_ulink,
int v, int e_v, int e_vlink);
int gp_DeleteEdge(graphP theGraph, int e);

void gp_HideEdge(graphP theGraph, int e);
void gp_RestoreEdge(graphP theGraph, int e);
int gp_HideVertex(graphP theGraph, int vertex);
int gp_RestoreVertex(graphP theGraph);
int gp_DeleteEdge(graphP theGraph, int e, int nextLink);

int gp_ContractEdge(graphP theGraph, int e);
int gp_IdentifyVertices(graphP theGraph, int u, int v, int eBefore);
Expand All @@ -77,13 +77,13 @@ extern "C"
int gp_SortVertices(graphP theGraph);
int gp_LowpointAndLeastAncestor(graphP theGraph);
int gp_LeastAncestor(graphP theGraph);
int gp_PreprocessForEmbedding(graphP theGraph);

int gp_Embed(graphP theGraph, int embedFlags);
int gp_TestEmbedResultIntegrity(graphP theGraph, graphP origGraph, int embedResult);

/* Possible Flags for gp_Embed. The planar and outerplanar settings are supported
natively. The rest require extension modules. */
/* Possible graph embedFlags for gp_Embed.
The planar and outerplanar settings are supported natively
The rest are supported via extension modules. */

#define EMBEDFLAGS_PLANAR 1
#define EMBEDFLAGS_OUTERPLANAR 2
Expand All @@ -94,8 +94,8 @@ extern "C"
#define EMBEDFLAGS_SEARCHFORK4 (32 | EMBEDFLAGS_OUTERPLANAR)
#define EMBEDFLAGS_SEARCHFORK33 (64 | EMBEDFLAGS_PLANAR)

// Reserved for the future possible extension modules
#define EMBEDFLAGS_SEARCHFORK5 (128 | EMBEDFLAGS_PLANAR)

#define EMBEDFLAGS_MAXIMALPLANARSUBGRAPH 256
#define EMBEDFLAGS_PROJECTIVEPLANAR 512
#define EMBEDFLAGS_TOROIDAL 1024
Expand Down
81 changes: 44 additions & 37 deletions planarity/c/graphLib/graphDFSUtils.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 1997-2025, John M. Boyer
Copyright (c) 1997-2026, John M. Boyer
All rights reserved.
See the LICENSE.TXT file for licensing information.
*/
Expand All @@ -12,7 +12,7 @@ See the LICENSE.TXT file for licensing information.
int _SortVertices(graphP theGraph);

// Imported methods
extern void _ClearVertexVisitedFlags(graphP theGraph, int);
extern void _ClearAnyTypeVertexVisitedFlags(graphP theGraph, int);

/********************************************************************
gp_CreateDFSTree
Expand Down Expand Up @@ -59,12 +59,12 @@ int gp_CreateDFSTree(graphP theGraph)

sp_ClearStack(theStack);

_ClearVertexVisitedFlags(theGraph, FALSE);
_ClearAnyTypeVertexVisitedFlags(theGraph, FALSE);

/* This outer loop causes the connected subgraphs of a disconnected
graph to be numbered */

for (DFI = v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, DFI); v++)
for (DFI = v = gp_GetFirstVertex(theGraph); gp_VertexInRangeAscending(theGraph, DFI); v++)
{
if (gp_IsNotDFSTreeRoot(theGraph, v))
continue;
Expand All @@ -73,16 +73,16 @@ int gp_CreateDFSTree(graphP theGraph)
while (sp_NonEmpty(theStack))
{
sp_Pop2(theStack, uparent, e);
u = gp_IsNotVertex(uparent) ? v : gp_GetNeighbor(theGraph, e);
u = gp_IsNotVertex(theGraph, uparent) ? v : gp_GetNeighbor(theGraph, e);

if (!gp_GetVertexVisited(theGraph, u))
if (!gp_GetVisited(theGraph, u))
{
gp_LogLine(gp_MakeLogStr3("V=%d, DFI=%d, Parent=%d", u, DFI, uparent));

gp_SetVertexVisited(theGraph, u);
gp_SetVertexIndex(theGraph, u, DFI++);
gp_SetVisited(theGraph, u);
gp_SetIndex(theGraph, u, DFI++);
gp_SetVertexParent(theGraph, u, uparent);
if (gp_IsArc(e))
if (gp_IsArc(theGraph, e))
{
gp_SetEdgeType(theGraph, e, EDGE_TYPE_CHILD);
gp_SetEdgeType(theGraph, gp_GetTwinArc(theGraph, e), EDGE_TYPE_PARENT);
Expand All @@ -92,9 +92,9 @@ int gp_CreateDFSTree(graphP theGraph)
tree edges to children or forward arcs of back edges */

e = gp_GetFirstArc(theGraph, u);
while (gp_IsArc(e))
while (gp_IsArc(theGraph, e))
{
if (!gp_GetVertexVisited(theGraph, gp_GetNeighbor(theGraph, e)))
if (!gp_GetVisited(theGraph, gp_GetNeighbor(theGraph, e)))
sp_Push2(theStack, u, e);
e = gp_GetNextArc(theGraph, e);
}
Expand Down Expand Up @@ -139,6 +139,9 @@ int gp_CreateDFSTree(graphP theGraph)

int gp_SortVertices(graphP theGraph)
{
if (theGraph == NULL)
return NOTOK;

return theGraph->functions.fpSortVertices(theGraph);
}

Expand All @@ -163,21 +166,21 @@ int _SortVertices(graphP theGraph)
Also, if any links go back to locations 0 to n-1, then they
need to be changed because we are reordering the vertices */

EsizeOccupied = gp_EdgeInUseIndexBound(theGraph);
EsizeOccupied = gp_EdgeInUseArraySize(theGraph);
for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e += 2)
{
if (gp_EdgeInUse(theGraph, e))
{
gp_SetNeighbor(theGraph, e, gp_GetVertexIndex(theGraph, gp_GetNeighbor(theGraph, e)));
gp_SetNeighbor(theGraph, e + 1, gp_GetVertexIndex(theGraph, gp_GetNeighbor(theGraph, e + 1)));
gp_SetNeighbor(theGraph, e, gp_GetIndex(theGraph, gp_GetNeighbor(theGraph, e)));
gp_SetNeighbor(theGraph, e + 1, gp_GetIndex(theGraph, gp_GetNeighbor(theGraph, e + 1)));
}
}

/* Convert DFSParent from v to DFI(v) or vice versa */

for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRangeAscending(theGraph, v); v++)
if (gp_IsNotDFSTreeRoot(theGraph, v))
gp_SetVertexParent(theGraph, v, gp_GetVertexIndex(theGraph, gp_GetVertexParent(theGraph, v)));
gp_SetVertexParent(theGraph, v, gp_GetIndex(theGraph, gp_GetVertexParent(theGraph, v)));

/* Sort by 'v using constant time random access. Move each vertex to its
destination 'v', and store its source location in 'v'. */
Expand All @@ -187,7 +190,7 @@ int _SortVertices(graphP theGraph)
location, so we cannot use index==v as a test for whether the
correct vertex is in location 'index'. */

_ClearVertexVisitedFlags(theGraph, FALSE);
_ClearAnyTypeVertexVisitedFlags(theGraph, FALSE);

/* We visit each vertex location, skipping those marked as visited since
we've already moved the correct vertex into that location. The
Expand All @@ -196,18 +199,18 @@ int _SortVertices(graphP theGraph)
location as visited, then sets its index to be the location from
whence we obtained the vertex record. */

for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRangeAscending(theGraph, v); v++)
{
srcPos = v;
while (!gp_GetVertexVisited(theGraph, v))
while (!gp_GetVisited(theGraph, v))
{
dstPos = gp_GetVertexIndex(theGraph, v);
dstPos = gp_GetIndex(theGraph, v);

gp_SwapVertexRec(theGraph, dstPos, theGraph, v);
gp_SwapAnyTypeVertexRec(theGraph, dstPos, theGraph, v);
gp_SwapVertexInfo(theGraph, dstPos, theGraph, v);

gp_SetVertexVisited(theGraph, dstPos);
gp_SetVertexIndex(theGraph, dstPos, srcPos);
gp_SetVisited(theGraph, dstPos);
gp_SetIndex(theGraph, dstPos, srcPos);

srcPos = dstPos;
}
Expand Down Expand Up @@ -254,12 +257,14 @@ int _SortVertices(graphP theGraph)

int gp_LowpointAndLeastAncestor(graphP theGraph)
{
stackP theStack = theGraph->theStack;
stackP theStack = NULL;
int v, u, uneighbor, e, L, leastAncestor;

if (theGraph == NULL)
return NOTOK;

theStack = theGraph->theStack;

if (!(theGraph->internalFlags & FLAGS_DFSNUMBERED))
if (gp_CreateDFSTree(theGraph) != OK)
return NOTOK;
Expand All @@ -282,12 +287,12 @@ int gp_LowpointAndLeastAncestor(graphP theGraph)

sp_ClearStack(theStack);

_ClearVertexVisitedFlags(theGraph, FALSE);
_ClearAnyTypeVertexVisitedFlags(theGraph, FALSE);

// This outer loop causes the connected subgraphs of a disconnected graph to be processed
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v);)
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRangeAscending(theGraph, v);)
{
if (gp_GetVertexVisited(theGraph, v))
if (gp_GetVisited(theGraph, v))
{
++v;
continue;
Expand All @@ -299,16 +304,16 @@ int gp_LowpointAndLeastAncestor(graphP theGraph)
sp_Pop(theStack, u);

// If not visited, then we're on the pre-order visitation, so push u and its DFS children
if (!gp_GetVertexVisited(theGraph, u))
if (!gp_GetVisited(theGraph, u))
{
// Mark u as visited, then push it back on the stack
gp_SetVertexVisited(theGraph, u);
gp_SetVisited(theGraph, u);
++v;
sp_Push(theStack, u);

// Push the DFS children of u
e = gp_GetFirstArc(theGraph, u);
while (gp_IsArc(e))
while (gp_IsArc(theGraph, e))
{
if (gp_GetEdgeType(theGraph, e) == EDGE_TYPE_CHILD)
{
Expand All @@ -327,7 +332,7 @@ int gp_LowpointAndLeastAncestor(graphP theGraph)

// Compute leastAncestor and L, the least lowpoint from the DFS children
e = gp_GetFirstArc(theGraph, u);
while (gp_IsArc(e))
while (gp_IsArc(theGraph, e))
{
uneighbor = gp_GetNeighbor(theGraph, e);
if (gp_GetEdgeType(theGraph, e) == EDGE_TYPE_CHILD)
Expand Down Expand Up @@ -377,12 +382,14 @@ int gp_LowpointAndLeastAncestor(graphP theGraph)

int gp_LeastAncestor(graphP theGraph)
{
stackP theStack = theGraph->theStack;
stackP theStack = NULL;
int v, u, uneighbor, e, leastAncestor;

if (theGraph == NULL)
return NOTOK;

theStack = theGraph->theStack;

if (!(theGraph->internalFlags & FLAGS_DFSNUMBERED))
if (gp_CreateDFSTree(theGraph) != OK)
return NOTOK;
Expand All @@ -405,9 +412,9 @@ int gp_LeastAncestor(graphP theGraph)
sp_ClearStack(theStack);

// This outer loop causes the connected subgraphs of a disconnected graph to be processed
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v);)
for (v = gp_GetFirstVertex(theGraph); gp_VertexInRangeAscending(theGraph, v);)
{
if (gp_GetVertexVisited(theGraph, v))
if (gp_GetVisited(theGraph, v))
{
++v;
continue;
Expand All @@ -418,14 +425,14 @@ int gp_LeastAncestor(graphP theGraph)
{
sp_Pop(theStack, u);

if (!gp_GetVertexVisited(theGraph, u))
if (!gp_GetVisited(theGraph, u))
{
gp_SetVertexVisited(theGraph, u);
gp_SetVisited(theGraph, u);
++v;
leastAncestor = u;

e = gp_GetFirstArc(theGraph, u);
while (gp_IsArc(e))
while (gp_IsArc(theGraph, e))
{
uneighbor = gp_GetNeighbor(theGraph, e);
if (gp_GetEdgeType(theGraph, e) == EDGE_TYPE_CHILD)
Expand Down
Loading