Skip to content

Issue #37 - Update planarity/c/graphLib/ contents + corresponding .pxd definition files + .pyx Cython source files in preparation for EAPS 4.0.2 release#38

Merged
john-boyer-phd merged 8 commits into
masterfrom
Issue37-graphLibBump
Apr 23, 2026
Merged

Issue #37 - Update planarity/c/graphLib/ contents + corresponding .pxd definition files + .pyx Cython source files in preparation for EAPS 4.0.2 release#38
john-boyer-phd merged 8 commits into
masterfrom
Issue37-graphLibBump

Conversation

@wbkboyer
Copy link
Copy Markdown
Member

@wbkboyer wbkboyer commented Mar 27, 2026

Contributes to #37

Type of change

Please check only relevant options:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Changes

Added

  • examples/full/test_specific_graph.py - reads in a graph, calls gp_Embed() and tests embed result integrity, then writes the result to file. Running the module as a script allows user to specify the input file, the parent of the output directory for that input file, and the graph algorithm extensions to run on that input file.

Updated

  • examples/ - Moved existing Python scripts leveraging the planarity package into the classic/ package, then created the full/ namespace package to contain the new test_specific_graph.py module and the (moved) planarity_app_utils.py
    • full/planarity_app_utils.py - moved __all__ variable to reside under docstring (see Module Level Dunder Names). examples/full/test_specific_graph.py needs neither max_num_edges_for_order() nor ENSURE_EDGE_CAPACITY_SPECIFIERS() functions, since we are reading a single graph using gp_Read() (which will always call gp_DynamicAddEdge() behind the scenes, which itself calls gp_EnsureEdgeCapacity() if gp_AddEdge() failed due to lack of space in the edge array) before we extend the graph with the structures associated with the desired the graph algorithm extension (see this comment).
      N.B. Due to the move, the planarity_app_utils module contents are no longer in the planarity package namespace
  • planarity/c/graphLib/ - Updated to reflect c/graphLib/ of current EAPS HEAD of master
  • planarity/__init__.py - exposed new Cython functions to gp_GetProjectVersionFull() and gp_GetLibPlanarityVersionFull() (which directly call into the cgraphLib
  • planarity/classic/
    • cplanarity.pxd -
      • gp_IsArc() renamed to gp_IsEdge() and now takes the graphP as well as the vertex index.
      • gp_Get(First|Last|Prev|Next)Arc() renamed to gp_Get(First|Last|Prev|Next)Edge() with no change to parameter list.
      • Removed explicit cdef before declarations within cdef extern blocks (see Cython docs - Interfacing with External C Code: Referencing C Header Files, where they say "The cdef extern from clause does three things:... 3) It treats all declarations within the block as though they started with cdef extern.")
      • Updated gp_AttachDrawPlanar() to gp_ExtendWith_DrawPlanar()
    • planarity.pyx -
      • In PGraph.embed_planar(), early-out if embedding has already been performed; then, call cplanarity.gp_ExtendWith_Planarity(self.theGraph) (even though this currently is a macro that returns OK, this will eventually become a function in a separate header file according to @john-boyer-phd , i.e. will need to extend the graphP with structures associated with core planarity)
      • In PGraph.embed_drawplanar(), now call cgraphLib.gp_ExtendWith_DrawPlanar() and updated RuntimeError messaging
      • In PGraph.edges(), updated calls to gp_IsArc() to gp_IsEdge() with the first parameter being the graphP associated with the Cython PGraph object. Also use gp_GetFirstEdge() rather than Arc
    • planarity.c - rebuilt on MacOS Tahoe 26.3.1 using Cython 3.2.4 with clang 22.1.1
  • planarity/full/
    • cg6IterationDefs.pxd - updated function names to reflect changes to the graphLib
    • cgraphLib.pxd - updated function and macro names and parameterization to reflect changes to the graphLib, e.g. gp_IsArc() --> gp_IsEdge() (Which now has graphP as first param), gp_EdgeIndexBound() --> gp_EdgeArraySize(), gp_EdgeInUseIndexBound() --> gp_EdgeInUseArraySize(), gp_Get(First|Next)Arc() --> gp_Get(First|Next)Edge(), gp_VertexInRange() --> gp_VertexInRangeAscending(). Also, gp_IsVertex() takes a graphP as first param (as mentioned above). Finally, added declarations for gp_ExtendWith_Planarity() and gp_ExtendWith_Outerplanarity() (although these macros will become functions whose declarations will be in their own respective header files in the future according to @john-boyer-phd ; see above) Finally, exposes definitions for gp_DrawPlanar_RenderTo(File|String)()
    • g6IterationUtils.pyx - updated G6(Read|Write)Iterator Cython classes so that method names match the C graphLib function names. Note also that we no longer end iteration before freeing (i.e. removed redundant behaviour in the graphLib).
    • graph.pyx - Updated Graph Cython class so that method names match the C graphLib function/macro names (taking care to ensure the right macros are being used due to the distinction of Principal Vertices vs. Virtual Vertices vs. Any Type Vertices), and updated the arguments passed down to the C layer. Removed is_graph_NULL(), since this method was only used as a check in gp_CopyGraph() (which I've updated to work around this removal from the public API). Finally, adds wrappers for gp_DrawPlanar_RenderTo(File|String)(), where the string functionality makes sure to clean up the renditionString returned from the graphLib after copying the contents to a Python string.
    • g6IterationUtils.c and graph.c - rebuilt on MacOS Tahoe 26.3.1 using Cython 3.2.4 with clang 22.1.1

Removed

  • N/A

Testing

  • Outline manual or automated tests performed and how it relates to the particular feature added or functionality changed
    • Tested that classic scripts all still produce expected output
    • Ran pytest tests/
    • Updated (currently private) EAPS testing Python script repo to leverage the wrapper to ensure test_all_graphs.py and edge_deletion_analysis.py both produce the same OK/NONEMBEDDABLE results for N=6,10.
      • NOTE: One test I did not perform was to replace the files fixed to resolve EAPS Issue #105 with their versions as of the prior commit (89ca75) to reproduce the pre-fix numInvalidOKs counts for $K_{3,3}$ search.
      • To do this test, make the following changes to graphK33Search.c:
        1. Restore extern int _MarkLowestXYPath() declaration to extern int _MarkHighestXYPath()
        2. Restore declaration for _TestForLowXYPath(), and restore definition of this function
        3. In _RunExtraK33Tests(), remove call to _ClearVisitedFlagsInBicomp() and restore call to _TestForLowXYPath(), and remove call to re-mark lowest x-y path
        4. In _TestForLowXYPath(), need to add checks for IC->py != NIL any time we look at the result of _MarkHighestXYPath(), because if we are in the E4 case and no path is found, we must be in an error state. This is because the original implementation of _MarkHighestXYPath() used to return TRUE (highest x-y path marked successfully) or FALSE (no x-y path exists OR an error was encountered when attempting to mark the path) but NOW returns OK (highest x-y path marked successfully) or NOTOK (failed to mark path between x and y), so in order to verify that a path exists, you need to also check that IC->py != NIL (i.e. if no path exists between x and y, no error would be emitted by _MarkHighestXYPath(), and the low connection points would be NIL).
    • Built the source distribution and uploaded the updated package to TestPyPI, then installed into a fresh virtual environment to run the aforementioned Python scripts
  • Upload logs or provide relevant snippets of terminal output to demo functionality
Testing examples/full/test_specific_graph.py and all examples/classic examples, plus pytest

Installing dependencies (note especially setuptools to install from TestPyPI using --no-build-isolation flag for pip; see this comment for details):

wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python3.14 -m venv .venv
wbkboyer@Wandas-MacBook-Pro planarity-PR38 % source .venv/bin/activate
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pip install --upgrade pip
...
Successfully installed pip-26.0.1
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pip install setuptools
Collecting setuptools
  Using cached setuptools-82.0.1-py3-none-any.whl.metadata (6.5 kB)
Using cached setuptools-82.0.1-py3-none-any.whl (1.0 MB)
Installing collected packages: setuptools
Successfully installed setuptools-82.0.1
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pip install networkx
...
Successfully installed networkx-3.6.1
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pip install matplotlib
...
Successfully installed contourpy-1.3.3 cycler-0.12.1 fonttools-4.62.1 kiwisolver-1.5.0 matplotlib-3.10.8 numpy-2.4.4 packaging-26.1 pillow-12.2.0 pyparsing-3.3.2 python-dateutil-2.9.0.post0 six-1.17.0
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pip install pytest
Collecting pytest
...
Successfully installed iniconfig-2.3.0 pluggy-1.6.0 pygments-2.20.0 pytest-9.0.3

Installing planarity package from TestPyPI:

(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps --no-build-isolation planarity
Looking in indexes: https://test.pypi.org/simple/
Collecting planarity
  Using cached planarity-0.7.11-cp314-cp314-macosx_10_15_universal2.whl
Installing collected packages: planarity
Successfully installed planarity-0.7.11
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/full/test_specific_graph.py -i ~/git/edge-addition-planarity-suite-fork/c/samples/Petersen.txt -o .

===================================================
This program imports the planarity package, which
is based on the Edge Addition Planarity Suite
version 4.0.2.0, which contains the libPlanarity
graph library version 4:0:0.
===================================================

Planarity embed result was NONEMBEDDABLE.
	The graph is not planar
Draw Planar embed result was NONEMBEDDABLE.
	The graph is not planar
Outerplanarity embed result was NONEMBEDDABLE.
	The graph is not outerplanar
K_{2, 3} Search embed result was NONEMBEDDABLE.
	The graph is not K_{2, 3}-free
K_{3, 3} Search embed result was NONEMBEDDABLE.
	The graph is not K_{3, 3}-free
K_4 Search embed result was NONEMBEDDABLE.
	The graph is not K_4-free
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/full/test_specific_graph.py -i ~/git/edge-addition-planarity-suite-fork/c/samples/maxPlanar5.txt -o . -c d

===================================================
This program imports the planarity package, which
is based on the Edge Addition Planarity Suite
version 4.0.2.0, which contains the libPlanarity
graph library version 4:0:0.
===================================================

Do you wish to render the drawing to screen (s) or file (f)? (Select any other input to dismiss.)
	s
----1----
| | |   |
| | -4--|
| |  ||||
| -5--|||
|  |  |||
---3---||
 |     ||
 ---2----
         

Draw Planar embed result was OK.
	The graph is planar
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/full/test_specific_graph.py -i ~/git/edge-addition-planarity-suite-fork/c/samples/maxPlanar5.txt -o . -c d

===================================================
This program imports the planarity package, which
is based on the Edge Addition Planarity Suite
version 4.0.2.0, which contains the libPlanarity
graph library version 4:0:0.
===================================================

Do you wish to render the drawing to screen (s) or file (f)? (Select any other input to dismiss.)
	f
Draw Planar embed result was OK.
	The graph is planar
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % ls
maxPlanar5	Petersen
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % ls maxPlanar5 
maxPlanar5.s.d.out.txt		maxPlanar5.s.d.render.txt
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % ls Petersen 
Petersen.s.2.out.txt	Petersen.s.4.out.txt	Petersen.s.o.out.txt
Petersen.s.3.out.txt	Petersen.s.d.out.txt	Petersen.s.p.out.txt

Running examples/classic/ scripts:

(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/ascii.py 
----1----
| | |   |
| | -4--|
| |  ||||
| -3--|||
|  |  |||
---2---||
 |     ||
 ---5----
         

(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/graph_formats.py 
False
False
False
False
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/kuratowski.py 
False
[('b', 'd'), ('b', 'c'), ('b', 'e'), ('b', 'a'), ('e', 'd'), ('e', 'c'), ('e', 'a'), ('a', 'd'), ('a', 'c'), ('d', 'c')]
True
[]
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/networkx_draw.py 
Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/networkx_interface.py 
False
[(0, 3), (0, 2), (0, 4), (0, 1), (3, 1), (3, 2), (3, 4), (2, 1), (2, 4), (4, 1)]
(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/pgraph_class.py 
[0, 1, 2, 3, 4]
{1: 0, 2: 1, 3: 2, 4: 3, 5: 4}
[(0, 4), (0, 3), (0, 2), (0, 1), (1, 4), (1, 3), (1, 2), (2, 4), (2, 3), (3, 4)]
False
[(0, 3), (0, 2), (0, 4), (0, 1), (1, 3), (1, 4), (1, 2), (2, 4), (2, 3), (3, 4)]
----1----
|  |    |
|  --5--|
|   || ||
--4--| ||
 ||  | ||
 |--2--||
 |    |||
 ---3----
         

(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % python ~/git/planarity/examples/classic/write_adjlist.py 
{1: 'c', 2: 'e', 3: 'b', 4: 'd', 5: 'a'}

Running pytest:

(.venv) wbkboyer@Wandas-MacBook-Pro planarity-PR38 % pytest -v ~/git/planarity
================================ test session starts =================================
platform darwin -- Python 3.14.2, pytest-9.0.3, pluggy-1.6.0 -- /Users/wbkboyer/planarity-PR38/.venv/bin/python3.14
cachedir: .pytest_cache
rootdir: /Users/wbkboyer/git/planarity
configfile: pyproject.toml
collected 19 items                                                                   

../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_edgelist_input PASSED [  5%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_edgelist_input_function PASSED [ 10%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_adj_input PASSED [ 15%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_adj_input_function PASSED [ 21%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_adj_symmetric PASSED [ 26%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_adj_set PASSED [ 31%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_is_planar_adj_list PASSED [ 36%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_goldner_harary PASSED [ 42%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_kuratowski_k5 PASSED [ 47%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_kuratowski_k5_function PASSED [ 52%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_no_kuratowski_k5m PASSED [ 57%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_draw_text PASSED [ 63%]
../git/planarity/tests/test_planarity.py::TestPlanarity::test_write_adjlist PASSED [ 68%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_is_planar PASSED [ 73%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_is_planar_unions PASSED [ 78%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_goldner_harary PASSED [ 84%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_kuratowski_k5 PASSED [ 89%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_kuratowski_k5m PASSED [ 94%]
../git/planarity/tests/test_planarity_networkx.py::TestPlanarityNetworkX::test_networkx_graph PASSED [100%]

================================= 19 passed in 0.10s =================================

Zip files of tables vs. prior version of graphLib:

tables.zip

tables-old.zip

…D of master.

Tested that classic scripts all still produce expected output, ran pytest, and updated (currently private) EAPS testing Python script repo to leverage the wrapper to ensure test_all_graphs.py and edge_deletion_analysis.py both produce the same OK/NONEMBEDDABLE results for N=6,10.
@wbkboyer wbkboyer requested a review from john-boyer-phd March 27, 2026 01:02
…D of master, updating .pxd definition files, and updating C library function calls in .pyx files.
… embed result integrity, then writes the result to file. Running the module as a script allows user to specify the input file, the parent of the output directory for that input file, and the graph algorithm extensions to run on that input file.
Copy link
Copy Markdown
Member

@john-boyer-phd john-boyer-phd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great work, only two minor changes:

  1. Can you please make the new "specific graph" script (full api 101 demo) also emit the core embedResult from gp_Embed()? If multiple algorithms are executed, then a result for each would be great (the graph is planar/non-planar, the graph contains/doesn't contain a K3,3 homeomorph, etc.).

  2. Please can you expose two functions from graphLib.h: gp_GetProjectVersionFull and gp_GetLibPlanarityVersionFull? These are useful so that a user of the planarity python package can always find out about the underlying EAPS version. Ideally, you could even have your specific graph start out by emitting the "The planarity package is based on the Edge Addition Planarity Suite version N.N.N.N, which contains the libPlanarity graph library version N:N:N" or similar.

@wbkboyer wbkboyer requested a review from john-boyer-phd April 16, 2026 21:55
Copy link
Copy Markdown
Member

@john-boyer-phd john-boyer-phd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really coming along. Just a few more requested changes:

  1. Moving most of planarity_app_utils.py to the bottom of test_specific_graph.py
  2. Removing the edge capacity specifiers method and logic.
  3. Tweak to return value of planarity package info method
  4. Fix up algo name versus name of what algo returns
  5. Comment fix in max num edges method

Discuss necessity and name of two non-EAPS methods in graph.pyx (and any non-EAPS methods anywhere else, e.g., G6).

Comment thread examples/full/test_specific_graph.py
Comment thread examples/test_specific_graph.py Outdated
Comment thread examples/full/planarity_app_utils.py
Comment thread examples/full/planarity_app_utils.py
Comment thread examples/full/planarity_app_utils.py
Comment thread examples/test_specific_graph.py Outdated
Comment thread examples/test_specific_graph.py Outdated
Comment thread planarity/full/planarity_app_utils.py Outdated
Comment thread planarity/__init__.py Outdated
Comment thread planarity/__init__.py
Separated classic and full example scripts into their own namespace packages under examples/ directory.

Verified that pip install planarity of sdist published to TestPyPI was able to be used with examples/full/test_specific_graph.py
Copy link
Copy Markdown
Member

@john-boyer-phd john-boyer-phd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent addressing of all requests.

@john-boyer-phd john-boyer-phd merged commit 99688ea into master Apr 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix defect that K_{3,3} search doesn't find a K_{3,3} homeomorph in the 6-vertex 13-edge graph with G6 encoding of EV~w

2 participants