Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Graphs belong to the class `UGraph` or `DGraph` for undirected or directed graph
- `g.incidence()` incidence matrix

### Properties and methods of a vertex
Vertices belong to the class `UVertex` (for undirected graphs) or `DVertex` (for directed graphs), which are each subclasses of `Vertex`.
Vertices are instances of the class `Vertex`, for both undirected and directed graphs.

- `v.coord` the coordinate vector for embedded graph (optional)
- `v.name` the name of the vertex (optional)
Expand All @@ -123,11 +123,11 @@ Each edge references a pair of vertices, the graph lists all of its edges in `g.
Consider a user class `Foo` that we would like to connect using a graph _overlay_, ie.
instances of `Foo` becomes vertices in a graph.

- Have it subclass either `DVertex` or `UVertex` depending on graph type
- Have it subclass `Vertex`
- Then place instances of `Foo` into the graph using `add_vertex` and create edges as required

```
class Foo(UVertex):
class Foo(Vertex):
# foo stuff goes here

f1 = Foo(...)
Expand Down
20 changes: 8 additions & 12 deletions docs/source/common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@ The graph classes represent a single graph, either directed or undirected, and t
:private-bases:
:top-classes: pgraph.PGraph.Graph

The vertices in a directed graph (``DGraph``) inherit from :class:`DVertex` and the
vertices in an undirected graph (``UGraph``) inherit from :class:`UVertex`.

.. inheritance-diagram:: pgraph.PGraph.UVertex pgraph.PGraph.DVertex
:parts: 1

The vertex classes share
almost their entire interface, defined once on their common base classes
(:class:`Graph`, :class:`Vertex`). This section documents that
shared interface by task rather than by class; see :doc:`construction` for
the :class:`DGraph` and :class:`UGraph` classes and :doc:`edges_vertices` for
what's specific to directed vs. undirected vertices.
The vertices of both kinds of graph are :class:`Vertex` objects: a vertex has
no direction of its own, the graph it belongs to decides how an edge is
recorded at its ends.

The graph classes share almost their entire interface, defined once on their
common base class :class:`Graph`. This section documents that shared interface
by task rather than by class; see :doc:`construction` for the :class:`DGraph`
and :class:`UGraph` classes and :doc:`edges_vertices` for vertices and edges.

Edges are represented by the :class:`Edge` class, which is used by both directed and undirected graphs.

Expand Down
9 changes: 0 additions & 9 deletions docs/source/dvertex.rst

This file was deleted.

12 changes: 5 additions & 7 deletions docs/source/edges_vertices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ and to add them to the graph.
.. runblock:: pycon
:session:

>>> from pgraph import UGraph, UVertex, Edge
>>> from pgraph import UGraph, Vertex, Edge
>>> import numpy as np
>>> g = UGraph()

Expand All @@ -31,8 +31,8 @@ Next, we will explicitly create two vertices
.. runblock:: pycon
:session:

>>> v1 = UVertex(np.random.rand(2))
>>> v2 = UVertex(np.random.rand(2))
>>> v1 = Vertex(np.random.rand(2))
>>> v2 = Vertex(np.random.rand(2))


and then add them to the graph
Expand Down Expand Up @@ -77,7 +77,7 @@ Alternatively, we can create a vertex and *connect* it to an existing vertex, wh
.. runblock:: pycon
:session:

>>> v3 = UVertex(np.random.rand(2))
>>> v3 = Vertex(np.random.rand(2))
>>> g.add_vertex(v3)
>>> v2.connect(v3)
>>> print(g)
Expand All @@ -88,11 +88,9 @@ The ``connect`` method is available on both the
directed and undirected vertex classes.


.. note:: Where ever a vertex or edge is required, a subclass of the appropriate base class can be used. For example, we can create a subclass of ``UVertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.
.. note:: Where ever a vertex or edge is required, a subclass of the appropriate base class can be used. For example, we can create a subclass of ``Vertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.

.. toctree::
:maxdepth: 2

dvertex
uvertex
edge
8 changes: 4 additions & 4 deletions docs/source/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ we can obtain the reference by indexing the graph object. For example vertex 1 i

>>> g[1]

and is an instance of ``UVertex``, a vertex in an undirected graph; it has the coordinate
and is an instance of ``Vertex``; it has the coordinate
:math:`(0.6028, 0.5449)` and has been assigned a default name ``"#1"`` but we could specify
an explicit name to ``add_vertex``.
We can also reference a vertex by its name
Expand Down Expand Up @@ -201,15 +201,15 @@ Arbitrary data can be attached to any vertex or edge by assigning values to attr

This exploits the flexible nature of Python, but care must be taken to avoid name clashes with existing attributes.

A more robust and Pythonic approach is to create a subclass of the ``UVertex`` or ``DVertex`` classes class and
declare them at graph creation time. For example, we can create a subclass of ``UVertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.
A more robust and Pythonic approach is to create a subclass of the ``Vertex`` class and
declare them at graph creation time. For example, we can create a subclass of ``Vertex`` called ``MyVertex`` and a subclass of ``Edge`` called ``MyEdge`` and then create a new graph using these classes.

.. runblock:: pycon
:session:

