GraphPack Implementation Design and Details

Introduction

GraphPack contains the data structure for storing a graph of connected vertices and edges. Vertices are of type Vertex class, and edges have type Edge class. All the vertices are linked together in a doubly-linked list, which is held by the Graph class in variable vlist. Similarly, the edges are chained together and held by variable elist. There can be at most one edge between any two vertices.

The graph data structure is similar to an adjacency list as each vertex contains a list of attached edges. However the list of attached edges doesn't contain the real Edge objects since then there would be two copies of each Edge, and deleting an edge from the graph would require an O(number edges) search to find both copies of the Edge. Instead, we created an EdgeAlias class which points to the real Edge object. Every vertex has a list of EdgeAliases, each of which point to the real Edge. The Edge has pointers to both Vertex objects as well as both EdgeAlias objects, making the deletion of an edge efficient.

For example, the graph:

has this data structure:

When a user of GraphPack wishes to see a vertex's attached edges, we pass them the list of EdgeAliases. In order to make the graph data structure transparent to the user, we created an EdgeList interface which both EdgeAlias and Edge implement. Thus the user does not have to know about EdgeAliases in order to use any list of Edges. If the user needs an operation which is specific to Edge, not EdgeList, they can call EdgeList.getEdge() which returns a real Edge object.

Highlighting

For Zarbiff we needed to implement highlighting, ie the creation of a special subset of vertices and edges within the graph. We considered two ways of implementing highlighted vertices (same for edges)
  1. The graph has two lists: one of highlighted vertices, and one of plain vertices. However, if we implemented this there would be no easy way of handing users a complete list of ALL vertices, without copying and concatenating the lists together.
  2. Allow each Vertex object to be in two lists at the same time: the list of all graph vertices, and the list of highlighted vertices. Similarly for edges.
We implemented (2) and created a Qnode class to implement a quadrupally-linked object. Vertex, Edge and EdgeAlias all extend Qnode.

Directed Graphs

DirGraph extends Graph and implements the same GraphDrawingInterface. DirGraph contains DirVertex and DirEdge, which extend Vertex and Edge. The data structure is essentially the same as Graph, however Edge(v1, v2) refers semantically to an edge from v1 to v2, instead of just an edge between the two vertices. DirVertex contains two lists of attached edges instead of one: a list of outgoing edges and a list of incoming edges. The user of GraphPack must know this, and must explicitly examine both lists in order to get all attached edges. The edge(v1,v2) will have two edge aliases: one in v1's outgoing edge list, and one in v2's incoming edge list. A directed graph can have two edges between a pair of vertices: one edge in each direction.

Drawing graphs

Drawing a directed edge is difficult since if there are two edges between a pair of vertices then the edge must bow outward. Since it would be inefficient to recalculate the arc for a bowed out edge each time the edge is drawn, the information needed to draw the edge is stored. We wanted to separate the graph data structure from the details of drawing the graph as much as possible, so all the classes to draw graphs, vertices, and edges are in GraphDrawingPack. DirEdge contains a variable of type EdgeDrawingInterface (from GraphDrawingPack) and currently instatiates it to DirEdgeDrawing. Whenever one of DirEdge's vertices is moved, or another edge is added between its two vertices, the information to draw the edge must be recomputed, thus an update() function is called.

To be consistent, we did the same for vertices. Each vertex contains a variable of type VertexDrawingInterface, and instantiates it, currently to VertexDrawing. No information needs to be updated however, so drawing vertices is easier than edges.

See GraphDrawingPack README for futher details on drawing.

Object Model

Below is the object model for the GraphPack package. Classes are represented as boxes, circle edges represent "implements", arrow edges represent "contains" or "has a pointer to", and large triangles represent "inherits from".

Note: the relation between GraphPack and GraphDrawingPack is not shown because the model gets too complicated. For further information, see GraphDrawingPack, UndoPack and Properties