Skip to content

Commit bfdbca9

Browse files
committed
update viz
1 parent 2c2f002 commit bfdbca9

File tree

5 files changed

+209
-95
lines changed

5 files changed

+209
-95
lines changed

Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ version = "0.1.5"
55

66
[deps]
77
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
8+
Cairo = "159f3aea-2a34-519c-b102-8c37f9878175"
89
Compose = "a81c6b42-2e10-5240-aca2-a61377ecd94b"
910
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
1011
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
@@ -34,12 +35,13 @@ Requires = "1"
3435
SIMDTypes = "0.1"
3536
TropicalNumbers = "0.4, 0.5"
3637
Viznet = "0.3"
38+
Cairo = "1.0"
3739
julia = "1"
3840

3941
[extras]
40-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
41-
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
4242
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
43+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
44+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
4345

4446
[targets]
4547
test = ["Test", "Documenter", "Random"]

examples/IndependentSet/main.jl

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,65 @@
22

33
# ## Problem definition
44

5-
# Please check the docstring of [`Independence`](@ref).
6-
7-
# ## Solving properties
5+
# Please check the docstring of [`Independence`](@ref) for the definition of independence problem.
6+
# In the following, we are going to defined an independent set problem for the Petersen graph.
87

98
using GraphTensorNetworks, Graphs
109

1110
graph = Graphs.smallgraph(:petersen)
1211

12+
# We can visualize this graph using the following function
13+
rot15(a, b, i::Int) = cos(2i*π/5)*a + sin(2i*π/5)*b, cos(2i*π/5)*b - sin(2i*π/5)*a
14+
15+
locations = [[rot15(0.0, 1.0, i) for i=0:4]..., [rot15(0.0, 0.6, i) for i=0:4]...]
16+
17+
show_graph(graph; locs=locations)
18+
19+
# Let us contruct the problem instance with optimized tensor network contraction order as bellow.
1320
problem = Independence(graph; optimizer=TreeSA(sc_weight=1.0, ntrials=10,
1421
βs=0.01:0.1:15.0, niters=20, rw_weight=0.2));
1522

16-
# maximum independent set size
23+
24+
# ## Solving properties
25+
26+
# ### The decision problem
27+
# ##### maximum independent set size ``\alpha(G)``
1728
maximum_independent_set_size = solve(problem, SizeMax())
1829

19-
# all independent sets
30+
# ### Counting properties
31+
# ##### counting all independent sets
2032
count_all_independent_sets = solve(problem, CountingAll())
2133

22-
# counting independent sets of max two sizes
34+
# ##### counting independent sets with sizes ``\alpha(G)`` and ``\alpha(G)-1``
2335
count_max2_independent_sets = solve(problem, CountingMax(2))
2436

25-
# compute the independence polynomial
37+
# ##### computing the independence polynomial
38+
# For the definition of independence polynomial, please check the docstring of [`Independence`](@ref) or this [wiki page](https://mathworld.wolfram.com/IndependencePolynomial.html).
2639
independence_polynomial = solve(problem, GraphPolynomial(; method=:finitefield))
2740

28-
# find one MIS
29-
max_config = solve(problem, SingleConfigMax(; bounded=false))
41+
# ### Configuration properties
42+
# ##### finding one maximum independent set (MIS)
43+
max_config = solve(problem, SingleConfigMax(; bounded=false))[]
44+
45+
# The return value contains a bit string, and one should read this bit string from left to right.
46+
# Having value 1 at i-th bit means vertex ``i`` is in the maximum independent set.
47+
# One can visualize this MIS with the following function.
48+
show_graph(graph; locs=locations, colors=[iszero(max_config.c.data[i]) ? "white" : "red"
49+
for i=1:nv(graph)])
50+
51+
# ##### enumeration of all MISs
52+
all_max_configs = solve(problem, ConfigsMax(; bounded=true))[]
53+
54+
using Compose
55+
56+
m = length(all_max_configs.c)
57+
58+
imgs = ntuple(k->(context((k-1)/m, 0.0, 1.2/m, 1.0), show_graph(graph;
59+
locs=locations, scale=0.25,
60+
colors=[iszero(all_max_configs.c[k][i]) ? "white" : "red"
61+
for i=1:nv(graph)])), m)
3062

