gogl

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2014 License: MIT Imports: 4 Imported by: 4

README

gogl

Build Status Coverage Status

gogl is a graph library in Go. Its goal is to provide simple, unifying interfaces and implementations of graph algorithms and datastructures that can scale from small graphs to very large graphs. The latter case is, as yet, untested!

gogl is based on the premise that working with graphs can be decomplected by focusing primarily on the natural constraints established in graph theory.

There's still a lot to do - gogl is still firming up significant aspects of how its API works.

Principles

Graph systems are often big, complicated affairs. gogl tries to be not that. These are the operant principles:

  1. Simplicity: fully and correctly modeling graph theoretic concepts in idiomatic Go.
  2. Performance: be as fast as design constraints and known-best algorithms allow.
  3. Extensibility: expect others to run gogl's graph datastructures through their own algorithms, , and gogl's algorithms with their graph implementations.
  4. Functional: orient towards transforms, functors, and streams; achieve other styles through layering.
  5. Flexibility: Be unopinionated about vertices, and minimally opinionated about edges.
  6. Correctness: Utilize commonly accepted graph terminology where possible, and adhere to its meaning.

The first and last points are key - names in gogl are carefully chosen, with the hope that they can guide intuition when stricter rules (e.g., the type system) become ambiguous. The godoc generally takes care to detail these subtleties. But godoc is a reference, not a tutorial.

Quickstart

Getting started with gogl is simple: create a graph object, add your data, and off you go.

package main

import (
	"fmt"
	"github.com/sdboyer/gogl"
	"github.com/sdboyer/gogl/dfs"
)

func main() {
	// gogl uses a builder to specify the kind of graph you want.
	graph := gogl.BuildGraph().
		// The graph should be mutable. Default is immutable.
		Mutable().
		// The graph should have directed edges (arcs). Default is undirected.
		Directed().
		// The graph's edges are plain - no labels, weights, etc. This is the default.
		Basic().
		// No loops or parallel edges. This is the default.
		SimpleGraph().
		// gogl.AdjacencyList picks and returns an adjacency list-based graph, based on the spec.
		Create(gogl.AdjacencyList).
		// The builder always returns a Graph; type assert to get access to add/remove methods.
		(gogl.MutableGraph)

	// Adds two basic edges. Of course, this adds the vertices, too.
	graph.AddEdges(gogl.NewEdge("foo", "bar"), gogl.NewEdge("bar", "baz"))

	// gogl's core iteration concept is built on injected functions (VertexLambda or
	// EdgeLambda). Here, a VertexLambda is called once per vertex in the graph;
	// the return value determines whether traversal continues.
	graph.EachVertex(func(v gogl.Vertex) (terminate bool) {
		fmt.Println(v) // Probably "foo\nbar\nbaz", but ordering is not guaranteed.
		return // returns false, so iteration continues
	})

	// gogl refers to these sorts of iterating methods as enumerators. There are four
	// such methods on undirected graphs, and two more on directed graphs.

	// If you know you need the full result set, gogl provides functors to collect enumerations
	// into slices. This makes ranging easy.
	var vertices []gogl.Vertex = gogl.CollectVertices(graph)
	for _, v := range vertices {
		fmt.Println(v) // same as with EachVertex().
	}

	// The pattern is the same with edge enumeration. These two have the same output:
	graph.EachEdge(func(e gogl.Edge) (terminate bool) {
		fmt.Println(e) // Probably "{foo bar}\n{bar baz}". Again, ordering is not guaranteed.
		return
	})
	for _, e := range gogl.CollectEdges(graph) {
		fmt.Println(e)
	}

	// gogl's algorithms all rely on these enumerators to do their work. Here, we use
	// a depth-first topological sort algorithm to produce a slice of vertices.
	var tsl []gogl.Vertex
	tsl, err := dfs.Toposort(graph, "foo")
	if err == nil {
		fmt.Println(tsl) // [baz bar foo]
	}
}

Enumerators

TODO - add diagrams indicating what relationship each enumerator touches.

Gotchas

Documentation

Overview

gogl provides a framework for representing and working with graphs.