>>> import pgraph
>>> import numpy as np
>>> class MyVertex(pgraph.UVertex):
>>> class MyVertex(pgraph.Vertex):
... pass
>>> class MyEdge(pgraph.Edge):
... pass
Expand Down
8 changes: 4 additions & 4 deletions docs/source/modification.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Adding and removing vertices and edges
========================================

Building up and tearing down a graph's structure. ``connect()`` is shown
here in its base-class form; :doc:`DVertex <dvertex>` and
:doc:`UVertex <uvertex>` override it with different edge-list bookkeeping
-- see those pages for the concrete behaviour. See :class:`Edge` for
Building up and tearing down a graph's structure. ``connect()`` is the same
for both kinds of graph: the graph decides how the edge is recorded at its
vertices, so an undirected edge is found from either end and a directed one
leaves its start vertex and enters its end vertex. See :class:`Edge` for
constructing/removing an edge directly rather than via a vertex or graph.

Graph
Expand Down
39 changes: 19 additions & 20 deletions docs/source/policy.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Object lifecycle and graph-membership policy
=============================================

``Vertex``, ``UVertex``, ``DVertex`` and ``Edge`` can all be constructed
``Vertex`` and ``Edge`` can both be constructed
directly, independent of any graph. This is deliberate -- it is not an
oversight and not a "factory-only" design -- but it means the rules for what
those objects can and can't do *before* they belong to a graph need to be
Expand All @@ -10,7 +10,7 @@ stated explicitly rather than left implicit.
Standalone construction
------------------------

A vertex or edge built directly, e.g. ``UVertex(coord=[1, 2], name="A")`` or
A vertex or edge built directly, e.g. ``Vertex(coord=[1, 2], name="A")`` or
``Edge(v1, v2, cost=5.0)``, is a fully valid object in its own right. The
main supported use of this is lightweight, graph-independent work: building a
couple of vertices purely to demonstrate or test :class:`Edge` cost
Expand All @@ -23,17 +23,17 @@ anything (see below) until it is added to a graph via
Adding a vertex to a graph
---------------------------

:meth:`UGraph.add_vertex` and :meth:`DGraph.add_vertex` each only accept
their own matching vertex subclass -- a ``UVertex`` (or coordinate data, from
which one is built) for :class:`UGraph`, a ``DVertex`` for :class:`DGraph`.
Passing the wrong kind of vertex -- a plain ``Vertex``, or the other
graph's subclass -- raises ``TypeError`` rather than being silently accepted
or converted.
A vertex is the same for undirected and directed graphs: it has no
direction of its own, and the graph it belongs to decides how an edge is
recorded at its ends. :meth:`Graph.add_vertex` accepts coordinate data, from
which a vertex is built, or an existing ``Vertex`` that does not belong to a
graph. A graph given a ``vertex_class`` only accepts instances of that class;
passing any other vertex raises ``TypeError`` rather than being silently
accepted or converted. A vertex that already belongs to a graph raises
``ValueError``; remove it from that graph first.

This is the mechanism that makes graph membership meaningful: once added, a
vertex's ``._graph`` is fixed to that specific graph instance, and its
concrete type (``UVertex`` or ``DVertex``) is guaranteed correct for that
graph's edge semantics (undirected vs. directed edge-list bookkeeping).
vertex's ``._graph`` is fixed to that specific graph instance.

Connecting two vertices
-------------------------
Expand All @@ -46,12 +46,9 @@ Connecting two vertices
- If the two vertices belong to different graph instances, ``connect()``
raises ``ValueError``.

There is deliberately no separate check for "same vertex subclass" (e.g.
rejecting a ``UVertex``-to-``DVertex`` connection directly). It doesn't need
one: since a ``UVertex`` can only ever belong to a ``UGraph`` and a
``DVertex`` only to a ``DGraph`` (enforced by ``add_vertex()`` above), the
same-graph check above already makes a ``UVertex``-to-``DVertex`` connection
impossible as a structural consequence, not as a separately-maintained rule.
There is no such thing as connecting an "undirected" vertex to a "directed"
one, since a vertex is neither: the kind of edge is the graph's, so the
same-graph check above is the only one needed.

Constructing an ``Edge`` directly
-----------------------------------
Expand Down Expand Up @@ -79,15 +76,17 @@ Summary
* - Operation
- Requires graph membership?
- Failure mode
* - ``UVertex()`` / ``DVertex()`` / ``Vertex()``
* - ``Vertex()``
- No
- --
* - ``Edge(v1, v2)``
- No (cost falls back to ``None`` if ungraphed/cross-graph)
- --
* - ``graph.add_vertex(v)``
- ``v`` must be the graph's own vertex subclass, or coordinate data
- ``TypeError`` on wrong vertex subclass
- ``v`` must be of the graph's ``vertex_class`` and not already in a
graph, or coordinate data
- ``TypeError`` on a vertex of another class, ``ValueError`` if it is
already in a graph
* - ``v1.connect(v2)`` / ``graph.add_edge(v1, v2)``
- Both vertices must already belong to the same graph
- ``ValueError`` if either is ungraphed or they belong to different
Expand Down
9 changes: 0 additions & 9 deletions docs/source/uvertex.rst

This file was deleted.

Loading
Loading