31-
# enumerate all MISs
32-
all_max_configs = solve(problem, ConfigsMax(; bounded=true))
63+
Compose.set_default_graphic_size(18cm, 4cm); Compose.compose(context(), imgs...)
3364

34-
# enumerate all IS configurations
35-
all_independent_sets = solve(problem, ConfigsAll())
65+
# ##### enumeration of all IS configurations
66+
all_independent_sets = solve(problem, ConfigsAll())[]

src/GraphTensorNetworks.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export mis_compactify!
3838
export save_configs, load_configs
3939

4040
# Visualization
41-
export vizeinsum, vizconfig
41+
export show_graph
4242

4343
project_relative_path(xs...) = normpath(joinpath(dirname(dirname(pathof(@__MODULE__))), xs...))
4444

@@ -50,7 +50,7 @@ include("graph_polynomials.jl")
5050
include("configurations.jl")
5151
include("graphs.jl")
5252
include("bounding.jl")
53-
include("viz.jl")
53+
include("visualize.jl")
5454
include("interfaces.jl")
5555

5656
using Requires

src/visualize.jl

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
using Compose, Viznet, Cairo
2+
3+
struct Rescaler{T}
4+
xmin::T
5+
xmax::T
6+
ymin::T
7+
ymax::T
8+
pad::T
9+
end
10+
11+
getscale(r::Rescaler) = min(1/(r.xmax-r.xmin+2*r.pad), 1/(r.ymax-r.ymin+2*r.pad))
12+
13+
function config_plotting(sites)
14+
n = length(sites)
15+
if n <= 1
16+
return (1.0, 0.5, 0.4, 1.0)
17+
end
18+
shortest_distance = Inf
19+
for i=1:n
20+
for j=i+1:n
21+
shortest_distance = min(sqrt(sum(abs2, sites[i] .- sites[j])), shortest_distance)
22+
end
23+
end
24+
25+
rescaler = get_rescaler(sites, 0.0)
26+
xpad = (rescaler.xmax - rescaler.xmin) * 0.2 + shortest_distance
27+
ypad = (rescaler.ymax - rescaler.ymin) * 0.2 + shortest_distance
28+
pad = max(xpad, ypad)
29+
scale = shortest_distance
30+
return (pad=pad, scale=scale)
31+
end
32+
33+
function (r::Rescaler{T})(x; dims=(1,2)) where T
34+
xmin, ymin, xmax, ymax, pad = r.xmin, r.ymin, r.xmax, r.ymax, r.pad
35+
scale = getscale(r)
36+
if dims == (1,2)
37+
return (x[1]-xmin+pad, ymax+pad-x[2]) .* scale
38+
elseif dims == 1
39+
return (x - xmin + pad) * scale
40+
elseif dims == 2
41+
return (ymax + pad - x) * scale
42+
else
43+
throw(ArgumentError("dims should be (1,2), 1 or 2."))
44+
end
45+
end
46+
47+
function get_rescaler(locs::AbstractVector{<:Tuple}, pad)
48+
xmin = minimum(x->x[1], locs)
49+
ymin = minimum(x->x[2], locs)
50+
xmax = maximum(x->x[1], locs)
51+
ymax = maximum(x->x[2], locs)
52+
return Rescaler(promote(xmin, xmax, ymin, ymax, pad)...)
53+
end
54+
55+
default_node_style(scale, stroke_color, fill_color) = compose(context(), Viznet.nodestyle(:default, r=0.15cm*scale), Compose.stroke(stroke_color), fill(fill_color), linewidth(0.3mm*scale))
56+
default_text_style(scale, color) = Viznet.textstyle(:default, fontsize(4pt*scale), fill(color))
57+
default_bond_style(scale, color) = Viznet.bondstyle(:default, Compose.stroke(color), linewidth(0.3mm*scale))
58+
59+
"""
60+
show_graph(locations, edges;
61+
colors=["black", "black", ...],
62+
texts=["1", "2", ...],
63+
format=SVG,
64+
bond_color="black",
65+
)
66+
67+
Plots vertices at `locations` with colors specified by `colors` and texts specified by `texts`.
68+
You will need a `VSCode`, `Pluto` notebook or `Jupyter` notebook to show the image.
69+
If you want to write this image to the disk without displaying it in a frontend, please try
70+
71+
```julia
72+
julia> open("test.png", "w") do f
73+
viz_atoms(f, generate_sites(SquareLattice(), 5, 5))
74+
end
75+
```
76+
77+
The `format` keyword argument can also be `Compose.SVG` or `Compose.PDF`.
78+
"""
79+
function show_graph(locations, edges;
80+
colors=nothing,
81+
texts = nothing,
82+
format=SVG, io=nothing,
83+
kwargs...)
84+
if length(locations) == 0
85+
dx, dy = 12cm, 12cm
86+
img = Compose.compose(context())
87+
else
88+
img, (dx, dy) = viz_atoms(locations, edges; colors=colors, texts=texts, config=GraphDisplayConfig(; config_plotting(locations)..., kwargs...))
89+
end
90+
if io === nothing
91+
Compose.set_default_graphic_size(dx, dy)
92+
return img
93+
else
94+
return format(io, dx, dy)(img)
95+
end
96+
end
97+
function show_graph(graph::SimpleGraph; locs, kwargs...)
98+
show_graph(locs, [(e.src, e.dst) for e in edges(graph)]; kwargs...)
99+
end
100+
101+
function fit_image(rescaler::Rescaler, image_size, imgs...)
102+
X = rescaler.xmax - rescaler.xmin + 2*rescaler.pad
103+
Y = rescaler.ymax - rescaler.ymin + 2*rescaler.pad
104+
img_rescale = image_size/max(X, Y)*cm
105+
if Y < X
106+
return Compose.compose(context(0, 0, 1.0, X/Y), imgs...), (X*img_rescale, Y*img_rescale)
107+
else
108+
return Compose.compose(context(0, 0, Y/X, 1.0), imgs...), (X*img_rescale, Y*img_rescale)
109+
end
110+
end
111+
112+
# Returns a 2-tuple of (image::Context, size)
113+
function viz_atoms(locs, edges; colors, texts, config)
114+
rescaler = get_rescaler(locs, config.pad)
115+
img = _viz_atoms(rescaler.(locs), edges, colors, texts, config, getscale(rescaler))
116+
return fit_image(rescaler, config.image_size, img)
117+
end
118+
119+
Base.@kwdef struct GraphDisplayConfig
120+
# line, node and text
121+
scale::Float64 = 1.0
122+
pad::Float64 = 1.5
123+
124+
# node
125+
node_text_color::String = "black"
126+
node_stroke_color = "black"
127+
node_fill_color = "white"
128+
# bond
129+
bond_color::String = "black"
130+
# image size in cm
131+
image_size::Float64 = 12
132+
end
133+
134+
function _viz_atoms(locs, edges, colors, texts, config, rescale)
135+
rescale = rescale * config.image_size * config.scale * 1.6
136+
if colors !== nothing
137+
@assert length(locs) == length(colors)
138+
node_styles = [default_node_style(rescale, config.node_stroke_color, color) for color in colors]
139+
else
140+
node_styles = fill(default_node_style(rescale, config.node_stroke_color, config.node_fill_color), length(locs))
141+
end
142+
if texts !== nothing
143+
@assert length(locs) == length(texts)
144+
end
145+
edge_style = default_bond_style(rescale, config.bond_color)
146+
text_style = default_text_style(rescale, config.node_text_color)
147+
img1 = Viznet.canvas() do
148+
for (i, node) in enumerate(locs)
149+
node_styles[i] >> node
150+
if config.node_text_color !== "transparent"
151+
text_style >> (node, texts === nothing ? "$i" : texts[i])
152+
end
153+
end
154+
for (i, j) in edges
155+
edge_style >> (locs[i], locs[j])
156+
end
157+
end
158+
Compose.compose(context(), img1)
159+
end

src/viz.jl

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)