gogl is divided chiefly into two parts: datastructures and algorithms. These components are loosely coupled; the algorithms rely strictly on gogl's various exported Graph interfaces to do their work.

Index

Constants

View Source
const (
	// Edge directedness. Flags are provided for both, though gogl does not really support
	// a hybrid graph containing both directed and undirected edges. Algorithms would have
	// undefined results.
	G_UNDIRECTED = 1 << iota
	G_DIRECTED

	// Edge type. Basic (untyped edges, represented solely by the Edge interface) is the implied zero-value.
	G_BASIC
	G_LABELED
	G_WEIGHTED
	G_DATA

	// Multiplicity. Simple (no loops or multiple edges) is the implied zero-value.
	G_SIMPLE
	G_LOOPS
	G_PARALLEL

	// Mutability. Immutable is the implied zero-value.
	G_IMMUTABLE
	G_MUTABLE
	G_PERSISTENT = 1<<iota | G_MUTABLE // Persistent graphs are, kinda weirdly, both.
)
View Source
const NullGraph = nullGraph(false)

The null graph is a graph without any edges or vertices. It implements all possible (non-mutable) graph interfaces.

In effect, it is the zero-value of all possible graph types.

Variables

This section is empty.

Functions

func CopyGraph added in v0.4.0

func CopyGraph(from Graph, to interface{}) interface{}

Copies the first graph's edges and vertices into the second, and returns the second.

The second argument must be some flavor of MutableGraph, otherwise this function will panic.

Generally speaking, this is a very naive copy operation; it should not be relied on for complex cases.

Types

type AdjacencyEnumerator added in v0.4.0

type AdjacencyEnumerator interface {
	EachAdjacentTo(start Vertex, adjacentVertexLambda VertexLambda)
}

An AdjacencyEnumerator iteratively enumerates a given vertex's adjacent vertices.

type DataEdge added in v0.3.0

type DataEdge interface {
	Edge
	Data() interface{}
}

A DataEdge is an Edge that also holds arbitrary data.

func NewDataEdge added in v0.4.0

func NewDataEdge(u, v Vertex, data interface{}) DataEdge

Create a new "data" edge - an edge with arbitrary embedded data.

type DataEdgeList added in v0.4.0

type DataEdgeList []DataEdge

A DataEdgeList is a naive GraphSource implementation that is backed only by an edge slice.

This variant is for labeled edges.

func (DataEdgeList) EachEdge added in v0.4.0

func (el DataEdgeList) EachEdge(fn EdgeLambda)

func (DataEdgeList) EachVertex added in v0.4.0

func (el DataEdgeList) EachVertex(fn VertexLambda)

func (DataEdgeList) Order added in v0.4.0

func (el DataEdgeList) Order() int

type DataEdgeSetMutator added in v0.4.0

type DataEdgeSetMutator interface {
	AddEdges(edges ...DataEdge)
	RemoveEdges(edges ...DataEdge)
}

A DataEdgeSetMutator allows the addition and removal of data edges from a set.

type DataGraph added in v0.3.0

type DataGraph interface {
	Graph
	HasDataEdge(e DataEdge) bool
}

A data graph is a graph subtype where the edges carry arbitrary Go data; as described by the DataEdge interface, this identifier is an interface{}.

DataGraphs have both the HasEdge() and HasDataEdge() methods. Correct implementations should treat the difference as a matter of strictness:

HasEdge() should return true as long as an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), regardless of its label.

HasDataEdge() should return true iff an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), AND if the edge data is the same. Simple comparison will typically be used to establish data equality, which means that using noncomparables (a slice, map, or non-pointer struct containing a slice or a map) for the data will cause a panic.

type DegreeChecker added in v0.4.0

type DegreeChecker interface {
	DegreeOf(Vertex) (degree int, exists bool) // Number of incident edges; if vertex is present
}

A DegreeChecker reports the number of edges incident to a given vertex.

type Digraph added in v0.4.0

type Digraph interface {
	Graph
	IncidentArcEnumerator // Enumerates a vertex's incident in- and out-arcs to an injected lambda
	DirectedDegreeChecker // Reports in- and out-degree of vertices
	Transposer            // Digraphs can produce a transpose of themselves
}

