Janiczek / elm-graph / Graph

Construction


type Graph vertex edge

A directed graph data structure.

The vertices can hold any data, but you can't have two vertices holding the same data. (Think of it as of Set.)

The edges can also hold any data, but you can't have two edges going from/to the same place.


type alias Edge vertex edge =
{ from : vertex
, to : vertex
, data : edge 
}

A representation of an edge between two vertices.

empty : Graph vertex edge

An empty graph. No vertices, no edges.

fromVerticesAndEdges : List vertex -> List (Edge vertex edge) -> Graph vertex edge

Construct a graph from a list of vertices and a list of edges.

Implicitly adds vertices that are present in the edges list, as if they were mentioned in the vertices list too.

Graph.fromVerticesAndEdges
    [ "x", "y" ]
    [ { from = "x", to = "y", data = 100 }
    , { from = "y", to = "z", data = 200 }
    , { from = "z", to = "x", data = 300 }
    ]
    |> Graph.vertices
    |> List.length
--> 3

Modification

addVertex : vertex -> Graph vertex edge -> Graph vertex edge

Add the vertex to the graph. (Nothing happens if it's already present.)

By default it's not connected to any other vertex.

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.vertices
--> [ "foo" ]

removeVertex : vertex -> Graph vertex edge -> Graph vertex edge

Remove the vertex from the graph. (Nothing happens if it's not present.)

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.removeVertex "foo"
    |> Graph.isEmpty
--> True

updateVertex : vertex -> (vertex -> vertex) -> Graph vertex edge -> Graph vertex edge

Updates the vertex data. Does nothing if the vertex is not present.

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.updateVertex "foo" String.toUpper
    |> Graph.vertices
--> [ "FOO" ]

addEdge : vertex -> vertex -> edge -> Graph vertex edge -> Graph vertex edge

Add an edge to the graph, along with the associated data

If any of the vertices aren't present yet, this function will add them before adding the edge.

Directed: the order of the vertices does matter.

Graph.empty
    |> Graph.addEdge "foo" "bar" ()
    |> Graph.vertices
--> [ "foo", "bar" ]

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.edges
--> [ { from = "foo", to = "bar", data = 100 } ]

removeEdge : vertex -> vertex -> Graph vertex edge -> Graph vertex edge

Remove an edge from the first vertex to the second one. Does nothing if the edge is not present.

Directed: the order of the vertices does matter.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.removeEdge "foo" "bar"
    |> Graph.edges
--> []

updateEdge : vertex -> vertex -> (edge -> edge) -> Graph vertex edge -> Graph vertex edge

Updates the edge data. Does nothing if the edge is not present.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.updateEdge "foo" "bar" (\v -> v + 1000)
    |> Graph.edges
--> [ { from = "foo", bar = "bar", data = 1100 } ]

mapVertices : (vertex1 -> vertex2) -> Graph vertex1 edge -> Graph vertex2 edge

Applies a function to all the vertices.

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.addVertex "bar"
    |> Graph.mapVertices String.toUpper
    |> Graph.vertices
--> [ "FOO", "BAR" ]

mapEdges : (edge1 -> edge2) -> Graph vertex edge1 -> Graph vertex edge2

Applies a function to all the edges.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.addEdge "bar" "baz" 200
    |> Graph.mapEdges (\x -> x + 1000)
    |> Graph.edges
--> [ { from = "foo", to = "bar", data = 1100 }
--  , { from = "bar", to = "baz", data = 1200 }
--  ]
--
--  (sans the ordering on the edges list, see the note in `edges`)

reverseEdges : Graph vertex edge -> Graph vertex edge

Reverse the direction of all the edges in the graph.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.reverseEdges
    |> Graph.edges
--> [ { from = "bar", to = "foo", data = 100 } ]

Predicates

isEmpty : Graph vertex edge -> Basics.Bool

Is the graph empty?

hasVertex : vertex -> Graph vertex edge -> Basics.Bool

Is this vertex present in the graph?

Graph.empty
    |> Graph.hasVertex "x"
--> False

Graph.empty
    |> Graph.addVertex "x"
    |> Graph.hasVertex "x"
--> True

hasEdge : vertex -> vertex -> Graph vertex edge -> Basics.Bool

Is this edge present in the graph?

Graph.empty
    |> Graph.hasEdge "x" "y"
--> False

Graph.empty
    |> Graph.addEdge "x" "y" ()
    |> Graph.hasEdge "x" "y"
--> True

Graph.empty
    |> Graph.addEdge "y" "x" ()
    |> Graph.hasEdge "x" "y"
--> False

areAdjacent : vertex -> vertex -> Graph vertex edge -> Basics.Bool

Does the graph contain an edge between these two vertices (in any direction)?

Graph.empty
    |> Graph.areAdjacent "x" "y"
--> False

Graph.empty
    |> Graph.addEdge "x" "y" ()
    |> Graph.areAdjacent "x" "y"
--> True

Graph.empty
    |> Graph.addEdge "y" "x" ()
    |> Graph.areAdjacent "x" "y"
--> True

Querying

fold : (vertex -> acc -> acc) -> acc -> Graph vertex edge -> acc

Fold a function over all the vertices, starting with the "oldest" vertices.

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.addVertex "bar"
    |> Graph.fold (\v acc -> acc ++ v) ""
--> "foobar"

size : Graph vertex edge -> Basics.Int

Determine the number of vertices in the graph.

Graph.size Graph.empty
--> 0

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.addVertex "bar"
    |> Graph.size
--> 2

vertices : Graph vertex edge -> List vertex

Return a list of the vertices, starting with the "oldest".

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.addVertex "bar"
    |> Graph.vertices
--> [ "foo", "bar" ]

edges : Graph vertex edge -> List (Edge vertex edge)

Return a list of the edges.

Don't expect any sensible order - it's implementation defined.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.addEdge "bar" "quux" 200
    |> Graph.edges
--> [ { from = "bar", to = "quux", data = 200 }
--  , { from = "foo", to = "bar", data = 100 }
--  ]

verticesAndEdges : Graph vertex edge -> { vertices : List vertex, edges : List (Edge vertex edge) }

Return a record with a list of vertices and list of edges in the graph.

Graph.empty
    |> Graph.addVertex "foo"
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.verticesAndEdges
--> { vertices = [ "foo", "bar" ]
--  , edges = [ { from = "foo", to = "bar", data = 100 } ]
--  }

outgoingEdges : vertex -> Graph vertex edge -> List vertex

Lists all vertices this vertex has edges to.

Directed - only lists the edges that go from the given vertex.

 Graph.empty
     |> Graph.outgoingEdges "foo"
 --> []

 Graph.empty
     |> Graph.addEdge "foo" "bar" ()
     |> Graph.addEdge "foo" "baz" ()
     |> Graph.addEdge "quux" "foo" ()
     |> Graph.outgoingEdges "foo"
 --> [ "bar", "baz" ]

outgoingEdgesWithData : vertex -> Graph vertex edge -> List ( vertex, edge )

Lists all vertices this vertex has edges to, along with the edge data.

Directed - only lists the edges that go from the given vertex.

 Graph.empty
     |> Graph.outgoingEdgesWithData "foo"
 --> []

 Graph.empty
     |> Graph.addEdge "foo" "bar" 100
     |> Graph.addEdge "foo" "baz" 200
     |> Graph.addEdge "quux" "foo" 300
     |> Graph.outgoingEdgesWithData "foo"
 --> [ ("bar", 100)
 --  , ("baz", 200)
 --  ]

getEdge : vertex -> vertex -> Graph vertex edge -> Maybe edge

Get the value associated with the edge.

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.getEdge "foo" "bar"
--> Just 100

Graph.empty
    |> Graph.addEdge "foo" "bar" 100
    |> Graph.getEdge "bar" "quux"
--> Nothing

edgeToComparable : Edge comparableVertex comparableEdge -> ( comparableVertex, comparableVertex, comparableEdge )

Transform the record into a (from, to, data) tuple.

Graph.edgeToComparable { from = "foo", to = "bar", data = 123 }
--> ("foo", "bar", 123)