0
docs/source/_static/.keep
Normal file
0
docs/source/_static/.keep
Normal file
0
docs/source/_templates/.keep
Normal file
0
docs/source/_templates/.keep
Normal file
3
docs/source/changelog.rst
Normal file
3
docs/source/changelog.rst
Normal file
@@ -0,0 +1,3 @@
|
||||
Change Log
|
||||
==========
|
||||
|
||||
33
docs/source/conf.py
Normal file
33
docs/source/conf.py
Normal 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
25
docs/source/index.rst
Normal 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
180
docs/source/intro.rst
Normal 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
7
docs/source/modules.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
src
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
spqrtree
|
||||
10
docs/source/spqrtree.rst
Normal file
10
docs/source/spqrtree.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
spqrtree package
|
||||
================
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: spqrtree
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:undoc-members:
|
||||
Reference in New Issue
Block a user