Skip to content

Commit 665e66f

Browse files
committed
independent set
1 parent f2cf29d commit 665e66f

File tree

5 files changed

+83
-0
lines changed

5 files changed

+83
-0
lines changed

docs/src/algorithms.md

+9
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ GraphsOptim.min_vertex_cover!
7070

7171
Finds a subset $S \subset V$ of vertices of an undirected graph $G = (V,E)$ such that $\forall (u,v) \in E: u \in S \lor v \in S$
7272

73+
## Maximum Weight Independent Set
74+
75+
```@docs
76+
maximum_weight_independent_set
77+
GraphsOptim.maximum_weight_independent_set!
78+
```
79+
80+
Finds a subset $S \subset V$ of vertices of maximal weight of an undirected graph $G = (V,E)$ such that $\forall (u,v) \in E: u \notin S \lor v \notin S$.
81+
7382
## Graph matching
7483

7584
!!! danger "Work in progress"

src/GraphsOptim.jl

+1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ include("graph_matching.jl")
3434
include("min_vertex_cover.jl")
3535
include("fractional_coloring.jl")
3636
include("shortest_path.jl")
37+
include("independent_set.jl")
3738

3839
end

src/independent_set.jl

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
"""
3+
maximum_independent_set!(model, g; var_name)
4+
5+
Computes in-place in the JuMP model a maximum-weighted independent set of `g`.
6+
An optional `vertex_weights` vector can be passed to the graph, defaulting to uniform weights (computing a maximum size independent set).
7+
"""
8+
function maximum_weight_independent_set!(
9+
model::Model, g::AbstractGraph; binary::Bool=true, var_name, vertex_weights=ones(nv(g))
10+
)
11+
if is_directed(g)
12+
throw(ArgumentError("The graph must not be directed"))
13+
end
14+
g_vertices = collect(vertices(g))
15+
f = @variable(model, [g_vertices]; binary=binary, base_name=String(var_name))
16+
model[Symbol(var_name)] = f
17+
@constraint(
18+
model,
19+
covering_constraint[i=1:nv(g), j=1:nv(g); i j && has_edge(g, i, j)],
20+
f[i] + f[j] <= 1,
21+
)
22+
@objective(model, Max, dot(f, vertex_weights))
23+
return model
24+
end
25+
26+
"""
27+
maximum_weight_independent_set(g; optimizer, binary, vertex_weights)
28+
29+
Computes a maximum-weighted independent set or stable set of `g`.
30+
"""
31+
function maximum_weight_independent_set(
32+
g::AbstractGraph;
33+
binary::Bool=true,
34+
vertex_weights=ones(nv(g)),
35+
optimizer=HiGHS.Optimizer,
36+
)
37+
model = Model(optimizer)
38+
set_silent(model)
39+
maximum_weight_independent_set!(
40+
model, g; binary=binary, vertex_weights=vertex_weights, var_name=:stable
41+
)
42+
optimize!(model)
43+
@assert termination_status(model) == OPTIMAL
44+
stable_variables = Vector(model[:stable])
45+
stable_vertices = findall(v -> value(v) > 0.5, stable_variables)
46+
return stable_vertices
47+
end

test/independent_set.jl

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using GraphsOptim
2+
using Graphs
3+
using Test
4+
5+
g = Graphs.random_regular_graph(10, 5)
6+
7+
for _ in 1:10
8+
vertex_weights = rand(nv(g))
9+
stable = GraphsOptim.maximum_weight_independent_set(g; vertex_weights=vertex_weights)
10+
if length(stable) > 1
11+
for idx in 1:(length(stable) - 1)
12+
@test !Graphs.has_edge(g, stable[idx], stable[idx + 1])
13+
end
14+
end
15+
end
16+
17+
g2 = complete_graph(3)
18+
add_vertex!(g2)
19+
add_edge!(g2, 3, 4)
20+
stable = GraphsOptim.maximum_weight_independent_set(g2)
21+
@test length(stable) == 2
22+
@test 4 in stable

test/runtests.jl

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ using Test
4444
include("min_vertex_cover.jl")
4545
end
4646

47+
@testset verbose = true "Independent set" begin
48+
include("independent_set.jl")
49+
end
50+
4751
@testset verbose = true "Fractional coloring" begin
4852
include("fractional_coloring.jl")
4953
end

0 commit comments

Comments
 (0)