Digraph (directed graph) describes a Graph where all the edges are directed.

gogl treats edge directionality as a property of the graph, not the edge itself. Thus, implementing this interface is gogl's only signal that a graph's edges are directed.

type DirectedDegreeChecker added in v0.4.0

type DirectedDegreeChecker interface {
	InDegreeOf(Vertex) (degree int, exists bool)  // Number of in-edges; if vertex is present
	OutDegreeOf(Vertex) (degree int, exists bool) // Number of out-edges; if vertex is present
}

A DirectedDegreeChecker reports the number of in or out-edges incident to given vertex.

type Edge

type Edge interface {
	Source() Vertex
	Target() Vertex
	Both() (Vertex, Vertex)
}

The Edge interface describes a connection between two vertices.

Edge does not have an intrinsic opinion about directionality; gogl treats that as a property of the overall Graph object in which the Edge appears rather than a property of any individual Edge.

func CollectArcsFrom added in v0.4.0

func CollectArcsFrom(v Vertex, g IncidentArcEnumerator) (edges []Edge)

Collects all of a given vertex's out-edges into an edge slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

func CollectArcsTo added in v0.4.0

func CollectArcsTo(v Vertex, g IncidentArcEnumerator) (edges []Edge)

Collects all of a given vertex's in-edges into an edge slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

func CollectEdges added in v0.4.0

func CollectEdges(g EdgeEnumerator) (edges []Edge)

Collects all of a graph's edges into an edge slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

func CollectEdgesIncidentTo added in v0.4.0

func CollectEdgesIncidentTo(v Vertex, g IncidentEdgeEnumerator) (edges []Edge)

Collects all of a given vertex's incident edges into an edge slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

func NewEdge added in v0.4.0

func NewEdge(u, v Vertex) Edge

Create a new basic edge.

type EdgeEnumerator added in v0.4.0

type EdgeEnumerator interface {
	EachEdge(EdgeLambda)
}

An EdgeEnumerator iteratively enumerates edges, and can indicate the number of edges present.

type EdgeLambda added in v0.4.0

type EdgeLambda func(Edge) (terminate bool)

EdgeLambdas are used as arguments to various enumerators. They are called once for each edge produced by the enumerator.

If the lambda returns true, the calling enumerator is expected to end enumeration and return control to its caller.

type EdgeList

type EdgeList []Edge

An EdgeList is a naive GraphSource implementation that is backed only by an edge slice.

EdgeLists are primarily intended for use as fixtures.

It is inherently impossible for an EdgeList to represent a vertex isolate (degree 0) fully correctly, as vertices are only described in the context of their edges. One can be a little hacky, though, and represent one with a loop. As gogl expects graph implementations to simply discard loops if they are disallowed by the graph's constraints (i.e., in simple and multigraphs), they *should* be interpreted as vertex isolates.

func (EdgeList) EachEdge added in v0.4.0

func (el EdgeList) EachEdge(fn EdgeLambda)

func (EdgeList) EachVertex added in v0.4.0

func (el EdgeList) EachVertex(fn VertexLambda)

func (EdgeList) Order added in v0.4.0

func (el EdgeList) Order() int

type EdgeMembershipChecker added in v0.4.0

type EdgeMembershipChecker interface {
	HasEdge(Edge) bool
}

An EdgeMembershipChecker can indicate the presence of an edge.

type EdgeSetMutator added in v0.4.0

type EdgeSetMutator interface {
	AddEdges(edges ...Edge)
	RemoveEdges(edges ...Edge)
}

An EdgeSetMutator allows the addition and removal of edges from a set.

type Graph

type Graph interface {
	VertexEnumerator        // Enumerates vertices to an injected lambda
	EdgeEnumerator          // Enumerates edges to an injected lambda
	AdjacencyEnumerator     // Enumerates a vertex's adjacent vertices to an injected lambda
	IncidentEdgeEnumerator  // Enumerates a vertex's incident edges to an injected lambda
	VertexMembershipChecker // Allows inspection of contained vertices
	EdgeMembershipChecker   // Allows inspection of contained edges
	DegreeChecker           // Reports degree of vertices
	Order() int             // Reports total number of vertices in the graph
	Size() int              // Reports total number of edges in the graph
}

