Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Vertex Cover #949

Merged
merged 20 commits into from
Sep 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/LightGraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ kruskal_mst, prim_mst,
articulation, biconnected_components,

#graphcut
normalized_cut, karger_min_cut, karger_cut_cost, karger_cut_edges
normalized_cut, karger_min_cut, karger_cut_cost, karger_cut_edges,

#vertexcover
vertex_cover

"""
LightGraphs
Expand Down Expand Up @@ -241,6 +244,8 @@ include("biconnectivity/articulation.jl")
include("biconnectivity/biconnect.jl")
include("graphcut/normalized_cut.jl")
include("graphcut/karger_min_cut.jl")
include("vertexcover/degree_vertex_cover.jl")
include("vertexcover/random_vertex_cover.jl")
include("Experimental/Experimental.jl")
include("Parallel/Parallel.jl")

Expand Down
1 change: 1 addition & 0 deletions src/Parallel/Parallel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ include("traversals/bfs.jl")
include("traversals/gdistances.jl")
include("traversals/greedy_color.jl")
include("utils.jl")
include("vertexcover/random_vertex_cover.jl")

# Overload until https://github.com/JuliaLang/julia/pull/28651
import Distributed: splitrange
Expand Down
13 changes: 13 additions & 0 deletions src/Parallel/vertexcover/random_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
vertex_cover(g, reps, RandomVertexCover(); parallel=:threads)

Perform [`LightGraphs.vertex_cover(g, RandomVertexCover())`](@ref) `reps` times in parallel
and return the solution with the fewest vertices.

### Optional Arguements
- `parallel=:threads`: If `parallel=:distributed` then the multiprocessor implementation is
used. This implementation is more efficient if `reps` is large.
"""
vertex_cover(g::AbstractGraph{T}, reps::Integer, alg::RandomVertexCover; parallel=:threads) where T <: Integer =
LightGraphs.Parallel.generate_reduce(g, (g::AbstractGraph{T})->LightGraphs.vertex_cover(g, alg),
(x::Vector{T}, y::Vector{T})->length(x)<length(y), reps; parallel=parallel)
1 change: 0 additions & 1 deletion src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ function unweighted_contiguous_partition(
return part
end


"""
greedy_contiguous_partition(weight, required_partitions, num_items=length(weight))

Expand Down
40 changes: 40 additions & 0 deletions src/vertexcover/degree_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export DegreeVertexCover

struct DegreeVertexCover end

"""
vertex_cover(g, DegreeVertexCover())

Obtain a vertex cover using a greedy heuristic.

### Implementation Notes
An edge is said to be covered if it has at least one end-point in the vertex cover.
Initialise the vertex cover to an empty set and iteratively choose the vertex with the most uncovered
edges.

### Performance
Runtime: O((|V|+|E|)*log(|V|))
Memory: O(|V|)
"""
function vertex_cover(
g::AbstractGraph{T},
alg::DegreeVertexCover
) where T <: Integer

nvg = nv(g)
in_cover = falses(nvg)
degree_queue = PriorityQueue(Base.Order.Reverse, enumerate(degree(g)))

while !isempty(degree_queue) && peek(degree_queue)[2] > 0
v = dequeue!(degree_queue)
in_cover[v] = true

@inbounds @simd for u in neighbors(g, v)
if !in_cover[u]
degree_queue[u] -= 1
end
end
end

return [v for v in vertices(g) if in_cover[v]]
end
38 changes: 38 additions & 0 deletions src/vertexcover/random_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export RandomVertexCover

struct RandomVertexCover end

"""
vertex_cover(g, RandomVertexCover())

Find a set of vertices such that every edge in `g` has some vertex in the set as
atleast one of its end point.

### Implementation Notes
Performs [Approximate Minimum Vertex Cover](https://en.wikipedia.org/wiki/Vertex_cover#Approximate_evaluation) once.
Returns a vector of vertices representing the vertices in the Vertex Cover.

### Performance
Runtime: O(|V|+|E|)
Memory: O(|E|)
Approximation Factor: 2
"""
function vertex_cover(
g::AbstractGraph{T},
alg::RandomVertexCover
) where T <: Integer

nvg::T = nv(g)
cover = Vector{T}()
in_cover = falses(nvg)

@inbounds for e in shuffle(collect(edges(g)))
if !(in_cover[e.src] || in_cover[e.dst])
in_cover[e.src] = in_cover[e.dst] = true
push!(cover, e.src)
push!(cover, e.dst)
end
end

return [v for v in vertices(g) if in_cover[v]]
end
1 change: 1 addition & 0 deletions test/parallel/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ tests = [
"traversals/bfs",
"traversals/gdistances",
"traversals/greedy_color",
"vertexcover/random_vertex_cover",
"utils"
]

Expand Down
27 changes: 27 additions & 0 deletions test/parallel/vertexcover/random_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@testset "Parallel.Random Vertex Cover" begin

g3 = StarGraph(5)
for parallel in [:threads, :distributed]
for g in testgraphs(g3)
c = @inferred(Parallel.vertex_cover(g, 4, RandomVertexCover(); parallel=parallel))
@test (length(c)== 2 && (c[1] == 1 || c[2] == 1))
end
end

g4 = CompleteGraph(5)
for parallel in [:threads, :distributed]
for g in testgraphs(g4)
c = @inferred(Parallel.vertex_cover(g, 4, RandomVertexCover(); parallel=parallel))
@test length(c)== 4 #All except one vertex
end
end

g5 = PathGraph(5)
for parallel in [:threads, :distributed]
for g in testgraphs(g5)
c = @inferred(Parallel.vertex_cover(g, 4, RandomVertexCover(); parallel=parallel))
sort!(c)
@test (c == [1, 2, 3, 4] || c == [1, 2, 4, 5] || c == [2, 3, 4, 5])
end
end
end
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ tests = [
"biconnectivity/biconnect",
"graphcut/normalized_cut",
"graphcut/karger_min_cut",
"vertexcover/degree_vertex_cover",
"vertexcover/random_vertex_cover",
"experimental/experimental"
]

Expand Down
21 changes: 21 additions & 0 deletions test/vertexcover/degree_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@testset "Degree Vertex Cover" begin

g3 = StarGraph(5)
for g in testgraphs(g3)
c = @inferred(vertex_cover(g, DegreeVertexCover()))
@test c == [1,]
end

g4 = CompleteGraph(5)
for g in testgraphs(g4)
c = @inferred(vertex_cover(g, DegreeVertexCover()))
@test length(c)== 4 #All except one vertex
end

#PathGraph(5) with additional edge 2-5
g5 = Graph([0 1 0 0 0; 1 0 1 0 1; 0 1 0 1 0; 0 0 1 0 1; 0 1 0 1 0])
for g in testgraphs(g5)
c = @inferred(vertex_cover(g, DegreeVertexCover()))
@test sort(c) == [2, 4]
end
end
21 changes: 21 additions & 0 deletions test/vertexcover/random_vertex_cover.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@testset "Random Vertex Cover" begin

g3 = StarGraph(5)
for g in testgraphs(g3)
c = @inferred(vertex_cover(g, RandomVertexCover()))
@test (length(c)== 2 && (c[1] == 1 || c[2] == 1))
end

g4 = CompleteGraph(5)
for g in testgraphs(g4)
c = @inferred(vertex_cover(g, RandomVertexCover()))
@test length(c)== 4 #All except one vertex
end

g5 = PathGraph(5)
for g in testgraphs(g5)
c = @inferred(vertex_cover(g, RandomVertexCover()))
sort!(c)
@test (c == [1, 2, 3, 4] || c == [1, 2, 4, 5] || c == [2, 3, 4, 5])
end
end