From f592ab87dc3b199b64d30c95584819020dc5265c Mon Sep 17 00:00:00 2001 From: c-allergic Date: Mon, 31 Mar 2025 22:03:33 +0800 Subject: [PATCH 1/6] New model:Clique Cover --- src/ProblemReductions.jl | 1 + src/models/CliqueCover.jl | 54 ++++++++++++++++++++++++++++++++++++++ src/models/models.jl | 1 + test/models/CliqueCover.jl | 16 +++++++++++ test/models/models.jl | 3 +++ 5 files changed, 75 insertions(+) create mode 100644 src/models/CliqueCover.jl create mode 100644 test/models/CliqueCover.jl diff --git a/src/ProblemReductions.jl b/src/ProblemReductions.jl index 0ee2489..ffa7c02 100644 --- a/src/ProblemReductions.jl +++ b/src/ProblemReductions.jl @@ -32,6 +32,7 @@ export MaximalIS export PaintShop export BinaryMatrixFactorization, is_binary_matrix_factorization export BicliqueCover, is_biclique_cover +export CliqueCover,is_clique_cover,is_clique_cover # rules export target_problem, AbstractProblem, ConstraintSatisfactionProblem, solution_size, solution_size_multiple, SolutionSize, objectives, constraints, energy_mode diff --git a/src/models/CliqueCover.jl b/src/models/CliqueCover.jl new file mode 100644 index 0000000..a490603 --- /dev/null +++ b/src/models/CliqueCover.jl @@ -0,0 +1,54 @@ +""" +$TYPEDEF + CliqueCover{K}(graph::SimpleGraph{Int64}, k::Int64) + +A clique cover of a graph G is a set of cliques such that all vertices in G is coverd by the vertices union of these cliques. A K clique cover is to find whether we could use only k cliques to cover all the vertices in the graph. + +""" +struct CliqueCover{Int64} <: ConstraintSatisfactionProblem{Int64} + graph::SimpleGraph{Int64} + k::Int64 + function CliqueCover(graph::SimpleGraph{Int64}, k::Int64) + new{Int64}(graph, k) + end +end +problem_size(c::CliqueCover) = (; num_vertices=nv(c.graph), num_edges=ne(c.graph), k=c.k) +num_variables(c::CliqueCover) = nv(c.graph) * c.k +num_flavors(c::CliqueCover) = 2 + +# constraints interface +function constraints(c::CliqueCover) + return [LocalConstraint(num_flavors(c), v, [0,1]) for v in vertices(c.graph)] +end +function objectives(c::CliqueCover) + return [LocalSolutionSize(num_flavors(c), [v], [0, 1]) for v in vertices(c.graph)] +end +energy_mode(::Type{<:CliqueCover}) = SmallerSizeIsBetter() + +function is_clique_cover(configs::Vector{Vector{Int64}}, c::CliqueCover) + # check if they are all valid clique + if any(config -> !is_clique(c, config), configs) + return false + end + vertices_covered = reduce(vcat, [findall(x-> x==1,config) for config in configs]) + # check if the vertices are covered by the cliques + if length(vertices_covered) != nv(c.graph) + return false + end + return true +end +function is_clique(c::CliqueCover,config::Vector{Int64}) + vertices = findall(x -> x == 1, config) + for (v1, v2) in collect(Iterators.product(vertices, vertices)) + # pass if the vertices are the same + if v1 == v2 + continue + end + # check if the edge exists in the graph, if not, return false + if !has_edge(c.graph, v1, v2) + print("Edge ($v1, $v2) does not exist in the graph") + return false + end + end + return true +end \ No newline at end of file diff --git a/src/models/models.jl b/src/models/models.jl index da0dcd9..caf5a66 100644 --- a/src/models/models.jl +++ b/src/models/models.jl @@ -376,3 +376,4 @@ include("MaximalIS.jl") include("Paintshop.jl") include("BicliqueCover.jl") include("BMF.jl") +include("CliqueCover.jl") diff --git a/test/models/CliqueCover.jl b/test/models/CliqueCover.jl new file mode 100644 index 0000000..a8ab304 --- /dev/null +++ b/test/models/CliqueCover.jl @@ -0,0 +1,16 @@ +using Test, ProblemReductions, Graphs + +@testset "CliqueCover" begin + g = SimpleGraph(5) + for (i,j) in [(1,3),(1,5),(2,3),(2,4),(3,5)] + add_edge!(g,i,j) + end + c = CliqueCover(g,2) + @test num_variables(c) == 5 * 2 + @test num_flavors(c) == 2 + @test problem_size(c) == (; num_vertices=5, num_edges=5, k=2) + @test Base.:(==)(c, CliqueCover(g,2)) + @test energy_mode(c) == SmallerSizeIsBetter() + @test is_clique_cover([[1,0,1,0,1],[0,1,0,1,0]],c) == true + @test ProblemReductions.is_clique(c,[1,0,1,0,1]) == true +end \ No newline at end of file diff --git a/test/models/models.jl b/test/models/models.jl index 13bb99f..f17a516 100644 --- a/test/models/models.jl +++ b/test/models/models.jl @@ -74,3 +74,6 @@ end include("BicliqueCover.jl") end +@testset "CliqueCover" begin + include("CliqueCover.jl") +end \ No newline at end of file From e856b190fa1ab644e0d7b64d6039bb733191be36 Mon Sep 17 00:00:00 2001 From: c-allergic Date: Mon, 31 Mar 2025 22:10:39 +0800 Subject: [PATCH 2/6] Remove unnecessary line --- src/models/CliqueCover.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/models/CliqueCover.jl b/src/models/CliqueCover.jl index a490603..a694aa8 100644 --- a/src/models/CliqueCover.jl +++ b/src/models/CliqueCover.jl @@ -46,7 +46,6 @@ function is_clique(c::CliqueCover,config::Vector{Int64}) end # check if the edge exists in the graph, if not, return false if !has_edge(c.graph, v1, v2) - print("Edge ($v1, $v2) does not exist in the graph") return false end end From 66713d6ad26a5739284a6c89fa411590e2065a23 Mon Sep 17 00:00:00 2001 From: c-allergic Date: Mon, 31 Mar 2025 22:15:39 +0800 Subject: [PATCH 3/6] Remove redundant code --- src/ProblemReductions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ProblemReductions.jl b/src/ProblemReductions.jl index ffa7c02..65c8bf4 100644 --- a/src/ProblemReductions.jl +++ b/src/ProblemReductions.jl @@ -32,7 +32,7 @@ export MaximalIS export PaintShop export BinaryMatrixFactorization, is_binary_matrix_factorization export BicliqueCover, is_biclique_cover -export CliqueCover,is_clique_cover,is_clique_cover +export CliqueCover,is_clique_cover # rules export target_problem, AbstractProblem, ConstraintSatisfactionProblem, solution_size, solution_size_multiple, SolutionSize, objectives, constraints, energy_mode From be2b76bb2e59e042206ab06d89c019f64b0a15f1 Mon Sep 17 00:00:00 2001 From: c-allergic Date: Tue, 1 Apr 2025 10:18:13 +0800 Subject: [PATCH 4/6] add tests --- test/models/CliqueCover.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/models/CliqueCover.jl b/test/models/CliqueCover.jl index a8ab304..0df83d9 100644 --- a/test/models/CliqueCover.jl +++ b/test/models/CliqueCover.jl @@ -12,5 +12,8 @@ using Test, ProblemReductions, Graphs @test Base.:(==)(c, CliqueCover(g,2)) @test energy_mode(c) == SmallerSizeIsBetter() @test is_clique_cover([[1,0,1,0,1],[0,1,0,1,0]],c) == true + @test is_clique_cover([[1,0,1,0,0],[0,1,0,1,0],[0,0,0,0,0]],c) == false + @test ProblemReductions.is_clique(c,[1,0,1,0,0]) == true + @test ProblemReductions.is_clique(c,[0,1,0,1,1]) == false @test ProblemReductions.is_clique(c,[1,0,1,0,1]) == true end \ No newline at end of file From 4224d5ae09d208d7a86a31e643fb1973b716b0dc Mon Sep 17 00:00:00 2001 From: c-allergic Date: Tue, 1 Apr 2025 10:40:23 +0800 Subject: [PATCH 5/6] Add logic and tests --- src/models/CliqueCover.jl | 7 +++++++ test/models/CliqueCover.jl | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/models/CliqueCover.jl b/src/models/CliqueCover.jl index a694aa8..d088563 100644 --- a/src/models/CliqueCover.jl +++ b/src/models/CliqueCover.jl @@ -26,13 +26,20 @@ end energy_mode(::Type{<:CliqueCover}) = SmallerSizeIsBetter() function is_clique_cover(configs::Vector{Vector{Int64}}, c::CliqueCover) + # check if the number of cliques is equal to k + if length(configs) != c.k + print(1) + return false + end # check if they are all valid clique if any(config -> !is_clique(c, config), configs) + print(2) return false end vertices_covered = reduce(vcat, [findall(x-> x==1,config) for config in configs]) # check if the vertices are covered by the cliques if length(vertices_covered) != nv(c.graph) + print(3) return false end return true diff --git a/test/models/CliqueCover.jl b/test/models/CliqueCover.jl index 0df83d9..9204b80 100644 --- a/test/models/CliqueCover.jl +++ b/test/models/CliqueCover.jl @@ -13,7 +13,21 @@ using Test, ProblemReductions, Graphs @test energy_mode(c) == SmallerSizeIsBetter() @test is_clique_cover([[1,0,1,0,1],[0,1,0,1,0]],c) == true @test is_clique_cover([[1,0,1,0,0],[0,1,0,1,0],[0,0,0,0,0]],c) == false + @test is_clique_cover([[1,0,1,0,0],[0,1,0,1,1]],c) == false @test ProblemReductions.is_clique(c,[1,0,1,0,0]) == true @test ProblemReductions.is_clique(c,[0,1,0,1,1]) == false @test ProblemReductions.is_clique(c,[1,0,1,0,1]) == true + + g1 = SimpleGraph(6) + for (i,j) in [(1,3),(1,5),(1,6),(2,3),(2,4),(3,4),(3,5),(4,6),(5,6)] + add_edge!(g1,i,j) + end + c1 = CliqueCover(g1,2) + @test is_clique_cover([[1,0,0,0,1,1],[0,1,1,1,0,0]],c1) == true + @test is_clique_cover([[1,0,1,0,1,0],[0,1,0,1,0,0]],c1) == false + @test is_clique_cover([[1,0,1,0,1,0],[0,1,0,1,0,0],[0,0,0,0,0,0]],c1) == false + @test ProblemReductions.is_clique(c1,[1,0,1,0,1,0]) == true + c2 = CliqueCover(g1,3) + @test is_clique_cover([[1,0,1,0,1,0],[0,1,0,1,0,0],[0,0,0,0,0,1]],c2) == true + @test is_clique_cover([[1,0,1,0,1,0],[0,1,0,1,0,0],[0,0,0,0,0,0]],c2) == false end \ No newline at end of file From 23bfa7189f01b1fd183c6882013bd049faa801c3 Mon Sep 17 00:00:00 2001 From: c-allergic Date: Wed, 2 Apr 2025 12:54:34 +0800 Subject: [PATCH 6/6] update src/CliqueCover.jl --- src/models/CliqueCover.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/CliqueCover.jl b/src/models/CliqueCover.jl index d088563..adda127 100644 --- a/src/models/CliqueCover.jl +++ b/src/models/CliqueCover.jl @@ -14,7 +14,7 @@ struct CliqueCover{Int64} <: ConstraintSatisfactionProblem{Int64} end problem_size(c::CliqueCover) = (; num_vertices=nv(c.graph), num_edges=ne(c.graph), k=c.k) num_variables(c::CliqueCover) = nv(c.graph) * c.k -num_flavors(c::CliqueCover) = 2 +num_flavors(::Type{<:CliqueCover}) = 2 # constraints interface function constraints(c::CliqueCover)