Skip to content

Commit 477d550

Browse files
authored
add weights for Sat, Matching and Coloring (#29)
1 parent b4d2a4a commit 477d550

File tree

9 files changed

+97
-24
lines changed

9 files changed

+97
-24
lines changed

docs/src/ref.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ paint_shop_coloring_from_config
4747
4848
is_good_vertex_coloring
4949
50+
is_matching
51+
5052
CNF
5153
CNFClause
5254
BoolVar

src/GraphTensorNetworks.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export mis_compactify!, cut_size, num_paint_shop_color_switch, paint_shop_colori
4242
export is_good_vertex_coloring
4343
export CNF, CNFClause, BoolVar, satisfiable, @bools, , ¬,
4444
export is_dominating_set
45+
export is_matching
4546

4647
# Interfaces
4748
export solve, SizeMax, SizeMin, CountingAll, CountingMax, CountingMin, GraphPolynomial, SingleConfigMax, SingleConfigMin, ConfigsAll, ConfigsMax, ConfigsMin

src/networks/Coloring.jl

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
"""
2-
Coloring{K,CT<:AbstractEinsum} <: GraphProblem
3-
Coloring{K}(graph; openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
2+
Coloring{K,CT<:AbstractEinsum, WT<:Union{NoWeight, Vector}} <: GraphProblem
3+
Coloring{K}(graph; weights=NoWeight(), openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
44
55
The [Vertex Coloring](https://psychic-meme-f4d866f8.pages.github.io/dev/tutorials/Coloring.html) problem.
6+
`weights` has one to one correspondence with `edges(graph)`.
67
`optimizer` and `simplifier` are for tensor network optimization, check [`optimize_code`](@ref) for details.
78
"""
8-
struct Coloring{K,CT<:AbstractEinsum} <: GraphProblem
9+
struct Coloring{K,CT<:AbstractEinsum,WT<:Union{NoWeight, Vector}} <: GraphProblem
910
code::CT
1011
graph::SimpleGraph{Int}
12+
weights::WT
1113
end
12-
Coloring{K}(code::ET, graph::SimpleGraph) where {K,ET<:AbstractEinsum} = Coloring{K,ET}(code, graph)
14+
Coloring{K}(code::ET, graph::SimpleGraph, weights::Union{NoWeight, Vector}) where {K,ET<:AbstractEinsum} = Coloring{K,ET,typeof(weights)}(code, graph, weights)
1315
# same network layout as independent set.
14-
function Coloring{K}(g::SimpleGraph; openvertices=(), optimizer=GreedyMethod(), simplifier=nothing) where K
16+
function Coloring{K}(g::SimpleGraph; weights=NoWeight(), openvertices=(), optimizer=GreedyMethod(), simplifier=nothing) where K
17+
@assert weights isa NoWeight || length(weights) == ne(g)
1518
rawcode = EinCode(([[i] for i in Graphs.vertices(g)]..., # labels for vertex tensors
1619
[[minmax(e.src,e.dst)...] for e in Graphs.edges(g)]...), collect(Int, openvertices)) # labels for edge tensors
1720
code = _optimize_code(rawcode, uniformsize(rawcode, 2), optimizer, simplifier)
18-
Coloring{K}(code, g)
21+
Coloring{K}(code, g, weights)
1922
end
2023

2124
flavors(::Type{<:Coloring{K}}) where K = collect(0:K-1)
22-
get_weights(::Coloring{K}, i::Int) where K = ones(Int, K)
25+
get_weights(c::Coloring{K}, i::Int) where K = fill(c.weights[i], K)
2326
terms(gp::Coloring) = getixsv(gp.code)[1:nv(gp.graph)]
2427
labels(gp::Coloring) = [1:nv(gp.graph)...]
2528

2629
function generate_tensors(x::T, c::Coloring{K}) where {K,T}
2730
ixs = getixsv(c.code)
28-
return add_labels!(map(1:length(ixs)) do i
29-
i <= nv(c.graph) ? coloringv(T, K) .^ get_weights(c, i) : coloringb(x, K)
30-
end, ixs, labels(c))
31+
return vcat(add_labels!([coloringv(T, K) for i=1:nv(c.graph)], ixs[1:nv(c.graph)], labels(c)), [coloringb(x, K) .^ get_weights(c, i) for i=1:ne(c.graph)])
3132
end
3233

3334
# coloring bond tensor

src/networks/DominatingSet.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
optimizer=GreedyMethod(), simplifier=nothing)
55
66
The [dominating set](https://psychic-meme-f4d866f8.pages.github.io/dev/tutorials/DominatingSet.html) problem.
7-
In the constructor, `weights` are the weights of vertices.
7+
In the constructor, `weights` are associated with vertices.
88
`optimizer` and `simplifier` are for tensor network optimization, check [`optimize_code`](@ref) for details.
99
"""
1010
struct DominatingSet{CT<:AbstractEinsum,WT<:Union{NoWeight, Vector}} <: GraphProblem

src/networks/Matching.jl

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
"""
2-
Matching{CT<:AbstractEinsum} <: GraphProblem
3-
Matching(graph; openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
2+
Matching{CT<:AbstractEinsum, WT<:Union{NoWeight,Vector}} <: GraphProblem
3+
Matching(graph; weights=NoWeight(), openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
44
55
The [Vertex matching](https://psychic-meme-f4d866f8.pages.github.io/dev/tutorials/Matching.html) problem.
6+
`weights` has one to one correspondence with `edges(graph)`.
67
`optimizer` and `simplifier` are for tensor network optimization, check [`optimize_code`](@ref) for details.
78
"""
8-
struct Matching{CT<:AbstractEinsum} <: GraphProblem
9+
struct Matching{CT<:AbstractEinsum, WT<:Union{NoWeight,Vector}} <: GraphProblem
910
code::CT
1011
graph::SimpleGraph{Int}
12+
weights::WT
1113
end
1214

13-
function Matching(g::SimpleGraph; openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
15+
function Matching(g::SimpleGraph; weights=NoWeight(), openvertices=(), optimizer=GreedyMethod(), simplifier=nothing)
16+
@assert weights isa NoWeight || length(weights) == ne(g)
1417
edges = [minmax(e.src,e.dst) for e in Graphs.edges(g)]
1518
rawcode = EinCode(vcat([[s] for s in edges], # labels for edge tensors
1619
[[minmax(i,j) for j in neighbors(g, i)] for i in Graphs.vertices(g)]),
1720
collect(Tuple{Int,Int}, openvertices))
18-
Matching(_optimize_code(rawcode, uniformsize(rawcode, 2), optimizer, simplifier), g)
21+
Matching(_optimize_code(rawcode, uniformsize(rawcode, 2), optimizer, simplifier), g, weights)
1922
end
2023

2124
flavors(::Type{<:Matching}) = [0, 1]
22-
get_weights(::Matching, i::Int) = [0, 1]
25+
get_weights(m::Matching, i::Int) = [0, m.weights[i]]
2326
terms(gp::Matching) = getixsv(gp.code)[1:ne(gp.graph)]
2427
labels(gp::Matching) = getindex.(terms(gp))
2528

@@ -50,3 +53,28 @@ function match_tensor(::Type{T}, n::Int) where T
5053
return t
5154
end
5255

56+
"""
57+
is_matching(graph::SimpleGraph, config)
58+
59+
Returns true if `config` is a valid matching on `graph`, and `false` if a vertex is double matched.
60+
`config` is a vector of boolean variables, which has one to one correspondence with `edges(graph)`.
61+
"""
62+
function is_matching(g::SimpleGraph, config)
63+
@assert ne(g) == length(config)
64+
edges_mask = zeros(Bool, nv(g))
65+
for (e, c) in zip(edges(g), config)
66+
if !iszero(c)
67+
if edges_mask[e.src]
68+
@debug "Vertex $(e.src) is double matched!"
69+
return false
70+
end
71+
if edges_mask[e.dst]
72+
@debug "Vertex $(e.dst) is double matched!"
73+
return false
74+
end
75+
edges_mask[e.src] = true
76+
edges_mask[e.dst] = true
77+
end
78+
end
79+
return true
80+
end

src/networks/Satisfiability.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ function Base.show(io::IO, c::CNF)
5757
print(io, join(["($k)" for k in c.clauses], ""))
5858
end
5959
Base.:(==)(x::CNF, y::CNF) = x.clauses == y.clauses
60+
Base.length(x::CNF) = length(x.clauses)
6061

6162
"""
6263
¬(var::BoolVar)
@@ -106,26 +107,28 @@ macro bools(syms::Symbol...)
106107
end
107108

108109
"""
109-
Satisfiability{CT<:AbstractEinsum,WT<:Union{NoWeight, Vector}} <: GraphProblem
110-
Satisfiability(cnf::CNF; openvertices=(),
110+
Satisfiability{CT<:AbstractEinsum,T,WT<:Union{NoWeight, Vector}} <: GraphProblem
111+
Satisfiability(cnf::CNF; weights=NoWeight(), openvertices=(),
111112
optimizer=GreedyMethod(), simplifier=nothing)
112113
113114
The [satisfiability](https://psychic-meme-f4d866f8.pages.github.io/dev/tutorials/Satisfiability.html) problem.
114115
In the constructor, `cnf` is a logical expresion in conjunctive normal form ([`CNF`](@ref)) for the satisfiability problems.
116+
`weights` are associated with clauses.
115117
`optimizer` and `simplifier` are for tensor network optimization, check [`optimize_code`](@ref) for details.
116118
"""
117-
struct Satisfiability{CT<:AbstractEinsum,T} <: GraphProblem
119+
struct Satisfiability{CT<:AbstractEinsum,T,WT<:Union{NoWeight, Vector}} <: GraphProblem
118120
code::CT
119121
cnf::CNF{T}
122+
weights::WT
120123
end
121124

122-
function Satisfiability(cnf::CNF{T}; openvertices=(), optimizer=GreedyMethod(), simplifier=nothing) where T
125+
function Satisfiability(cnf::CNF{T}; weights=NoWeight(), openvertices=(), optimizer=GreedyMethod(), simplifier=nothing) where T
123126
rawcode = EinCode([[getfield.(c.vars, :name)...] for c in cnf.clauses], collect(T, openvertices))
124-
Satisfiability(_optimize_code(rawcode, uniformsize(rawcode, 2), optimizer, simplifier), cnf)
127+
Satisfiability(_optimize_code(rawcode, uniformsize(rawcode, 2), optimizer, simplifier), cnf, weights)
125128
end
126129

127130
flavors(::Type{<:Satisfiability}) = [0, 1] # false, true
128-
get_weights(::Satisfiability, sym) = [0, 1]
131+
get_weights(s::Satisfiability, i::Int) = [0, s.weights[i]]
129132
terms(gp::Satisfiability) = getixsv(gp.code)
130133
labels(gp::Satisfiability) = unique!(vcat(getixsv(gp.code)...))
131134

test/networks/Coloring.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ using Test, GraphTensorNetworks, Graphs
1818
@test is_good_vertex_coloring(g, c.c.data)
1919
end
2020

21+
22+
@testset "weighted coloring" begin
23+
g = smallgraph(:petersen)
24+
problem = Coloring{3}(g; weights=fill(2, 15))
25+
@test solve(problem, SizeMax())[].n == 30
26+
res = solve(problem, SingleConfigMax())[].c.data
27+
@test is_good_vertex_coloring(g, res)
28+
end

test/networks/Matching.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,13 @@ end
1616
@test graph_polynomial(Matching(g), Val(:polynomial))[] == Polynomial([1,7,13,5])
1717
g = smallgraph(:petersen)
1818
@test graph_polynomial(Matching(g), Val(:polynomial))[].coeffs == [6, 90, 145, 75, 15, 1][end:-1:1]
19+
end
20+
21+
@testset "weighted matching" begin
22+
g = smallgraph(:petersen)
23+
problem = Matching(g; weights=fill(2, 15))
24+
@test solve(problem, SizeMax())[].n == 10
25+
res = solve(problem, SingleConfigMax())[].c.data
26+
@test is_matching(g, res)
27+
@test count_ones(res) * 2 == 10
1928
end

test/networks/Satisfiability.jl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ using GraphTensorNetworks
2323
@test !satisfiable(cnf, Dict(:x=>false, :y=>true, :z=>true, :a=>false, :b=>false, :c=>true))
2424
end
2525

26-
@testset "enumerating - max cut" begin
26+
@testset "enumeration - sat" begin
2727
@bools x y z a b c
2828
c1 = x ¬y
2929
c2 = c (¬a b)
@@ -44,3 +44,24 @@ end
4444
end
4545
end
4646

47+
@testset "weighted cnf" begin
48+
@bools x y z a b c
49+
c1 = x ¬y
50+
c2 = c (¬a b)
51+
c3 = (z ¬a) y
52+
c4 = (c z) ¬b
53+
cnf = (c1 c4) (c2 c3)
54+
gp = Satisfiability(cnf; weights=fill(2, length(cnf)))
55+
56+
@test solve(gp, SizeMax())[].n == 8.0
57+
res = best_solutions(gp; all=true)[].c.data
58+
for i=0:1<<6-1
59+
v = StaticBitVector(Bool[i>>(k-1) & 1 for k=1:6])
60+
if v res
61+
@test satisfiable(gp.cnf, Dict(zip(labels(gp), v)))
62+
else
63+
@test !satisfiable(gp.cnf, Dict(zip(labels(gp), v)))
64+
end
65+
end
66+
end
67+

0 commit comments

Comments
 (0)