Graph is gogl's most basic interface: it contains only the methods that *every* type of graph implements.

Graph is intentionally underspecified: both directed and undirected graphs implement it; simple graphs, multigraphs, weighted, labeled, or any combination thereof.

The semantics of some of these methods vary slightly from one graph type to another, but in general, the basic Graph methods are supplemented, not superceded, by the methods in more specific interfaces.

Graph is a purely read oriented interface; the various Mutable*Graph interfaces contain the methods for writing.

func AdjacencyList added in v0.4.0

func AdjacencyList(gs GraphSpec) Graph

Create a graph implementation in the adjacency list style from the provided GraphSpec.

If the GraphSpec contains a GraphSource, it will be imported into the provided graph. If the GraphSpec indicates a graph type that is not currently implemented, this function will panic.

type GraphProperties added in v0.4.0

type GraphProperties uint16

Describes the properties of a graph as a bitfield.

type GraphSource added in v0.4.0

type GraphSource interface {
	VertexEnumerator
	EdgeEnumerator
	Order() int
}

GraphSource is a subinterface of Graph, describing the minimal set of methods necessary to accomplish a naive full graph traversal and copy.

type GraphSpec added in v0.4.0

type GraphSpec struct {
	Props  GraphProperties
	Source GraphSource
}

func G added in v0.4.0

func G() GraphSpec

Create a graph spec, which allows specification and creation of a graph through a fluent builder-style interface.

func (GraphSpec) Basic added in v0.4.0

func (b GraphSpec) Basic() GraphSpec

Specify that the edges should be "basic" - no weights, labels, or data.

func (GraphSpec) Create added in v0.4.0

func (b GraphSpec) Create(f func(GraphSpec) Graph) Graph

Creates a graph from the spec, using the provided creator function.

This is just a convenience method; the creator function can always be called directly.

func (GraphSpec) DataEdges added in v0.4.0

func (b GraphSpec) DataEdges() GraphSpec

Specify that the edges should contain arbitrary data. See DataEdge

func (GraphSpec) Directed added in v0.4.0

func (b GraphSpec) Directed() GraphSpec

Specify that the graph should have directed edges (be a digraph).

func (GraphSpec) Immutable added in v0.4.0

func (b GraphSpec) Immutable() GraphSpec

Specify that the graph is immutable.

func (GraphSpec) Labeled added in v0.4.0

func (b GraphSpec) Labeled() GraphSpec

Specify that the edges should be labeled. See LabeledEdge

func (GraphSpec) Loop added in v0.4.0

func (b GraphSpec) Loop() GraphSpec

Specify that the graph allows loops - edges connecting a vertex to itself.

func (GraphSpec) MultiGraph added in v0.4.0

func (b GraphSpec) MultiGraph() GraphSpec

Specify that the graph is a multigraph - allows parallel edges, but no loops.

func (GraphSpec) Mutable added in v0.4.0

func (b GraphSpec) Mutable() GraphSpec

Specify that the graph is mutable.

func (GraphSpec) Parallel added in v0.4.0

func (b GraphSpec) Parallel() GraphSpec

Specify that the graph allows parallel edges.

func (GraphSpec) PseudoGraph added in v0.4.0

func (b GraphSpec) PseudoGraph() GraphSpec

Specify that the graph is a pseudograph - allows both loops and parallel edges.

func (GraphSpec) SimpleGraph added in v0.4.0

func (b GraphSpec) SimpleGraph() GraphSpec

Specify that the graph should be simple - have no loops or multiple edges.

func (GraphSpec) Undirected added in v0.4.0

func (b GraphSpec) Undirected() GraphSpec

Specify that the graph should have undirected edges.

func (GraphSpec) Using added in v0.4.0

func (b GraphSpec) Using(g GraphSource) GraphSpec

Specify that the graph should be populated from the provided source "graph".

