Directed Graph

Build Status

Introduction

An integral part of storing, manipulating, and retrieving numerical data are data structures or as they are called in Dart: collections. Arguably the most common data structure is the list. It enables efficient storage and retrieval of sequential data that can be associated with an index.

A more general (non-linear) data structure where an element may be connected to one, several, or none of the other elements is called a graph.

Graphs are useful when keeping track of elements that are linked to or are dependent on other elements. Examples include: network connections, links in a document pointing to other paragraphs or documents, foreign keys in a relational database, file dependencies in a build system, etc.

The package directed_graph contains a rudimentary implementation of a Dart graph that follows the recommendations found in graphs-examples and is compatible with the algorithms provided by graphs. It is simple to use and includes methods that enable manipulating vertices and edges. The library provides access to algorithms for the calculation of the shortest path between vertices, detection of cycles, or the retrieval of a topological ordering of the graph vertices.

Terminology

Elements of a graph are called vertices (or nodes) and neighbouring vertices are connected by edges. The figure below shows a directed graph with unidirectional edges depicted as arrows. Graph edges are emanating from a vertex and ending at a vertex.

Directed Graph Image

  • In-degree of a vertex: Number of edges ending at this vertex. For example, vertex H has in-degree 3.
  • Out-degree of a vertex: Number of edges starting at this vertex. For example, vertex F has out-degree 1.
  • Source: A vertex with in-degree zero is called (local) source. Vertices A and D in the graph above are local sources.
  • Edge: An ordered pair of connected vertices. For example, the edge (A, C) starts at vertex A and ends at vertex C.
  • Path: A directed path is an ordered list of at least two connected vertices. The path (A, E, G) starts at vertex A and ends at vertex G.
  • Cycle: A path that starts and ends at the same vertex. For example, a self-loop is a cycle. The dashed edges in the figure complete a cycle.
  • DAG: An acronym for Directed Acyclic Graph, a directed graph without cycles.
  • Topological ordering: An ordered list of all vertices in a graph such that vertex1 occurs before vertex2 if there is an edge pointing from vertex1 to vertex2. A topological ordering of the graph above is: A, D, B, C, E, K, F, G, H, I, L. Hereby, dashed edges were disregarded since a cyclic graph does not have a topological ordering.

Note: In the context of this package the definition of edge might be more lax compared to a rigorous mathematical definition. For example, self-loops, that is edges connecting a vertex to itself are explicitly allowed.

For simplicity, edges are (internally) stored in a structure of type Map<Vertex<T>, List<Vertex<T>>> and there is nothing preventing a user from inserting self-loops or multiple edges between the same nodes. While self-loops will render a graph cyclic, multiple entries of the same edge do not affect the algorithms calculating a topological ordering of vertices.

Usage

To use this library include directed_graph as a dependency in your pubspec.yaml file. The example below shows how to construct a graph. The constructor takes an optional comparator function as parameter. If a comparator is specified, vertices are sorted accordingly. For more information see comparator.

import 'package:directed_graph/directed_graph.dart';

// To run this program navigate to
// the folder 'directed_graph/example'
// in your terminal and type:
//
// # dart bin/example.dart
//
// followed by enter.
void main() {
  var a = Vertex<String>('A');
  var b = Vertex<String>('B');
  var c = Vertex<String>('C');
  var d = Vertex<String>('D');
  var e = Vertex<String>('E');
  var f = Vertex<String>('F');
  var g = Vertex<String>('G');
  var h = Vertex<String>('H');
  var i = Vertex<String>('I');
  var k = Vertex<String>('K');
  var l = Vertex<String>('L');

  int comparator(
    Vertex<String> vertex1,
    Vertex<String> vertex2,
  ) {
    return vertex1.data.compareTo(vertex2.data);
  }

  int inverseComparator(Vertex<String> vertex1, Vertex<String> vertex2) =>
      -comparator(vertex1, vertex2);

  var graph = DirectedGraph<String>(
    {
      a: [b, h, c, e],
      d: [e, f],
      b: [h],
      c: [h, g],
      f: [i],
      i: [l],
      k: [g, f]
    },
    comparator: comparator,
  );

  print('Example Directed Graph...');
  print('\n graph.toString():');
  print(graph);

  print('\n Is Acylic:');
  print(graph.isAcyclic());

  print('\n Strongly connected components:');
  print(graph.stronglyConnectedComponents());

  print('\n ShortestPath(orange,darkRed):');
  print(graph.shortestPath(d, l));

  print('\n InDegree(C):');
  print(graph.inDegree(c));

  print('\n OutDegree(C)');
  print(graph.outDegree(c));

  print('\n Vertices sorted in lexicographical order:');
  print(graph.vertices);

  print('\n Vertices sorted in inverse lexicographical order:');
  graph.comparator = inverseComparator;
  print(graph.vertices);
  graph.comparator = comparator;

  print('\n InDegreeMap:');
  print(graph.inDegreeMap);

  print('\n Sorted Topological Ordering:');
  print(graph.sortedTopologicalOrdering());

  print('\n Topological Ordering:');
  print(graph.topologicalOrdering());

  print('\n Local Sources:');
  print(graph.localSources());

Examples

For further information on how to generate a topological sorting of vertices see example.

Features and bugs

Please file feature requests and bugs at the issue tracker.

Libraries

directed_graph
Dart implementation of a directed graph. Provides methods to add/remove edges, check if the graph is acyclic, and retrieve a list of vertices in topological order.