Skip to content

Commit

Permalink
Set covering (#39)
Browse files Browse the repository at this point in the history
* Update src/models/Coloring.jl

Co-authored-by: Jinguo Liu <cacate0129@gmail.com>

* update comment

* New: "SetCovering" model

* New:"SetCovering" model

* Add: single test & Clean up

* New:"findbest" function in set covering

* Add: single test of terms

---------

Co-authored-by: Jinguo Liu <cacate0129@gmail.com>
  • Loading branch information
c-allergic and GiggleLiu authored Jul 17, 2024
1 parent a744429 commit 1a398d2
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/models/SetCovering.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
$TYPEDEF
The [set covering problem](https://queracomputing.github.io/GenericTensorNetworks.jl/dev/generated/SetCovering/).
Positional arguments
-------------------------------
* `sets` is a vector of vectors, a collection of subsets of universe , each set is associated with a weight specified in `weights`.
* `weights` are associated with sets.
"""

struct SetCovering{ET, WT<:Union{UnitWeight, Vector}} <: AbstractProblem
sets::Vector{Vector{ET}}
weights::WT
function SetCovering(sets::Vector{Vector{ET}}, weights::Union{UnitWeight, Vector}=UnitWeight()) where {ET}
@assert weights isa UnitWeight || length(weights) == length(sets)
new{ET, typeof(weights)}(sets, weights)
end
end
Base.:(==)(a::SetCovering, b::SetCovering) = a.sets == b.sets && a.weights == b.weights

#variables interface
variables(gp::SetCovering) = gp.sets
num_variables(c::SetCovering) = length(c.sets)
flavors(::Type{<:SetCovering}) = [0, 1] #whether the set is selected or not



# weights interface
parameters(c::SetCovering) = c.weights
set_parameters(c::SetCovering, weights) = SetCovering(c.sets, weights)
terms(gp::SetCovering) = [[i] for i=1:length(gp.sets)] # return the index of sets

"""
evaluate(c::SetCovering, config)
evaluate the energy of the set covering configuration `config`, the energy is the
sum of the weights of the sets that are selected. Config is a vector of boolean numbers.
"""

function evaluate(c::SetCovering, config)
@assert length(config) == num_variables(c)
set_covering_energy(c.weights, config )
end
set_covering_energy(weights::AbstractVector, config) = sum(weights[i]*config[i] for i=1:length(weights))

"""
findbest(c::SetCovering) -> Vector
Find the best configurations of the `c` using the `method`. We offer bruteforce search as the default method.
"""

function findbest(c::SetCovering, method="bruteforce")
best = nothing
best_energy = Inf
for config in Iterators.product((fill([0,1],num_variables(c)))...)
if sum(config) == 0
continue
end
if is_set_covering(c,config)
energy = evaluate(c,config)
if energy < best_energy
best = config
best_energy = energy
end
end
end
return best
end

"""
is_set_covering(sets::AbstractVector, config)
Return true if `config` (a vector of boolean numbers as the mask of sets) is a set covering of `sets`.
"""
function is_set_covering(c::SetCovering, config)
return reduce(union,c.sets)==reduce(union,c.sets[i] for i in 1:length(config) if config[i]==1)
end
1 change: 1 addition & 0 deletions src/models/models.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,4 @@ Base.eltype(::UnitWeight) = Int
include("SpinGlass.jl")
include("Circuit.jl")
include("Coloring.jl")
include("SetCovering.jl")
27 changes: 27 additions & 0 deletions test/models/SetCovering.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Test, ProblemReductions, Graphs
using ProblemReductions: SetCovering, variables, flavors, terms, evaluate, set_parameters, parameters,is_set_covering,set_covering_energy, findbest

@testset "setcovering" begin
c = SetCovering([[1, 2], [2, 3], [2, 3, 4]], [1, 1, 2])
# constructor function
@test variables(c)==[[1,2],[2,3],[2,3,4]]
@test num_variables(c) == 3
@test flavors(SetCovering) == [0, 1]
@test terms(c) == [[1], [2], [3]]

# weights interface
@test parameters(c) == [1, 1, 2]
@test set_parameters(c, [1, 2, 3]) == SetCovering([[1, 2], [2, 3], [2, 3, 4]], [1, 2, 3])

# evaluate
@test evaluate(c, [0, 1, 1]) == 3
@test set_covering_energy([1, 1, 2], [0, 0, 1]) == 2
@test is_set_covering(c,[1,0,1]) == true
@test is_set_covering(c,[0,0,1]) == false

# findbest
@test findbest(c) == (1,0,1)
@test findbest(c, "bruteforce") == (1,0,1)
g = SetCovering([[1, 2], [1, 3, 4], [2, 3]], [1, 1, 2])
@test findbest(g) == (1,1,0)
end
4 changes: 4 additions & 0 deletions test/models/models.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ end

@testset "Coloring" begin
include("Coloring.jl")
end

@testset "SetCovering" begin
include("SetCovering.jl")
end

0 comments on commit 1a398d2

Please sign in to comment.