# Graphs in Julia with LightGraphs¶

## Structure, abstractions and algorithms¶

Mathieu Besançon
JuliaGraphs

Twitter for live-complaints: @matbesancon

Re-using / citing the materials:

## First things first, logistics¶

Repository at https://github.com/matbesancon/JuliaNantesWorkshop

In [1]:
# Run this notebook in the exact same environment
import Pkg

## What's LightGraphs take on this?¶

1. Define a graph as an expected behaviour, not an implementation
2. Build algorithms assuming only this behaviour

# Graph abstraction¶

Say you define a type G which you want to be a graph, the following methods are required:

LightGraphs.edges(::G)
LightGraphs.edgetype(::G)
LightGraphs.is_directed(::Type{G})
LightGraphs.ne(::G)
LightGraphs.nv(::G)
LightGraphs.vertices(::G)

LightGraphs.outneighbors(::G, v)
LightGraphs.inneighbors(::G, v)
LightGraphs.has_vertex(::G, v)

LightGraphs.has_edge(::G, i, j)


... And that's it

# Quick tour of graph types¶

## Simple(Di)Graph¶

Sane default, scales well.

In [3]:
Random.seed!(40)
sg = SimpleDiGraph(5)
gplot(sg, nodelabel = vertices(sg))

Out[3]:

## Standard graphs¶

In [4]:
Random.seed!(42)
wg = LightGraphs.WheelGraph(7)
gplot(wg, nodelabel = vertices(wg))

Out[4]:
In [5]:
Random.seed!(42)
sdg = LightGraphs.StarDiGraph(10)
gplot(sdg, nodelabel = vertices(sdg))

Out[5]:

## Random graph generators¶

In [6]:
Random.seed!(30)
ba = barabasi_albert(10, 3, 3)
gplot(ba, nodelabel = vertices(ba))

Out[6]:

## MetaGraphs¶

Graphs with meta-information on edges and vertices. Add any arbitrary field (like a Dict) to edges.

In [7]:
meta_wheel = MetaGraphs.MetaGraph(wg)

MetaGraphs.set_prop!(meta_wheel, 1, :central, true)
for j in 2:nv(meta_wheel)
MetaGraphs.set_prop!(meta_wheel, j, :central, false)
end

In [8]:
Random.seed!(42)
nodecolors = [MetaGraphs.get_prop(meta_wheel, i, :central) ? colorant"red" : colorant"blue" for i in vertices(meta_wheel)]

gplot(meta_wheel, nodelabel = vertices(meta_wheel), nodefillc = nodecolors)

Out[8]:
In [9]:
# add information on edges
for e in edges(meta_wheel)
if src(e) == 1
MetaGraphs.set_prop!(meta_wheel, e, :type, "rayon")
else
MetaGraphs.set_prop!(meta_wheel, e, :type, "perimeter")
end
end

ewidth = [MetaGraphs.get_prop(meta_wheel, e, :type) == "rayon" ? 0.6 : 2.5 for e in edges(meta_wheel)];

In [10]:
Random.seed!(42)

gplot(meta_wheel, nodelabel = vertices(meta_wheel), nodefillc = nodecolors, edgelinewidth = ewidth)

Out[10]:

## SimpleWeightedGraphs¶

In many contexts, only weights associated with edges is required: meet SimpleWeightedGraphs.

In [11]:
g = SimpleWeightedGraph(3)
# add edge src ⇒ dst w
g

Out[11]:
{3, 3} undirected simple Int64 graph with Float64 weights

# Batteries included: essential algorithms¶

In [12]:
Random.seed!(42)
gplot(wg, nodelabel = vertices(wg))

Out[12]:
In [13]:
Random.seed!(42)
order = LightGraphs.dfs_parents(wg, 1)
gplot(wg, nodelabel = order)

Out[13]:
In [14]:
Random.seed!(42)
order = LightGraphs.bfs_parents(wg, 1)
gplot(wg, nodelabel = order)

Out[14]:

## Minimum Spanning Tree¶

Kruskal & Prim algorithms

In [15]:
Random.seed!(30)
ba = barabasi_albert(10, 3, 3)

st = kruskal_mst(ba)
edge_width = [e ∈ st ? 2.5 : 1.0 for e in edges(ba)]
edge_color = [e ∈ st ? colorant"red" : colorant"lightgray" for e in edges(ba)]

gplot(ba, nodelabel = vertices(ba), edgelinewidth = edge_width, edgestrokec = edge_color)

Out[15]: