Skip to content

Commit

Permalink
Implement bridge (sbromberger#1105)
Browse files Browse the repository at this point in the history
* implement bridge computation

* added tests

* fix reference

* fix docstring

* change to Edge

* simplify test

* fix tests

* fix tests for real

* just add one edge

* remove unnecessary lines

* implement suggestions

* rename to bridges

* added check for undirectedness

* use dispatch on trait IsDirected

* update docs

* Update bridge.jl

add newlines between signature and start of doc
  • Loading branch information
Pietro Vertechi authored and sbromberger committed Jan 18, 2019
1 parent b1e95f8 commit ee0db34
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/src/pathing.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ condensation
neighborhood
neighborhood_dists
articulation
bridges
period
isgraphical
```
Expand Down
3 changes: 2 additions & 1 deletion src/LightGraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ euclidean_graph,
kruskal_mst, prim_mst,

#biconnectivity and articulation points
articulation, biconnected_components,
articulation, biconnected_components, bridges,

#graphcut
normalized_cut, karger_min_cut, karger_cut_cost, karger_cut_edges,
Expand Down Expand Up @@ -250,6 +250,7 @@ include("spanningtrees/kruskal.jl")
include("spanningtrees/prim.jl")
include("biconnectivity/articulation.jl")
include("biconnectivity/biconnect.jl")
include("biconnectivity/bridge.jl")
include("graphcut/normalized_cut.jl")
include("graphcut/karger_min_cut.jl")
include("dominatingset/degree_dom_set.jl")
Expand Down
81 changes: 81 additions & 0 deletions src/biconnectivity/bridge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""
Bridges{T}
A state type for the depth-first search that finds bridges in a graph.
"""
mutable struct Bridges{T<:Integer}
low::Vector{T}
depth::Vector{T}
bridges::Vector{Edge{T}}
id::T
end

function Bridges(g::AbstractGraph)
n = nv(g)
T = eltype(g)
return Bridges(zeros(T, n), zeros(T, n), Edge{T}[], zero(T))
end

"""
visit!(state, g, u, v)
Perform a depth first search storing the depth (in `depth`) and low-points
(in `low`) of each vertex.
"""
function visit!(state::Bridges, g::AbstractGraph, u::Integer, v::Integer)
state.id += 1
state.depth[v] = state.id
state.low[v] = state.depth[v]

@inbounds for w in outneighbors(g, v)
if state.depth[w] == 0
visit!(state, g, v, w)

state.low[v] = min(state.low[v], state.low[w])
if state.low[w] > state.depth[v]
edge = v < w ? Edge(v, w) : Edge(w, v)
push!(state.bridges, edge)
end

elseif w != u
state.low[v] = min(state.low[v], state.depth[w])
end
end
end

"""
bridges(g)
Compute the [bridges](https://en.m.wikipedia.org/wiki/Bridge_(graph_theory))
of a connected graph `g` and return an array containing all bridges, i.e edges
whose deletion increases the number of connected components of the graph.
# Examples
```jldoctest
julia> using LightGraphs
julia> bridges(StarGraph(5))
8-element Array{LightGraphs.SimpleGraphs.SimpleEdge{Int64},1}:
Edge 1 => 2
Edge 1 => 3
Edge 1 => 4
Edge 1 => 5
julia> bridges(PathGraph(5))
8-element Array{LightGraphs.SimpleGraphs.SimpleEdge{Int64},1}:
Edge 4 => 5
Edge 3 => 4
Edge 2 => 3
Edge 1 => 2
```
"""
function bridges end

@traitfn function bridges(g::AG::(!IsDirected)) where {T<:Integer, AG<:AbstractGraph{T}}
state = Bridges(g)
for u in vertices(g)
if state.depth[u] == 0
visit!(state, g, u, u)
end
end
return state.bridges
end
50 changes: 50 additions & 0 deletions test/biconnectivity/bridge.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@testset "Bridge" begin
gint = SimpleGraph(13)
add_edge!(gint, 1, 7)
add_edge!(gint, 1, 2)
add_edge!(gint, 1, 3)
add_edge!(gint, 12, 13)
add_edge!(gint, 10, 13)
add_edge!(gint, 10, 12)
add_edge!(gint, 12, 11)
add_edge!(gint, 5, 4)
add_edge!(gint, 6, 4)
add_edge!(gint, 8, 9)
add_edge!(gint, 6, 5)
add_edge!(gint, 1, 6)
add_edge!(gint, 7, 5)
add_edge!(gint, 7, 3)
add_edge!(gint, 7, 8)
add_edge!(gint, 7, 10)
add_edge!(gint, 7, 12)

for g in testgraphs(gint)
brd = @inferred(bridges(g))
ans = [
Edge(1, 2),
Edge(8, 9),
Edge(7, 8),
Edge(11, 12),
]
@test brd == ans
end
for level in 1:6
btree = LightGraphs.BinaryTree(level)
for tree in [btree, Graph{UInt8}(btree), Graph{Int16}(btree)]
brd = @inferred(bridges(tree))
ans = collect(edges(tree))
@test Set(brd) == Set(ans)
end
end

hint = blockdiag(WheelGraph(5), WheelGraph(5))
add_edge!(hint, 5, 6)
for h in (hint, Graph{UInt8}(hint), Graph{Int16}(hint))
@test @inferred(bridges(h)) == [
Edge(5, 6),
]
end

dir = SimpleDiGraph(10, 10)
@test_throws MethodError bridges(dir)
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ tests = [
"spanningtrees/prim",
"biconnectivity/articulation",
"biconnectivity/biconnect",
"biconnectivity/bridge",
"graphcut/normalized_cut",
"graphcut/karger_min_cut",
"dominatingset/degree_dom_set",
Expand Down

0 comments on commit ee0db34

Please sign in to comment.