The GraphSource interface is used here because this is an ideal place at which to load in, for example, graph data exported into a flat file; a GraphSource can represent that data and only implement the minimal interface.

func (GraphSpec) Weighted added in v0.4.0

func (b GraphSpec) Weighted() GraphSpec

Specify that the edges should be weighted. See WeightedEdge

type IncidentArcEnumerator added in v0.4.0

type IncidentArcEnumerator interface {
	EachArcFrom(v Vertex, outEdgeLambda EdgeLambda)
	EachArcTo(v Vertex, inEdgeLambda EdgeLambda)
}

An IncidentArcEnumerator iteratively enumerates a given vertex's incident arcs (directed edges). One enumerator provides inbound edges, the other outbound edges.

type IncidentEdgeEnumerator added in v0.4.0

type IncidentEdgeEnumerator interface {
	EachEdgeIncidentTo(v Vertex, incidentEdgeLambda EdgeLambda)
}

An IncidentEdgeEnumerator iteratively enumerates a given vertex's incident edges.

type LabeledEdge added in v0.2.0

type LabeledEdge interface {
	Edge
	Label() string
}

A LabeledEdge is an Edge that also has a string label.

func NewLabeledEdge added in v0.4.0

func NewLabeledEdge(u, v Vertex, label string) LabeledEdge

Create a new labeled edge.

type LabeledEdgeList added in v0.4.0

type LabeledEdgeList []LabeledEdge

A LabeledEdgeList is a naive GraphSource implementation that is backed only by an edge slice.

This variant is for labeled edges.

func (LabeledEdgeList) EachEdge added in v0.4.0

func (el LabeledEdgeList) EachEdge(fn EdgeLambda)

func (LabeledEdgeList) EachVertex added in v0.4.0

func (el LabeledEdgeList) EachVertex(fn VertexLambda)

func (LabeledEdgeList) Order added in v0.4.0

func (el LabeledEdgeList) Order() int

type LabeledEdgeSetMutator added in v0.4.0

type LabeledEdgeSetMutator interface {
	AddEdges(edges ...LabeledEdge)
	RemoveEdges(edges ...LabeledEdge)
}

A LabeledEdgeSetMutator allows the addition and removal of labeled edges from a set.

type LabeledGraph added in v0.2.0

type LabeledGraph interface {
	Graph
	HasLabeledEdge(e LabeledEdge) bool
}

A labeled graph is a graph subtype where the edges have an identifier; as described by the LabeledEdge interface, this identifier is a string.

LabeledGraphs have both the HasEdge() and HasLabeledEdge() methods. Correct implementations should treat the difference as a matter of strictness:

HasEdge() should return true as long as an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), regardless of its label.

HasLabeledEdge() should return true iff an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), AND if the edge labels are the same.

type MutableDataGraph added in v0.3.0

type MutableDataGraph interface {
	DataGraph
	VertexSetMutator
	DataEdgeSetMutator
}

MutableDataGraph is the mutable version of a propety graph. Its AddEdges() method is incompatible with MutableGraph, guaranteeing only property edges can be present in the graph.

type MutableGraph added in v0.1.0

type MutableGraph interface {
	Graph
	VertexSetMutator
	EdgeSetMutator
}

MutableGraph describes a graph with basic edges (no weighting, labeling, etc.) that can be modified freely by adding or removing vertices or edges.

func NewUndirected added in v0.1.0

func NewUndirected() MutableGraph

type MutableLabeledGraph added in v0.2.0

type MutableLabeledGraph interface {
	LabeledGraph
	VertexSetMutator
	LabeledEdgeSetMutator
}

LabeledWeightedGraph is the mutable version of a labeled graph. Its AddEdges() method is incompatible with MutableGraph, guaranteeing only labeled edges can be present in the graph.

type MutableWeightedGraph added in v0.1.0

type MutableWeightedGraph interface {
	WeightedGraph
	VertexSetMutator
	WeightedEdgeSetMutator
}

MutableWeightedGraph is the mutable version of a weighted graph. Its AddEdges() method is incompatible with MutableGraph, guaranteeing only weighted edges can be present in the graph.

