-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
created iterators src folder, added kruskal
- Loading branch information
Showing
9 changed files
with
364 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# iterators | ||
|
||
_Graphs.jl_ includes various routines for iterating through graphs. | ||
|
||
## Index | ||
|
||
```@index | ||
Pages = ["iterators.md"] | ||
``` | ||
|
||
## Full docs | ||
|
||
```@autodocs | ||
Modules = [Graphs] | ||
Pages = [ | ||
"iterators/iterators.jl", | ||
"iterators/bfs.jl", | ||
"iterators/dfs.jl", | ||
"iterators/kruskal.jl", | ||
] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
""" | ||
BFSIterator | ||
`BFSIterator` is a subtype of [`VertexIterator`](@ref) to iterate through graph vertices using a breadth-first search. A source node(s) is optionally supplied as an `Int` or an array-like type that can be indexed if supplying multiple sources. If no source is provided, it defaults to the first vertex. | ||
# Examples | ||
```julia-repl | ||
julia> g = smallgraph(:house) | ||
{5, 6} undirected simple Int64 graph | ||
julia> for node in BFSIterator(g,3) | ||
display(node) | ||
end | ||
3 | ||
1 | ||
4 | ||
5 | ||
2 | ||
julia> for node in BFSIterator(g,[1,3]) | ||
display(node) | ||
end | ||
1 | ||
2 | ||
3 | ||
4 | ||
5 | ||
3 | ||
1 | ||
4 | ||
5 | ||
2 | ||
``` | ||
""" | ||
struct BFSIterator{S} <: VertexIterator | ||
graph::AbstractGraph | ||
source::S | ||
end | ||
|
||
BFSIterator(g::AbstractGraph) = BFSIterator(g, one(eltype(g))) | ||
|
||
|
||
""" | ||
Base.iterate(t::BFSIterator) | ||
First iteration to visit each vertex in a graph using breadth-first search. | ||
""" | ||
function Base.iterate(t::BFSIterator) | ||
visited = falses(nv(t.graph)) | ||
if t.source isa Number | ||
visited[t.source] = true | ||
return (t.source, SingleSourceIteratorState(visited, [t.source])) | ||
else | ||
init_source = first(t.source) | ||
visited[init_source] = true | ||
return (init_source, MultiSourceIteratorState(visited, [init_source], 1)) | ||
end | ||
end | ||
|
||
|
||
""" | ||
Base.iterate(t::BFSIterator, state::SingleSourceIteratorState) | ||
Iterator to visit each vertex in a graph using breadth-first search. | ||
""" | ||
function Base.iterate(t::BFSIterator, state::SingleSourceIteratorState) | ||
while !isempty(state.queue) | ||
for node in outneighbors(t.graph, state.queue[1]) | ||
if !state.visited[node] | ||
push!(state.queue, node) | ||
state.visited[node] = true | ||
return (node, state) | ||
end | ||
end | ||
popfirst!(state.queue) | ||
end | ||
end | ||
|
||
|
||
""" | ||
Base.iterate(t::BFSIterator, state::SingleSourceIteratorState) | ||
Iterator to visit each vertex in a graph using breadth-first search. | ||
""" | ||
function Base.iterate(t::BFSIterator, state::MultiSourceIteratorState) | ||
while !isempty(state.queue) | ||
for node in outneighbors(t.graph, state.queue[1]) | ||
if !state.visited[node] | ||
push!(state.queue, node) | ||
state.visited[node] = true | ||
return (node, state) | ||
end | ||
end | ||
popfirst!(state.queue) | ||
end | ||
# reset state and begin traversal at next source | ||
state.source_id += 1 | ||
state.source_id > length(t.source) && return nothing | ||
init_source =t.source[state.source_id] | ||
state.visited .= false | ||
state.visited[init_source] = true | ||
state.queue = [init_source] | ||
return (init_source, state) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
""" | ||
DFSIterator | ||
`DFSIterator` is a subtype of [`VertexIterator`](@ref) to iterate through graph vertices using a depth-first search. A source node(s) is optionally supplied as an `Int` or an array-like type that can be indexed if supplying multiple sources. If no source is provided, it defaults to the first vertex. | ||
# Examples | ||
```julia-repl | ||
julia> g = smallgraph(:house) | ||
{5, 6} undirected simple Int64 graph | ||
julia> for node in DFSIterator(g, 3) | ||
display(node) | ||
end | ||
1 | ||
2 | ||
4 | ||
3 | ||
5 | ||
julia> for node in DFSIterator(g,[1,5]) | ||
display(node) | ||
end | ||
1 | ||
2 | ||
4 | ||
3 | ||
5 | ||
5 | ||
3 | ||
1 | ||
2 | ||
4 | ||
``` | ||
""" | ||
struct DFSIterator{S} <: VertexIterator | ||
graph::AbstractGraph | ||
source::S | ||
end | ||
|
||
DFSIterator(g::AbstractGraph) = DFSIterator(g, one(eltype(g))) | ||
|
||
|
||
""" | ||
Base.iterate(t::DFSIterator) | ||
First iteration to visit each vertex in a graph using depth-first search. | ||
""" | ||
function Base.iterate(t::DFSIterator) | ||
visited = falses(nv(t.graph)) | ||
if t.source isa Number | ||
visited[t.source] = true | ||
return (t.source, SingleSourceIteratorState(visited, [t.source])) | ||
else | ||
init_source = first(t.source) | ||
visited[init_source] = true | ||
return (init_source, MultiSourceIteratorState(visited, [init_source], 1)) | ||
end | ||
end | ||
|
||
|
||
""" | ||
Base.iterate(t::DFSIterator, state::SingleSourceIteratorState) | ||
Iterator to visit each vertex in a graph using depth-first search. | ||
""" | ||
function Base.iterate(t::DFSIterator, state::SingleSourceIteratorState) | ||
while !isempty(state.queue) | ||
for node in outneighbors(t.graph, state.queue[end]) | ||
if !state.visited[node] | ||
push!(state.queue, node) | ||
state.visited[node] = true | ||
return (node, state) | ||
end | ||
end | ||
pop!(state.queue) | ||
end | ||
end | ||
|
||
|
||
""" | ||
Base.iterate(t::DFSIterator, state::MultiSourceIteratorState) | ||
Iterator to visit each vertex in a graph using depth-first search. | ||
""" | ||
function Base.iterate(t::DFSIterator, state::MultiSourceIteratorState) | ||
while !isempty(state.queue) | ||
for node in outneighbors(t.graph, state.queue[end]) | ||
if !state.visited[node] | ||
push!(state.queue, node) | ||
state.visited[node] = true | ||
return (node, state) | ||
end | ||
end | ||
pop!(state.queue) | ||
end | ||
# reset state and begin traversal at next source | ||
state.source_id += 1 | ||
state.source_id > length(t.source) && return nothing | ||
init_source =t.source[state.source_id] | ||
state.visited .= false | ||
state.visited[init_source] = true | ||
state.queue = [init_source] | ||
return (init_source, state) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
""" | ||
abstract type Iterator | ||
`Iterator` is an abstract type which specifies a particular algorithm to use when iterating through a graph. | ||
""" | ||
abstract type Iterator end | ||
|
||
|
||
""" | ||
abstract type VertexIterator <: Iterator | ||
`VertexIterator` is an abstract type to iterate through graph vertices. | ||
""" | ||
abstract type VertexIterator <: Iterator end | ||
|
||
|
||
""" | ||
abstract type EdgeIterator <: Iterator | ||
`EdgeIterator` is an abstract type to iterate through graph edges. | ||
""" | ||
abstract type EdgeIterator <: Iterator end | ||
|
||
|
||
""" | ||
abstract type AbstractIteratorState | ||
`IteratorState` is an abstract type to hold the current state of iteration which is need for the Base.iterate() function. | ||
""" | ||
abstract type AbstractIteratorState end | ||
|
||
|
||
""" | ||
mutable struct SingleSourceIteratorState | ||
`SingleSourceIteratorState` is a struct to hold the current state of iteration which is need for the Base.iterate() function. It is a basic implementation used for depth-first or breadth-first iterators when a single source is supplied. | ||
""" | ||
mutable struct SingleSourceIteratorState <: AbstractIteratorState | ||
visited::BitArray | ||
queue::Vector{Int} | ||
end | ||
|
||
|
||
""" | ||
mutable struct MultiSourceIteratorState | ||
`MultiSourceIteratorState` is a struct to hold the current state of iteration which is need for Julia's Base.iterate() function. It is a basic implementation used for depth-first or breadth-first iterators when mutltiple sources are supplied. | ||
""" | ||
mutable struct MultiSourceIteratorState <: AbstractIteratorState | ||
visited::BitArray | ||
queue::Vector{Int} | ||
source_id::Int | ||
end | ||
|
||
|
||
include("bfs.jl") | ||
include("dfs.jl") | ||
include("kruskal.jl") | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# The kruskal algorithms are largely copied from Graphs/src/spanningtrees/kruskal.jl | ||
|
||
struct KruskalIterator <: EdgeIterator | ||
graph::AbstractGraph | ||
connected_vs::IntDisjointSets | ||
distmx::AbstractMatrix | ||
edge_list | ||
|
||
function KruskalIterator(graph, distmx=weights(g); minimize=true) | ||
is_directed(graph) && throw(ArgumentError("$graph is a directed graph.")) | ||
weights = Vector{eltype(distmx)}() | ||
sizehint!(weights, ne(graph)) | ||
edge_list = collect(edges(graph)) | ||
for e in edge_list | ||
push!(weights, distmx[src(e), dst(e)]) | ||
end | ||
e = edge_list[sortperm(weights; rev=!minimize)] | ||
new(graph, IntDisjointSets(nv(graph)), distmx, e) | ||
end | ||
end | ||
|
||
|
||
""" | ||
mutable struct KruskalIteratorState | ||
`KruskalIteratorState` is a struct to hold the current state of iteration which is need for the Base.iterate() function. | ||
""" | ||
mutable struct KruskalIteratorState <: AbstractIteratorState | ||
edge_id::Int | ||
mst_len::Int | ||
end | ||
|
||
|
||
function Base.iterate(t::KruskalIterator, state::KruskalIteratorState=KruskalIteratorState(1,1)) | ||
while state.mst_len <= (nv(t.graph)-1) | ||
i = state.edge_id | ||
if !in_same_set(t.connected_vs, src(t.edge_list[i]), dst(t.edge_list[i])) | ||
union!(t.connected_vs, src(t.edge_list[i]), dst(t.edge_list[i])) | ||
state.mst_len += 1 | ||
return (t.edge_list[i], state) | ||
end | ||
state.edge_id += 1 | ||
end | ||
end | ||
|
||
|
||
function traverse_kruskal_mst(t::EdgeIterator, state::SingleSourceIteratorState) | ||
connected_vs = IntDisjointSets(nv(g)) | ||
|
||
mst = Vector{edgetype(g)}() | ||
sizehint!(mst, nv(g) - 1) | ||
|
||
weights = Vector{T}() | ||
sizehint!(weights, ne(g)) | ||
edge_list = collect(edges(g)) | ||
for e in edge_list | ||
push!(weights, distmx[src(e), dst(e)]) | ||
end | ||
|
||
for e in edge_list[sortperm(weights; rev=!minimize)] | ||
if !in_same_set(connected_vs, src(e), dst(e)) | ||
union!(connected_vs, src(e), dst(e)) | ||
push!(mst, e) | ||
(length(mst) >= nv(g) - 1) && break | ||
end | ||
end | ||
end |
File renamed without changes.
Oops, something went wrong.