To get a sense of all the functionality provided, you may need to look in the source files directly. Of course, our goal is to have this documentation be complete. Your help is welcome.
This module defines two data types for working with graphs:
- The
SimpleGraph
type represents undirected graphs without loops or multiple edges. - The
SimpleDigraph
type represents directed graphs in which there may be at most one directed edge(u,v)
from a vertexu
to a vertexv
. There may also be a directed edge in the opposite direction,(v,u)
.
To get started, get the package like this:
]clone https://github.com/scheinerman/SimpleGraphs.jl.git
Then, in any Julia session or program, give the command
using SimpleGraphs
.
The SimpleGraphs
module defines two data types:
G = SimpleGraph()
creates a new simple graph.D = SimpleDigraph()
creates a new directed graph.
In both cases, the vertices of the graph may be of Any
type. More
often, it is useful to restrict the type of the vertices to be of a
given type. This can be done with SimpleGraph{T}()
or
SimpleDigraph{T}()
where T
is a Julia type.
Two common choices the vertex type are integers and strings. For this purpose, we provide these special constructors:
IntGraph()
andIntDigraph()
creates graphs withInt
vertices. These can be called with an optional positive integer argument like this:IntGraph(n)
orIntDigraph(n)
. This prepopulates the vertex set withn
vertices named1
throughn
.StringGraph()
andStringDigraph()
creates graphs whose vertex type isASCIIString
.
To create a new graph from an adjacency matrix A
one can use
either SimpleGraph(A)
or IntGraph(A)
.
The most basic operations for graphs are adding and deleting vertices
and edges. These are done with add!
and delete!
. In general, if
G
is a graph or a digraph, then we have the following:
add!(G,v)
adds the vertexv
to the graph.add!(G,v,w)
adds the edge(v,w)
to the graph. IfG
is an undirected graph, then(v,w)
and(w,v)
are the same thing. See also the discussion concerning loops just below.delete!(G,v)
deletes the vertexv
from the graph as well as any edges that might be incident withv
.delete!(G,v,w)
deletes the edge(v,w)
.
The has
function may be used to determine if a given vertex or edge
is present in the graph:
has(G,v)
returnstrue
ifv
is a vertex ofG
.has(G,v,w)
returnstrue
if(v,w)
is an edge ofG
. In the case of undirected graphs, this is the same ashas(G,w,v)
.
The functions NV(G)
and NE(G)
return the number of vertices and
edges in G
, respectively.
The functions vlist(G)
and elist(G)
return a list of the vertices
and edges in G
. These lists are sorted if possible.
If G
is a SimpleGraph
and v
is one of its vertices, then
neighbors(G,v)
as a (possibly sorted) list. This may also be found
with G[v]
. The degree of v
is returned by deg(G,v)
. A call to
deg(G)
returns a sorted list of the degrees of all the vertices.
The function deg_hist
returns a vector that indicates how many
vertices of each degree is present in the graph. Because the first
element of an array has index 1, the counts are offset by one
place. That is if we put dh=deg_hist(G)
then dh[k]
is the number
of vertices of degree k-1
.
The situation is more involved if G
is a SimpleDigraph
. In this
case we have the following.
out_neighbors(G,v)
returns a list of all verticesw
such that(v,w)
is an edge ofG
. This includesv
itself if there's a loop atv
.in_neighbors(G,v)
returns a list of all verticesu
such that(u,v)
is an edge ofG
.out_deg(G,v)
is the number of vertices inout_neighbors(G,v)
.in_deg(G,v)
is the number of vertices inin_neighbors(G,v)
.deg(G,v)
is the sum ofout_deg(G,v)
andin_deg(G,v)
.
The SimpleGraph
data structure provides a mechanism for speedy
neighborhood lookup. This comes at a cost of holding considerable
redundant information. If the graph is very large, this may cause a
problem.
The function fastN!
may be used to supress (or restore) this
additional data structure.
fastN!(G,false)
destroys the redundant data structure. Neighborhood lookup is now much slower (as are any algorithms that might depend on it).fastN!(G,true)
restores the additional data structure. Note thatfastN!(G)
has the same effect.
To check if a graph possesses this data structure, the value of
G.Nflag
may be inspected but in no circumstance should this value
be changed except through the use of fastN!
.
A SimpleGraph
may never contain a loop (an edge whose end points are
the same). However, the ability for a SimpleDigraph
to have loops is
at the user's discretion. The default constructor SimpleDigraph{T}()
creates a digraph that may have loops; use SimpleDigraph{T}(false)
to create a digraph that is incapable of containing loops.
In addition, we provide the following functions to inspect and manipulate loops:
is_looped(D)
tests ifD
may hold loops; it returnstrue
if so andfalse
otherwise.loops(D)
returns a list of vertices inD
at which there is a loop present.allow_loops!(D)
enables the digraph to have loops.remove_loops!(D)
deletes all loops fromD
(if any) but does not alter its ability to have loops.forbid_loops!(D)
deletes all loops (if any) and preventsD
from having loops.
We provide a variety of functions for generating certain standard graphs.
In addition to the basic SimpleGraph
, IntGraph
, and StringGraph
constructors, we have the following:
Complete(n)
creates a complete graph withn
vertices numbered1
throughn
.Complete(n,m)
creates a complete bipartite graph withn
vertices in one part andm
vertices in the other.Complete([n1,n2,n3,...,nt])
creates a complete multipartite graph with part sizes as given in the array of integers[n1,n2,n3,...,nt]
.Cube(n)
creates ann
-dimensional cube graph. The vertices aren
-long character strings of 0s and 1s. Two vertices are adjacent iff they differ in exactly one location. By default,n=3
.Path(n)
creates a path graph withn
vertices. Alternatively, iflist
is a 1-dimensional array then this creates a graph with the members oflist
as vertices and with edges of the form(list[k],list[k+1])
. The elements oflist
should be distinct but this is not checked.Cycle(n)
creates a cycle onn
vertices. This requiresn
to be at least 3.Wheel(n)
creates a wheel graph withn
vertices. This is formed from ann-1
-cycle and additional vertex adjacent to all the vertices on the cycle.Grid(n,m)
creates ann
-by-m
grid graph.BuckyBall()
creates the 60-vertex graph that is the 1-skellaton of a truncated icosahedron.Dodecahedron()
creates the dodecahedron graph.Icosahedron()
creates the icosahedron graph.Octahedron()
creates the octahedron graph.Tetrahedron()
creates the tetrahedron graph; this is the same asComplete(4)
.RandomGraph(n,p)
creates an Erdos-Renyi random graph withn
vertices and edge probabilityp
. The parameterp
may be omitted, in which case the value 1/2 is used.RandomTree(n)
creates a random tree withn
vertices. There aren^(n-2)
trees with vertices set{1,2,...,n}
and they are all equally likely.RandomRegular(n,d)
creates a random regular graph withn
vertices and all vertices of degreed
.Knesser(n,k)
creates the Knesser graph. The vertices of this graph are thek
-element subsets of{1,2,...,n}
. Two vertices are adjacent iff they correspond to disjoint sets.Knight(r,c)
creates a Knight's moves graph on anr
byc
chessboard.Petersen()
creates the Petersen graph asKnesser(5,2)
.Paley(p)
creates the Paley graph withp
vertices wherep
is a prime congruent to 1 modulo 4. The vertex set is0:p-1
in which two vertices are adjacent exactly when their difference is a quadratic residue modp
.
In addition to SimpleDigraph
, IntDigraph
, and StringDigraph
constructors, we have the following:
DirectedComplete(n)
creates ann
-vertex digraph with alln*n
possible edges (including loops). To prevent loops, useDirectedComplete(n,false)
.DirectedPath(n)
creates ann
-vertex directed path with then-1
edges(1,2)
,(2,3)
, ...,(n-1,n)
.DirectedCycle(n)
creates ann
-vertex directed cycle with then
edges(1,2)
,(2,3)
, ...,(n-1,n)
,(n,1)
.RandomDigraph(n,p)
creates a random directed graph in which each of then*n
possible edges is present with probabilityp
(whose default value is 1/2). UseRandomDigraphs(n,p,false)
to prevent the formation of loops.RandomTournament(n)
creates a random digraph onn
vertices. For each pair of distinct verticesu
andv
we have exactly one of the edges(u,v)
or(v,u)
with probability 1/2 each (independently for all pairs of vertices). This graph has no loops.ShiftDigraph(alphabet, n)
creates the shift digraph whose vertices aren
-tuples of the elements ofalphabet
with an edge fromu
tov
exactly whenv
is a shift ofu
. (See thehelp
message for more detail.)
If D
is a SimpleDigraph
then simplify(D)
creates a new
SimpleGraph
that's formed by removing directions (and loops). That
is, the new graph has the same vertices as D
and an edge between
distinct vertices u
and v
if and only if (u,v)
or (v,u)
(or
both) is an edge of D
.
We also provide the function vertex_split
that takes a directed
graph D
and makes a new undirected graph by splitting each vertex in
two. That is, v
becomes (v,1)
and (v,2)
in the new graph. If
(u,v)
is a directed edge of D
then ((u,1),(v,2))
is an edge in
the resulting graph (which will be bipartite).
julia> D = DirectedCycle(4)
SimpleDigraph{Int64} (4 vertices)
julia> elist(D)
4-element Array{(Int64,Int64),1}:
(1,2)
(2,3)
(3,4)
(4,1)
julia> G = vertex_split(D)
SimpleGraph{(Int64,Int64)} (8 vertices)
julia> elist(G)
4-element Array{((Int64,Int64),(Int64,Int64)),1}:
((1,1),(2,2))
((1,2),(4,1))
((2,1),(3,2))
((3,1),(4,2))
julia> two_color(G)
Dict{(Int64,Int64),Int64} with 8 entries:
(1,2) => 1
(3,2) => 1
(3,1) => 1
(4,1) => 2
(2,2) => 1
(1,1) => 2
(4,2) => 2
(2,1) => 2
Undirected graphs only at this time. To be documented:
isequal
,G==H
complement
,complement!
,G'
induce
contract!
cartesian
,G*H
lex
,G[H]
lexicographic productdisjoint_union
union
join
trim
relabel
Undirected graphs only at this time. To be documented:
is_connected
num_components
components
find_path
(and now also directed graphs!)dist
dist_matrix
diam
is_cut_edge
spanning_forest
We generate the following kinds of matrices for graphs
adjacency
for both undirected and directed graphs.char_poly
gives the characteristic polynomial of theadjacency
matrix.laplace
for undirected graphs only.incidence
for both undirected and directed graphs.dist_matrix
for undirected graphs only.
Undirected graphs only at this time. See also my SimpleGraphAlgorithms
module for algorithms that rely on integer programming.
There are three ways this can be invoked.
euler(G,u,v)
finds an Eulerian trail that begins atu
and ends atv
.euler(G,u)
finds an Eulerian tour that begins and ends atu
.euler(G)
finds an Eulerian tour that begins at an arbitrary vertex.
Here's an example:
julia> G = complement(Cube(3))
SimpleGraph{ASCIIString} (8 vertices)
julia> euler(G)
17-element Array{ASCIIString,1}:
"000"
"011"
"100"
"001"
"010"
"100"
"111"
"000"
"101"
"010"
"111"
"001"
"110"
"011"
"101"
"110"
"000"
The tour is returned as an Array
of vertices with
NE(G)+1
elements. If no trail can be found, an empty Array
is returned.
Note that isolated vertices are ignored.
Use hamiltonian_cycle(G)
to find a Hamiltonian cycle in a graph. This returns a list (1-dimensional array) containing the vertices (in order) of the Hamiltonian cycle. An empty list is returned if there is no such cycle.
julia> hamiltonian_cycle(Cube(3))
8-element Array{ASCIIString,1}:
"000"
"001"
"011"
"010"
"110"
"111"
"101"
"100"
julia> hamiltonian_cycle(Petersen())
0-element Array{Set{Int64},1}
bipartition
determines if a graph is bipartite and returns a
partition of the vertex set into two parts. This returns a
Partition
(see SimplePartitions
).
julia> bipartition(RandomTree(10))
{{4,5,7,9},{1,2,3,6,8,10}}
Invoking bipartition
on a nonbipartite graph throws an error.
These functions create proper colorings of a graph. These functions
return a Dict
mapping vertices to integers so that adjacent vertices
are mapped to distinct values.
-
two_color
If the graph is bipartite, then this returns a proper 2-coloring of the graph.julia> two_color(Cube(3)) Dict{ASCIIString,Int64} with 8 entries: "000" => 1 "111" => 2 "001" => 2 "011" => 1 "101" => 1 "110" => 1 "010" => 2 "100" => 2
Applying
two_color
to a nonbipartite graph throws an error. -
greedy_color
is used to create a proper coloring of a graph given an ordering of the vertex set (as anArray
containing all the vertices). Of course, this is not guaranteed to find an optimal coloring. If no ordering is specified, then the a degree-decreasing ordering is used.julia> T = RandomTree(10) SimpleGraph{Int64} (10 vertices) julia> greedy_color(T,[1:10]) Dict{Int64,Int64} with 10 entries: 7 => 1 4 => 2 9 => 1 10 => 3 2 => 1 3 => 1 5 => 2 8 => 3 6 => 1 1 => 1 julia> greedy_color(T) Dict{Int64,Int64} with 10 entries: 7 => 2 4 => 1 9 => 1 10 => 2 2 => 3 3 => 2 5 => 1 8 => 2 6 => 2 1 => 1
-
random_greedy_color
is a variant ofgreedy_color
in which the ordering of the vertices is chosen at random. An optional second argument specifies the number of random orders to generate. The best coloring found (fewest colors) is returned.julia> random_greedy_color(T,100) Initial coloring uses 3 colors Reduced to 2 colors Dict{Int64,Int64} with 10 entries: 7 => 1 4 => 2 9 => 1 10 => 2 2 => 1 3 => 2 5 => 1 8 => 2 6 => 1 1 => 1
Code for these operations by Tara Abrishami.
Given a simple graph G
, use transitive_orientation(G)
to create
a directed graph whose underlying simple graph is G
that has a
transitive orientation. If G
is not transitively orientable,
an error is raised.
num_trans_orientations(G)
returns the number of
transitive orientations of the graph.
NOTE: This feature has been disabled because of errors
in the Graphs
module under Julia 0.6.
We provide a convert_simple
function that takes a SimpleGraph
or a SimpleDigraph
as input and returns a Julia
Graphs.simple_graph
representation of the same graph
(together with dictionaries to match up the vertex sets).
julia> (G,d,dinv) = convert_simple(Cube(3));
julia> G
Undirected Graph (8 vertices, 12 edges)
julia> d
Dict{ASCIIString,Int64} with 8 entries:
"000" => 1
"111" => 8
"001" => 2
"011" => 4
"101" => 6
"110" => 7
"010" => 3
"100" => 5
julia> dinv
Dict{Int64,ASCIIString} with 8 entries:
7 => "110"
4 => "011"
2 => "001"
3 => "010"
8 => "111"
5 => "100"
6 => "101"
1 => "000"
This is very much a work in process with a lot of more features that can/should be added. If you're interested in contributing, please contact me. I'm especially interested in JHU undergraduates getting involved.
Ed Scheinerman (ers@jhu.edu)