type SimpleGraph

type SimpleGraph interface {
	Graph
	Density() float64
}

A simple graph is in opposition to a multigraph or pseudograph: it disallows loops and parallel edges.

type Transposer added in v0.4.0

type Transposer interface {
	Transpose() Digraph
}

A Transposer produces a transposed version of a Digraph.

type Vertex

type Vertex interface{}

A Vertex in gogl is a value of empty interface type.

This is largely comensurate with graph theory, as vertices are, in the general case, known to be unique within the graph context, but the particular property that makes them unique has no bearing on the graph's behavior. In Go-speak, that translates pretty nicely to interface{}.

func CollectVertices added in v0.4.0

func CollectVertices(g VertexEnumerator) (vertices []Vertex)

Collects all of a graph's vertices into a vertex slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

func CollectVerticesAdjacentTo added in v0.4.0

func CollectVerticesAdjacentTo(v Vertex, g AdjacencyEnumerator) (vertices []Vertex)

Collects all of a given vertex's adjacent vertices into a vertex slice, for easy range-ing.

This is a convenience function. Avoid it on very large graphs or in performance critical sections.

type VertexEnumerator added in v0.4.0

type VertexEnumerator interface {
	EachVertex(VertexLambda)
}

A VertexEnumerator iteratively enumerates vertices, and can indicate the number of vertices present.

type VertexLambda added in v0.4.0

type VertexLambda func(Vertex) (terminate bool)

VertexLambdas are used as arguments to various enumerators. They are called once for each vertex produced by the enumerator.

If the lambda returns true, the calling enumerator is expected to end enumeration and return control to its caller.

type VertexMembershipChecker added in v0.4.0

type VertexMembershipChecker interface {
	HasVertex(Vertex) bool // Whether or not the vertex is present in the set
}

A VertexMembershipChecker can indicate the presence of a vertex.

type VertexSetMutator added in v0.4.0

type VertexSetMutator interface {
	EnsureVertex(...Vertex)
	RemoveVertex(...Vertex)
}

A VertexSetMutator allows the addition and removal of vertices from a set.

type WeightedEdge added in v0.1.0

type WeightedEdge interface {
	Edge
	Weight() float64
}

A WeightedEdge is an Edge that also has a numerical weight.

func NewWeightedEdge added in v0.4.0

func NewWeightedEdge(u, v Vertex, weight float64) WeightedEdge

Create a new weighted edge.

type WeightedEdgeList added in v0.4.0

type WeightedEdgeList []WeightedEdge

A WeightedEdgeList is a naive GraphSource implementation that is backed only by an edge slice.

This variant is for weighted edges.

func (WeightedEdgeList) EachEdge added in v0.4.0

func (el WeightedEdgeList) EachEdge(fn EdgeLambda)

func (WeightedEdgeList) EachVertex added in v0.4.0

func (el WeightedEdgeList) EachVertex(fn VertexLambda)

func (WeightedEdgeList) Order added in v0.4.0

func (el WeightedEdgeList) Order() int

type WeightedEdgeSetMutator added in v0.4.0

type WeightedEdgeSetMutator interface {
	AddEdges(edges ...WeightedEdge)
	RemoveEdges(edges ...WeightedEdge)
}

A WeightedEdgeSetMutator allows the addition and removal of weighted edges from a set.

type WeightedGraph added in v0.1.0

type WeightedGraph interface {
	Graph
	HasWeightedEdge(e WeightedEdge) bool
}

A weighted graph is a graph subtype where the edges have a numeric weight; as described by the WeightedEdge interface, this weight is a signed int.

WeightedGraphs have both the HasEdge() and HasWeightedEdge() methods. Correct implementations should treat the difference as a matter of strictness:

HasEdge() should return true as long as an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), regardless of its weight.

HasWeightedEdge() should return true iff an edge exists connecting the two given vertices (respecting directed or undirected as appropriate), AND if the edge weights are the same.

Directories

Path Synopsis
Contains algos and logic related to depth-first graph traversal.
Contains algos and logic related to depth-first graph traversal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL