Skip to content

Commit 1dd2f5e

Browse files
matbesancongdalle
andauthored
Added maximum (weight) cliques (#21)
* format * include test * Add to obj --------- Co-authored-by: Guillaume Dalle <22795598+gdalle@users.noreply.github.com>
1 parent 2295e2e commit 1dd2f5e

File tree

5 files changed

+85
-0
lines changed

5 files changed

+85
-0
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 clique
74+
75+
```@docs
76+
maximum_weight_clique
77+
GraphsOptim.maximum_weight_clique!
78+
```
79+
80+
A *clique* is a subset $S \subset V$ of vertices of an undirected graph $G = (V,E)$ such that $\forall (u,v) \in S: (u, v) \in E$. We search for the clique maximizing the total weight of selected vertices.
81+
7382
## Maximum Weight Independent Set
7483

7584
```@docs

src/GraphsOptim.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export min_vertex_cover
2727
export maximum_weight_independent_set
2828
export fractional_chromatic_number, fractional_clique_number
2929
export shortest_path
30+
export maximum_weight_clique
3031

3132
include("utils.jl")
3233
include("flow.jl")
@@ -35,6 +36,7 @@ include("graph_matching.jl")
3536
include("min_vertex_cover.jl")
3637
include("fractional_coloring.jl")
3738
include("shortest_path.jl")
39+
include("maximum_clique.jl")
3840
include("independent_set.jl")
3941

4042
end

src/maximum_clique.jl

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
"""
3+
maximum_weight_clique!(model, g; var_name)
4+
5+
Computes in-place in the JuMP model a maximum-weighted clique of `g`.
6+
An optional `vertex_weights` vector can be passed to the graph, defaulting to uniform weights (computing a maximum size clique).
7+
"""
8+
function maximum_weight_clique!(
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+
packing_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_clique(g; optimizer, binary, vertex_weights)
30+
31+
Computes a maximum-weighted clique of `g`.
32+
"""
33+
function maximum_weight_clique(
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_clique!(
42+
model, g; binary=binary, vertex_weights=vertex_weights, var_name=:clique
43+
)
44+
optimize!(model)
45+
@assert termination_status(model) == OPTIMAL
46+
clique_variables = Vector(model[:clique])
47+
clique_vertices = findall(v -> value(v) > 0.5, clique_variables)
48+
return clique_vertices
49+
end

test/maximum_clique.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
clique = GraphsOptim.maximum_weight_clique(g; vertex_weights=vertex_weights)
10+
if length(clique) > 1
11+
for idx in 1:(length(clique) - 1)
12+
@test Graphs.has_edge(g, clique[idx], clique[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+
clique = GraphsOptim.maximum_weight_clique(g2)
21+
@test sort(clique) == 1:3

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 "Cliques" begin
48+
include("maximum_clique.jl")
49+
end
50+
4751
@testset verbose = true "Independent set" begin
4852
include("independent_set.jl")
4953
end

0 commit comments

Comments
 (0)