Skip to content

Commit

Permalink
independent set (#22)
Browse files Browse the repository at this point in the history
* independent set

* import function

* export function

* fix export

* Add to objective

* Objective max

---------

Co-authored-by: Guillaume Dalle <[email protected]>
  • Loading branch information
matbesancon and gdalle authored Apr 26, 2024
1 parent f2cf29d commit 2295e2e
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 1 deletion.
9 changes: 9 additions & 0 deletions docs/src/algorithms.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ GraphsOptim.min_vertex_cover!

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$

## Maximum Weight Independent Set

```@docs
maximum_weight_independent_set
GraphsOptim.maximum_weight_independent_set!
```

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$.

## Graph matching

!!! danger "Work in progress"
Expand Down
4 changes: 3 additions & 1 deletion src/GraphsOptim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A package for graph optimization algorithms that rely on mathematical programmin
module GraphsOptim

using Graphs: AbstractGraph, is_directed
using Graphs: vertices, edges, nv, ne, src, dst, inneighbors, outneighbors
using Graphs: vertices, edges, nv, ne, src, dst, inneighbors, outneighbors, has_edge
using Graphs: complement, maximal_cliques
using FillArrays: Zeros, Ones, Fill
using HiGHS: HiGHS
Expand All @@ -24,6 +24,7 @@ export min_cost_flow
export min_cost_assignment
export FAQ, GOAT, graph_matching
export min_vertex_cover
export maximum_weight_independent_set
export fractional_chromatic_number, fractional_clique_number
export shortest_path

Expand All @@ -34,5 +35,6 @@ include("graph_matching.jl")
include("min_vertex_cover.jl")
include("fractional_coloring.jl")
include("shortest_path.jl")
include("independent_set.jl")

end
49 changes: 49 additions & 0 deletions src/independent_set.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

"""
maximum_independent_set!(model, g; var_name)
Computes in-place in the JuMP model a maximum-weighted independent set of `g`.
An optional `vertex_weights` vector can be passed to the graph, defaulting to uniform weights (computing a maximum size independent set).
"""
function maximum_weight_independent_set!(
model::Model, g::AbstractGraph; binary::Bool=true, var_name, vertex_weights=ones(nv(g))
)
if is_directed(g)
throw(ArgumentError("The graph must not be directed"))
end
g_vertices = collect(vertices(g))
f = @variable(model, [g_vertices]; binary=binary, base_name=String(var_name))
model[Symbol(var_name)] = f
@constraint(
model,
covering_constraint[i=1:nv(g), j=1:nv(g); i j && has_edge(g, i, j)],
f[i] + f[j] <= 1,
)
obj = objective_function(model)
add_to_expression!(obj, dot(f, vertex_weights))
@objective(model, Max, obj)
return model
end

"""
maximum_weight_independent_set(g; optimizer, binary, vertex_weights)
Computes a maximum-weighted independent set or stable set of `g`.
"""
function maximum_weight_independent_set(
g::AbstractGraph;
binary::Bool=true,
vertex_weights=ones(nv(g)),
optimizer=HiGHS.Optimizer,
)
model = Model(optimizer)
set_silent(model)
maximum_weight_independent_set!(
model, g; binary=binary, vertex_weights=vertex_weights, var_name=:stable
)
optimize!(model)
@assert termination_status(model) == OPTIMAL
stable_variables = Vector(model[:stable])
stable_vertices = findall(v -> value(v) > 0.5, stable_variables)
return stable_vertices
end
22 changes: 22 additions & 0 deletions test/independent_set.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using GraphsOptim
using Graphs
using Test

g = Graphs.random_regular_graph(10, 5)

for _ in 1:10
vertex_weights = rand(nv(g))
stable = GraphsOptim.maximum_weight_independent_set(g; vertex_weights=vertex_weights)
if length(stable) > 1
for idx in 1:(length(stable) - 1)
@test !Graphs.has_edge(g, stable[idx], stable[idx + 1])
end
end
end

g2 = complete_graph(3)
add_vertex!(g2)
add_edge!(g2, 3, 4)
stable = GraphsOptim.maximum_weight_independent_set(g2)
@test length(stable) == 2
@test 4 in stable
4 changes: 4 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ using Test
include("min_vertex_cover.jl")
end

@testset verbose = true "Independent set" begin
include("independent_set.jl")
end

@testset verbose = true "Fractional coloring" begin
include("fractional_coloring.jl")
end
Expand Down

0 comments on commit 2295e2e

Please sign in to comment.