Skip to content

Commit 2295e2e

Browse files
matbesancongdalle
andauthored
independent set (#22)
* independent set * import function * export function * fix export * Add to objective * Objective max --------- Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
1 parent f2cf29d commit 2295e2e

File tree

5 files changed

+87
-1
lines changed

5 files changed

+87
-1
lines changed

docs/src/algorithms.md

Lines changed: 9 additions & 0 deletions
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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A package for graph optimization algorithms that rely on mathematical programmin
66
module GraphsOptim
77

88
using Graphs: AbstractGraph, is_directed
9-
using Graphs: vertices, edges, nv, ne, src, dst, inneighbors, outneighbors
9+
using Graphs: vertices, edges, nv, ne, src, dst, inneighbors, outneighbors, has_edge
1010
using Graphs: complement, maximal_cliques
1111
using FillArrays: Zeros, Ones, Fill
1212
using HiGHS: HiGHS
@@ -24,6 +24,7 @@ export min_cost_flow
2424
export min_cost_assignment
2525
export FAQ, GOAT, graph_matching
2626
export min_vertex_cover
27+
export maximum_weight_independent_set
2728
export fractional_chromatic_number, fractional_clique_number
2829
export shortest_path
2930

@@ -34,5 +35,6 @@ include("graph_matching.jl")
3435
include("min_vertex_cover.jl")
3536
include("fractional_coloring.jl")
3637
include("shortest_path.jl")
38+
include("independent_set.jl")
3739

3840
end

src/independent_set.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
obj = objective_function(model)
23+
add_to_expression!(obj, dot(f, vertex_weights))
24+
@objective(model, Max, obj)
25+
return model
26+
end
27+
28+
"""
29+
maximum_weight_independent_set(g; optimizer, binary, vertex_weights)
30+
31+
Computes a maximum-weighted independent set or stable set of `g`.
32+
"""
33+
function maximum_weight_independent_set(
34+
g::AbstractGraph;
35+
binary::Bool=true,
36+
vertex_weights=ones(nv(g)),
37+
optimizer=HiGHS.Optimizer,
38+
)
39+
model = Model(optimizer)
40+
set_silent(model)
41+
maximum_weight_independent_set!(
42+
model, g; binary=binary, vertex_weights=vertex_weights, var_name=:stable
43+
)
44+
optimize!(model)
45+
@assert termination_status(model) == OPTIMAL
46+
stable_variables = Vector(model[:stable])
47+
stable_vertices = findall(v -> value(v) > 0.5, stable_variables)
48+
return stable_vertices
49+
end

test/independent_set.jl

Lines changed: 22 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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)