Initial commit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 09:33:44 +08:00
parent 06153f7d76
commit 23282de176
26 changed files with 9732 additions and 0 deletions

20
docs/Makefile Normal file
View File

@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

35
docs/make.bat Normal file
View File

@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

1
docs/requirements.txt Normal file
View File

@@ -0,0 +1 @@
sphinx_rtd_theme

View File

View File

View File

@@ -0,0 +1,3 @@
Change Log
==========

33
docs/source/conf.py Normal file
View File

@@ -0,0 +1,33 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import os
import sys
sys.path.insert(0, os.path.abspath('../../src/'))
import spqrtree
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'Pure Python SPQR-Tree Implementation'
copyright = '2026, imacat'
author = 'imacat'
release = spqrtree.VERSION
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = ["sphinx.ext.autodoc"]
templates_path = ['_templates']
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']

25
docs/source/index.rst Normal file
View File

@@ -0,0 +1,25 @@
spqrtree
========
A pure Python SPQR-tree implementation for biconnected graphs.
**spqrtree** decomposes a biconnected graph into its triconnected
components and organizes them as an SPQR-tree, a classical data
structure in graph theory used for planarity testing, graph drawing,
and network analysis.
.. toctree::
:maxdepth: 2
:caption: Contents:
intro
spqrtree
changelog
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

180
docs/source/intro.rst Normal file
View File

@@ -0,0 +1,180 @@
Introduction
============
What is an SPQR-Tree?
---------------------
An SPQR-tree is a tree data structure that represents the decomposition
of a biconnected graph into its triconnected components. Each node of
the tree corresponds to one of four types:
- **S-node** (series): a simple cycle.
- **P-node** (parallel): a bundle of parallel edges between two poles.
- **Q-node**: a single real edge (degenerate case).
- **R-node** (rigid): a 3-connected subgraph that cannot be further
decomposed.
SPQR-trees are widely used in graph drawing, planarity testing,
and network reliability analysis.
Features
--------
- Pure Python --- no compiled extensions or external dependencies.
- Handles multigraphs (parallel edges between the same vertex pair).
- Implements the Gutwenger & Mutzel (2001) algorithm with corrections
to Hopcroft & Tarjan (1973).
- Simple ``dict``-based input for quick prototyping.
- Typed package with :pep:`561` support.
Installation
------------
Install from `PyPI <https://pypi.org/project/spqrtree/>`_ with pip:
.. code-block:: bash
pip install spqrtree
Or install the latest development version from GitHub:
.. code-block:: bash
pip install git+https://github.com/imacat/spqrtree.git
Requires Python 3.10 or later.
Quick Start
-----------
Build an SPQR-tree from an adjacency-list dictionary:
.. code-block:: python
from spqrtree import SPQRTree
# A simple diamond graph (K4 minus one edge)
graph = {
1: [2, 3, 4],
2: [1, 3, 4],
3: [1, 2, 4],
4: [1, 2, 3],
}
tree = SPQRTree(graph)
print(tree.root.type) # NodeType.R
print(len(tree.nodes())) # number of SPQR-tree nodes
The input dictionary maps each vertex to its list of neighbors. For
each pair ``(u, v)`` where ``u < v``, one edge is added.
Usage Guide
-----------
Inspecting the Tree
~~~~~~~~~~~~~~~~~~~
The :class:`~spqrtree.SPQRTree` object exposes two main attributes:
- :attr:`~spqrtree.SPQRTree.root` --- the root
:class:`~spqrtree.SPQRNode` of the tree.
- :meth:`~spqrtree.SPQRTree.nodes` --- all nodes in BFS order.
.. code-block:: python
from spqrtree import SPQRTree, NodeType
graph = {
0: [1, 2],
1: [0, 2, 3],
2: [0, 1, 3],
3: [1, 2],
}
tree = SPQRTree(graph)
for node in tree.nodes():
print(node.type, node.poles)
Each :class:`~spqrtree.SPQRNode` has the following attributes:
- ``type`` --- a :class:`~spqrtree.NodeType` enum (``S``, ``P``,
``Q``, or ``R``).
- ``skeleton`` --- the skeleton graph containing the real and virtual
edges of the component.
- ``poles`` --- the two vertices shared with the parent component.
- ``parent`` --- the parent node (``None`` for the root).
- ``children`` --- the list of child nodes.
Understanding Node Types
~~~~~~~~~~~~~~~~~~~~~~~~
**S-node (series):**
Represents a cycle. The skeleton is a simple polygon whose edges
alternate between real edges and virtual edges leading to children.
**P-node (parallel):**
Represents parallel edges between two pole vertices. The skeleton
contains three or more edges (real and/or virtual) between the same
pair of poles.
**R-node (rigid):**
Represents a 3-connected component that cannot be further decomposed
by any separation pair. The skeleton is a 3-connected graph.
**Q-node:**
Represents a single real edge. Q-nodes appear as leaves of the tree.
Using a MultiGraph
~~~~~~~~~~~~~~~~~~
For more control, build a
:class:`~spqrtree._graph.MultiGraph` directly:
.. code-block:: python
from spqrtree._graph import MultiGraph
from spqrtree import SPQRTree
g = MultiGraph()
g.add_edge(0, 1)
g.add_edge(1, 2)
g.add_edge(2, 0)
g.add_edge(1, 3)
g.add_edge(3, 2)
tree = SPQRTree(g)
References
----------
The implementation is based on the following papers:
- J. Hopcroft and R. Tarjan, "Dividing a graph into triconnected
components," *SIAM Journal on Computing*, vol. 2, no. 3,
pp. 135--158, 1973.
`doi:10.1137/0202012 <https://doi.org/10.1137/0202012>`_
- G. Di Battista and R. Tamassia, "On-line planarity testing,"
*SIAM Journal on Computing*, vol. 25, no. 5, pp. 956--997, 1996.
`doi:10.1137/S0097539794280736
<https://doi.org/10.1137/S0097539794280736>`_
- C. Gutwenger and P. Mutzel, "A linear time implementation of
SPQR-trees," *Proc. 8th International Symposium on Graph Drawing
(GD 2000)*, LNCS 1984, pp. 77--90, Springer, 2001.
`doi:10.1007/3-540-44541-2_8
<https://doi.org/10.1007/3-540-44541-2_8>`_
Acknowledgments
---------------
The test suite was validated against the SPQR-tree implementation in
`SageMath <https://www.sagemath.org/>`_, which served as the reference
for verifying correctness of the decomposition results.

7
docs/source/modules.rst Normal file
View File

@@ -0,0 +1,7 @@
src
===
.. toctree::
:maxdepth: 4
spqrtree

10
docs/source/spqrtree.rst Normal file
View File

@@ -0,0 +1,10 @@
spqrtree package
================
Module contents
---------------
.. automodule:: spqrtree
:members:
:show-inheritance:
:undoc-members: