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

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.