Skip to content

Commit 3199dcc

Browse files
authored
polish docs of paintshop, coloring and matching (#13)
* new paintshop problem * save * update paint shop doc * update * update * update * fix docs * fix docs * fix one doc
1 parent 5346fc8 commit 3199dcc

29 files changed

+448
-113
lines changed

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ makedocs(;
2323
repo="https://github.com/Happy-Diode/GraphTensorNetworks.jl/blob/{commit}{path}#{line}",
2424
sitename="GraphTensorNetworks.jl",
2525
format=Documenter.HTML(;
26-
prettyurls=false,
26+
prettyurls=get(ENV, "CI", "false") == "true",
2727
canonical="https://Happy-Diode.github.io/GraphTensorNetworks.jl",
2828
assets=String[indigo],
2929
),

docs/src/ref.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ mis_compactify!
3535
3636
cut_size
3737
cut_assign
38+
39+
num_paint_shop_color_switch
40+
paint_shop_coloring_from_config
41+
42+
is_good_vertex_coloring
3843
```
3944

4045
## Properties
@@ -90,10 +95,12 @@ MergeGreedy
9095
#### Graph
9196
```@docs
9297
show_graph
98+
spring_layout
9399
94100
diagonal_coupled_graph
95101
square_lattice_graph
96102
unit_disk_graph
103+
line_graph
97104
98105
random_diagonal_coupled_graph
99106
random_square_lattice_graph

examples/Coloring.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,27 @@ show_graph(graph; locs=locations)
4747
# We construct the tensor network for the 3-coloring problem as
4848
problem = Coloring{3}(graph);
4949

50-
# ## Solving properties
50+
# ## Solving properties
51+
# ##### counting all possible coloring
52+
num_of_coloring = solve(problem, CountingAll())[]
53+
54+
# ##### finding one best coloring
55+
single_solution = solve(problem, SingleConfigMax())[]
56+
57+
is_good_vertex_coloring(graph, single_solution.c.data)
58+
59+
vertex_color_map = Dict(0=>"red", 1=>"green", 2=>"blue")
60+
61+
show_graph(graph; locs=locations, vertex_colors=[vertex_color_map[Int(c)] for c in single_solution.c.data])
62+
63+
# Let us try to solve the same issue on its line graph, a graph that generated by mapping an edge to a vertex and two edges sharing a common vertex will be connected.
64+
linegraph = line_graph(graph)
65+
66+
show_graph(linegraph; locs=[0.5 .* (locations[e.src] .+ locations[e.dst]) for e in edges(graph)])
67+
68+
# Let us construct the tensor network and see if there are solutions.
69+
lineproblem = Coloring{3}(linegraph);
70+
71+
num_of_coloring = solve(lineproblem, CountingAll())[]
72+
73+
# You will see a zero printed, meaning no solution for the 3-coloring on edges of a Petersen graph.

examples/IndependentSet.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ max_config = solve(problem, SingleConfigMax(; bounded=false))[]
8989
# The return value contains a bit string, and one should read this bit string from left to right.
9090
# Having value 1 at i-th bit means vertex ``i`` is in the maximum independent set.
9191
# One can visualize this MIS with the following function.
92-
show_graph(graph; locs=locations, colors=[iszero(max_config.c.data[i]) ? "white" : "red"
92+
show_graph(graph; locs=locations, vertex_colors=[iszero(max_config.c.data[i]) ? "white" : "red"
9393
for i=1:nv(graph)])
9494

9595
# ##### enumeration of all MISs
@@ -101,12 +101,12 @@ using Compose
101101

102102
m = length(all_max_configs.c)
103103

104-
imgs = ntuple(k->(context((k-1)/m, 0.0, 1.2/m, 1.0), show_graph(graph;
104+
imgs = ntuple(k->show_graph(graph;
105105
locs=locations, scale=0.25,
106-
colors=[iszero(all_max_configs.c[k][i]) ? "white" : "red"
107-
for i=1:nv(graph)])), m)
106+
vertex_colors=[iszero(all_max_configs.c[k][i]) ? "white" : "red"
107+
for i=1:nv(graph)]), m);
108108

109-
Compose.set_default_graphic_size(18cm, 4cm); Compose.compose(context(), imgs...)
109+
Compose.set_default_graphic_size(18cm, 4cm); Compose.compose(context(), ntuple(k->(context((k-1)/m, 0.0, 1.2/m, 1.0), imgs[k]), m)...)
110110

111111
# ##### enumeration of all IS configurations
112112
all_independent_sets = solve(problem, ConfigsAll())[]
@@ -129,7 +129,7 @@ problem = IndependentSet(graph; weights=collect(1:10))
129129

130130
max_config_weighted = solve(problem, SingleConfigMax())[]
131131

132-
show_graph(graph; locs=locations, colors=
132+
show_graph(graph; locs=locations, vertex_colors=
133133
[iszero(max_config_weighted.c.data[i]) ? "white" : "red" for i=1:nv(graph)])
134134

135135
# The following code computes the MIS tropical tensor (reference to be added) with open vertices 1 and 2.

examples/Matching.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,25 @@ show_graph(graph; locs=locations)
4848
problem = Matching(graph);
4949

5050
# ## Solving properties
51+
# ### Maximum matching
52+
# ### Configuration properties
53+
max_matching = solve(problem, SizeMax())[]
54+
# The largest number of matching is 5, which means we have a perfect matching (vertices are all paired).
55+
56+
# ##### matching polynomial
5157
# The graph polynomial defined for the independence problem is known as the matching polynomial.
5258
# Here, we adopt the first definition in the [wiki page](https://en.wikipedia.org/wiki/Matching_polynomial).
5359
# ```math
5460
# M(G, x) = \sum\limits_{k=1}^{|V|/2} c_k x^k,
5561
# ```
56-
# where ``k`` is the number of matches, and coefficients ``c_k`` are the corresponding counting.
62+
# where ``k`` is the number of matches, and coefficients ``c_k`` are the corresponding counting.
63+
64+
matching_poly = solve(problem, GraphPolynomial())[]
65+
66+
# ## Configuration properties
67+
68+
# ##### one of the perfect matches
69+
match_config = solve(problem, SingleConfigMax())[]
70+
71+
# Let us show the result by coloring the matched edges to red
72+
show_graph(graph; locs=locations, edge_colors=[isone(match_config.c.data[i]) ? "red" : "black" for i=1:ne(graph)])

examples/MaxCut.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ max_cut_size_verify = cut_size(graph, max_vertex_config)
7171

7272
# You should see a consistent result as above `max_cut_size`.
7373

74-
show_graph(graph; locs=locations, colors=[
74+
show_graph(graph; locs=locations, vertex_colors=[
7575
iszero(max_vertex_config[i]) ? "white" : "red" for i=1:nv(graph)])

examples/MaximalIS.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# * how to compute weighted graphs and handle open vertices.
1010

1111
# ## Problem definition
12-
using GraphTensorNetworks, Graphs
12+
using GraphTensorNetworks, Graphs, Compose
1313

1414
# In graph theory, a [maximal independent set](https://en.wikipedia.org/wiki/Maximal_independent_set) is an independent set that is not a subset of any other independent set.
1515
# It is different from maximum independent set because it does not require the set to have the max size.
@@ -26,6 +26,7 @@ locations = [[rot15(0.0, 1.0, i) for i=0:4]..., [rot15(0.0, 0.6, i) for i=0:4]..
2626
show_graph(graph; locs=locations)
2727

2828
# ## Tensor network representation
29+
# Type [`MaximalIS`](@ref) can be used for constructing the tensor network with optimized contraction order for solving a maximal independent set problem.
2930
# For a vertex ``v\in V``, we define a boolean degree of freedom ``s_v\in\{0, 1\}``.
3031
# We defined the restriction on its neighbourhood ``N[v]``:
3132
# ```math
@@ -58,9 +59,16 @@ max_config = solve(problem, GraphPolynomial())[]
5859

5960
# ### Configuration properties
6061
# ##### finding all maximal independent set
61-
max_edge_config = solve(problem, ConfigsAll())[]
62+
maximal_configs = solve(problem, ConfigsAll())[]
63+
64+
imgs = ntuple(k->show_graph(graph;
65+
locs=locations, scale=0.25,
66+
vertex_colors=[iszero(maximal_configs[k][i]) ? "white" : "red"
67+
for i=1:nv(graph)]), length(maximal_configs));
68+
69+
Compose.set_default_graphic_size(18cm, 12cm); Compose.compose(context(), ntuple(k->(context((mod1(k,5)-1)/5, ((k-1)÷5)/3, 1.2/5, 1.0/3), imgs[k]), 15)...)
6270

6371
# This result should be consistent with that given by the [Bron Kerbosch algorithm](https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm) on the complement of Petersen graph.
64-
maximal_cliques = maximal_cliques(complement(graph))
72+
cliques = maximal_cliques(complement(graph))
6573

6674
# For sparse graphs, the generic tensor network approach is usually much faster and memory efficient.

examples/PaintShop.jl

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,96 @@
99
# * how to compute weighted graphs and handle open vertices.
1010

1111
# ## Problme Definition
12-
# The [binary paint shop problem](http://m-hikari.com/ams/ams-2012/ams-93-96-2012/popovAMS93-96-2012-2.pdf).
12+
# The [binary paint shop problem](http://m-hikari.com/ams/ams-2012/ams-93-96-2012/popovAMS93-96-2012-2.pdf) is defined as follows:
13+
# we are given a ``2m`` length sequence containing ``m`` cars, where each car appears twice.
14+
# Each car need to be colored red in one occurrence, and blue in the other.
15+
# We need to choose which occurrence for each car to color with which color — the goal is to minimize the number of times we need to change the current color.
1316

14-
# In the following, we are going to defined a binary paint shop problem for the following string
17+
# In the following, we use a character to represent a car,
18+
# and defined a binary paint shop problem as a string that each character appear exactly twice.
1519

1620
using GraphTensorNetworks, Graphs
1721

18-
sequence = "abaccb"
22+
sequence = collect("iadgbeadfcchghebif")
23+
24+
# We can visualize this paint shop problem as a graph
25+
rot(a, b, θ) = cos(θ)*a + sin(θ)*b, cos(θ)*b - sin(θ)*a
26+
27+
locations = [rot(0.0, 1.0, -0.25π - 1.5*π*(i-0.5)/length(sequence)) for i=1:length(sequence)]
28+
29+
graph = path_graph(length(sequence))
30+
for i=1:length(sequence)
31+
j = findlast(==(sequence[i]), sequence)
32+
i != j && add_edge!(graph, i, j)
33+
end
34+
35+
show_graph(graph; locs=locations, texts=string.(sequence), edge_colors=[sequence[e.src] == sequence[e.dst] ? "blue" : "black" for e in edges(graph)])
36+
37+
# Vertices connected by blue edges must have different colors,
38+
# and the goal becomes a min-cut problem defined on black edges.
39+
40+
# ## Tensor network representation
41+
# Type [`PaintShop`](@ref) can be used for constructing the tensor network with optimized contraction order for solving a binary paint shop problem.
42+
# To obtain its tensor network representation, we associating car ``c_i`` (the ``i``-th character in our example) with a degree of freedom ``s_{c_i} \in \{0, 1\}``,
43+
# where we use ``0`` to denote the first appearance of a car is colored red and ``1`` to denote the first appearance of a car is colored blue.
44+
# For each black edges ``(i, i+1)``, we define an edge tensor labeld by ``(s_{c_i}, s_{c_{i+1}})`` as follows:
45+
# If both cars on this edge are their first or second appearance
46+
# ```math
47+
# B^{\rm parallel} = \begin{matrix}
48+
# x & 1 \\
49+
# 1 & x \\
50+
# \end{matrix},
51+
#
52+
# otherwise,
53+
# B^{\rm anti-parallel} = B^{\rm 10} = \begin{matrix}
54+
# 1 & x \\
55+
# x & 1 \\
56+
# \end{matrix}.
57+
# ```
58+
# It can be understood as, when both cars are their first appearance,
59+
# they tend to have the same configuration so that the color is not changed.
60+
# Otherwise, they tend to have different configuration to keep the color unchanged.
61+
62+
# Let us contruct the problem instance as bellow.
63+
problem = PaintShop(sequence);
64+
65+
# ### Counting properties
66+
# ##### maximal independence polynomial
67+
# The graph polynomial defined for the maximal independent set problem is
68+
# ```math
69+
# I_{\rm max}(G, x) = \sum_{k=0}^{\alpha(G)} b_k x^k,
70+
# ```
71+
# where ``b_k`` is the number of maximal independent sets of size ``k`` in graph ``G=(V, E)``.
72+
73+
max_config = solve(problem, GraphPolynomial())[]
74+
75+
# Since it only counts the maximal independent sets, the first several coefficients are 0.
76+
77+
# ### Counting properties
78+
# ##### graph polynomial
79+
# The graph polynomial of the binary paint shop problem in our convension is defined as
80+
# ```math
81+
# D(G, x) = \sum_{k=0}^{\delta(G)} d_k x^k
82+
# ```
83+
# where ``2d_k`` is the number of possible coloring with number of color changes ``2m-1-k``.
84+
paint_polynomial = solve(problem, GraphPolynomial())[]
85+
86+
# ### Configuration properties
87+
# ##### finding best solutions
88+
best_configs = solve(problem, ConfigsMax())[]
89+
90+
painting1 = paint_shop_coloring_from_config(best_configs.c.data[1]; initial=false)
91+
92+
show_graph(graph; locs=locations, texts=string.(sequence), edge_colors=[sequence[e.src] == sequence[e.dst] ? "blue" : "black" for e in edges(graph)],
93+
vertex_colors=[isone(c) ? "red" : "black" for c in painting1], vertex_text_color="white")
94+
95+
#
96+
97+
painting2 = paint_shop_coloring_from_config(best_configs.c.data[2]; initial=false)
98+
99+
show_graph(graph; locs=locations, texts=string.(sequence), edge_colors=[sequence[e.src] == sequence[e.dst] ? "blue" : "black" for e in edges(graph)],
100+
vertex_colors=[isone(c) ? "red" : "black" for c in painting2], vertex_text_color="white")
101+
102+
# Since we have different choices of initial color, the number of best solution is 4.
103+
# The following function will check the solution and return you the number of color switchs
104+
num_paint_shop_color_switch(sequence, painting2)

src/GraphTensorNetworks.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export GreedyMethod, TreeSA, SABipartite, KaHyParBipartite, MergeVectors, MergeG
1515
export StaticBitVector, StaticElementVector, @bv_str
1616
export is_commutative_semiring
1717
export Max2Poly, TruncatedPoly, Polynomial, Tropical, CountingTropical, StaticElementVector, Mod, ConfigEnumerator, onehotv, ConfigSampler
18+
export CountingTropicalF64, CountingTropicalF32, TropicalF64, TropicalF32
1819

1920
# Lower level APIs
2021
export AllConfigs, SingleConfig
@@ -25,11 +26,13 @@ export contractx, contractf, graph_polynomial, max_size, max_size_count
2526
# Graphs
2627
export random_regular_graph, diagonal_coupled_graph, is_independent_set
2728
export square_lattice_graph, unit_disk_graph, random_diagonal_coupled_graph, random_square_lattice_graph
29+
export line_graph
2830

2931
# Tensor Networks (Graph problems)
3032
export GraphProblem, IndependentSet, MaximalIS, Matching, Coloring, optimize_code, set_packing, MaxCut, PaintShop, paintshop_from_pairs, UnWeighted
3133
export flavors, symbols, nflavor, get_weights
32-
export mis_compactify!, cut_assign, cut_size
34+
export mis_compactify!, cut_assign, cut_size, num_paint_shop_color_switch, paint_shop_coloring_from_config
35+
export is_good_vertex_coloring
3336

3437
# Interfaces
3538
export solve, SizeMax, CountingAll, CountingMax, GraphPolynomial, SingleConfigMax, ConfigsAll, ConfigsMax
@@ -38,7 +41,7 @@ export solve, SizeMax, CountingAll, CountingMax, GraphPolynomial, SingleConfigMa
3841
export save_configs, load_configs
3942

4043
# Visualization
41-
export show_graph
44+
export show_graph, spring_layout
4245

4346
project_relative_path(xs...) = normpath(joinpath(dirname(dirname(pathof(@__MODULE__))), xs...))
4447

src/arithematics.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,18 @@ end
220220
Base.:(==)(x::ConfigSampler{N,S,C}, y::ConfigSampler{N,S,C}) where {N,S,C} = x.data == y.data
221221

222222
function Base.:+(x::ConfigSampler{N,S,C}, y::ConfigSampler{N,S,C}) where {N,S,C} # biased sampling: return `x`, maybe using random sampler is better.
223-
return x
223+
return randn() > 0.5 ? x : y
224224
end
225225

226226
function Base.:*(x::ConfigSampler{L,S,C}, y::ConfigSampler{L,S,C}) where {L,S,C}
227227
ConfigSampler(x.data | y.data)
228228
end
229229

230-
Base.zero(::Type{ConfigSampler{N,S,C}}) where {N,S,C} = ConfigSampler{N,S,C}(statictrues(StaticElementVector{N,S,C}))
231-
Base.one(::Type{ConfigSampler{N,S,C}}) where {N,S,C} = ConfigSampler{N,S,C}(staticfalses(StaticElementVector{N,S,C}))
230+
@generated function Base.zero(::Type{ConfigSampler{N,S,C}}) where {N,S,C}
231+
ex = Expr(:call, :(StaticElementVector{$N,$S,$C}), Expr(:tuple, fill(typemax(UInt64), C)...))
232+
:(ConfigSampler{N,S,C}($ex))
233+
end
234+
Base.one(::Type{ConfigSampler{N,S,C}}) where {N,S,C} = ConfigSampler{N,S,C}(zero(StaticElementVector{N,S,C}))
232235
Base.zero(::ConfigSampler{N,S,C}) where {N,S,C} = zero(ConfigSampler{N,S,C})
233236
Base.one(::ConfigSampler{N,S,C}) where {N,S,C} = one(ConfigSampler{N,S,C})
234237

0 commit comments

Comments
 (0)