Skip to content

Commit a324b54

Browse files
contra-bitLiam
andauthored
Plotting for ZXDiagrams and ZXGraphs, Equality for ZXDiagrams and converting ZX to ZXW (#102)
* Vega and Compose Plotting and Tutorial * fix ploting when there are no gates replace index based access with get and a default value * test ploting for all existing ZXDiagrams * Add Multigraph ZXDiagram to tutorial.jl * add research notebook * convert plot_vega into an extension * fix src and dst bugs * add plots for all ZX test * integrate equality * fix id match and rewrite rule * cvd accesible colors for plot * better plot ux * ZXW from IR import * fix ir tests by shadowing instrinsic operations * cleanup repo * update notebooks * set default indentation and margin * apply default indent of 4 * use upstream packages * indent gates_to_circ function * test plot for ZXGraph * use upstream packages in notebooks * creat test for BlockIR -> ZXWDiagram -> Matrix * correct names of Pkgs * readd phase test with CodeIR * improve testcoverage * add more docstrings * use builtin pluto env * remove formater * update of Pkg * correct us of isnothing * use pluto env * fix if expression for id rule * Minor Notebook improvements * remove Documentation.yml * fix indentation again --------- Co-authored-by: liam <[email protected]> Co-authored-by: Liam <[email protected]>
1 parent 146e39b commit a324b54

30 files changed

+4166
-296
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/docs/src/assets/indigo.css
99
/docs/Manifest.toml
1010
.vscode
11+
.JuliaFormatter.toml

Project.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1414
YaoHIR = "6769671a-fce8-4286-b3f7-6099e1b1298a"
1515
YaoLocations = "66df03fb-d475-48f7-b449-3d9064bf085b"
1616

17+
[weakdeps]
18+
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
19+
Vega = "239c3e63-733f-47ad-beb7-a12fde22c578"
20+
21+
[extensions]
22+
ZXCalculusExt = ["Vega", "DataFrames"]
23+
1724
[compat]
1825
Expronicon = "0.10.3"
1926
Graphs = "1"
@@ -22,11 +29,12 @@ Multigraphs = "0.3"
2229
OMEinsum = "0.7, 0.8"
2330
YaoHIR = "0.2"
2431
YaoLocations = "0.1"
25-
julia = "1.9"
32+
julia = ">= 1.9"
2633

2734
[extras]
2835
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
2936
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
37+
Vega = "239c3e63-733f-47ad-beb7-a12fde22c578"
3038

3139
[targets]
32-
test = ["Test", "Documenter"]
40+
test = ["Test", "Documenter", "Vega", "DataFrames"]

ext/ZXCalculusExt.jl

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
module ZXCalculusExt
2+
3+
using Graphs
4+
import Graphs: AbstractEdge, src, dst
5+
using Vega, DataFrames
6+
using ZXCalculus, ZXCalculus.ZX
7+
using ZXCalculus: ZX
8+
9+
function spider_type_string(st1)
10+
st1 == SpiderType.X && return "X"
11+
st1 == SpiderType.Z && return "Z"
12+
st1 == SpiderType.H && return "H"
13+
st1 == SpiderType.Out && return "Out"
14+
st1 == SpiderType.In && return "In"
15+
end
16+
17+
function generate_d_spiders(vs, st, ps, x_locs_normal, y_locs_normal)
18+
return DataFrame(
19+
id = [v for v in vs],
20+
x = [get(x_locs_normal, v, nothing) for v in vs],
21+
y = [get(y_locs_normal, v, nothing) for v in vs],
22+
spider_type = [spider_type_string(st[v]) for v in vs],
23+
phase = [iszero(ps[v]) ? "" : "$(ps[v])" for v in vs],
24+
)
25+
end
26+
27+
function generate_d_edges(zxd::ZXDiagram)
28+
s = Int[]
29+
d = Int[]
30+
isH = Bool[]
31+
for e in ZXCalculus.ZX.edges(zxd.mg)
32+
push!(s, src(e))
33+
push!(d, dst(e))
34+
push!(isH, false)
35+
end
36+
return DataFrame(src = s, dst = d, isHadamard = isH)
37+
end
38+
function generate_d_edges(zxd::ZXGraph)
39+
s = Int[]
40+
d = Int[]
41+
isH = Bool[]
42+
for e in ZXCalculus.ZX.edges(zxd.mg)
43+
push!(s, src(e))
44+
push!(d, dst(e))
45+
push!(isH, ZXCalculus.ZX.is_hadamard(zxd, src(e), dst(e)))
46+
end
47+
return DataFrame(src = s, dst = d, isHadamard = isH)
48+
end
49+
50+
function ZXCalculus.ZX.plot(zxd::Union{ZXDiagram,ZXGraph}; kwargs...)
51+
scale = 2
52+
lattice_unit = 50 * scale
53+
zxd = copy(zxd)
54+
ZXCalculus.ZX.generate_layout!(zxd)
55+
vs = spiders(zxd)
56+
x_locs = zxd.layout.spider_col
57+
x_min = minimum(values(x_locs), init = 0)
58+
x_max = maximum(values(x_locs), init = 1)
59+
x_range = (x_max - x_min) * lattice_unit
60+
y_locs = zxd.layout.spider_q
61+
y_min = minimum(values(y_locs), init = 0)
62+
y_max = maximum(values(y_locs), init = 1)
63+
y_range = (y_max - y_min) * lattice_unit
64+
x_locs_normal = copy(x_locs)
65+
for (k, v) in x_locs_normal
66+
x_locs_normal[k] = v * lattice_unit
67+
end
68+
y_locs_normal = copy(y_locs)
69+
for (k, v) in y_locs_normal
70+
y_locs_normal[k] = v * lattice_unit
71+
end
72+
73+
st = zxd.st
74+
ps = zxd.ps
75+
76+
d_spiders = generate_d_spiders(vs, st, ps, x_locs_normal, y_locs_normal)
77+
d_edges = generate_d_edges(zxd)
78+
79+
spec = @vgplot(
80+
$schema = "https://vega.github.io/schema/vega/v5.json",
81+
height = y_range,
82+
width = x_range,
83+
padding = 0.5 * lattice_unit,
84+
marks = [
85+
{
86+
encode = {
87+
update = {strokeWidth = {signal = "edgeWidth"}, path = {field = "path"}},
88+
enter = {stroke = {field = "color"}},
89+
},
90+
from = {data = "edges"},
91+
type = "path",
92+
},
93+
{
94+
encode = {
95+
update = {
96+
stroke = {value = "black"},
97+
x = {field = "x"},
98+
strokeWidth = {signal = "strokeWidth"},
99+
size = {signal = "spiderSize"},
100+
y = {field = "y"},
101+
},
102+
enter = {shape = {field = "shape"}, fill = {field = "color"}},
103+
},
104+
from = {data = "spiders"},
105+
type = "symbol",
106+
},
107+
{
108+
encode = {
109+
update = {
110+
align = {value = "center"},
111+
x = {field = "x"},
112+
ne = {value = "top"},
113+
opacity = {signal = "showIds"},
114+
y = {field = "y"},
115+
fontSize = {value = 6 * lattice_unit / 50},
116+
dy = {value = 18 * lattice_unit / 50},
117+
},
118+
enter = {fill = {value = "lightgray"}, text = {field = "id"}},
119+
},
120+
from = {data = "spiders"},
121+
type = "text",
122+
},
123+
{
124+
encode = {
125+
update = {
126+
align = {value = "center"},
127+
x = {field = "x"},
128+
dy = {value = lattice_unit / 50},
129+
baseline = {value = "middle"},
130+
opacity = {signal = "showPhases"},
131+
fontSize = {value = 6 * lattice_unit / 50},
132+
y = {field = "y"},
133+
},
134+
enter = {fill = {value = "black"}, text = {field = "phase"}},
135+
},
136+
from = {data = "spiders"},
137+
type = "text",
138+
},
139+
],
140+
data = [
141+
{
142+
name = "spiders",
143+
values = d_spiders,
144+
on = [{
145+
modify = "whichSymbol",
146+
values = "newLoc && {x: newLoc.x, y: newLoc.y}",
147+
trigger = "newLoc",
148+
}],
149+
transform = [
150+
{
151+
as = "shape",
152+
expr = "datum.spider_type === 'Z' ? 'circle' : (datum.spider_type === 'X' ? 'circle' : (datum.spider_type === 'H' ? 'square' : 'circle'))",
153+
type = "formula",
154+
},
155+
{
156+
as = "color",
157+
expr = "datum.spider_type === 'Z' ? '#D8F8D8' : (datum.spider_type === 'X' ? '#E8A5A5' : (datum.spider_type === 'H' ? 'yellow' : '#9558B2'))",
158+
type = "formula",
159+
},
160+
],
161+
},
162+
{
163+
name = "edges",
164+
values = d_edges,
165+
transform = [
166+
{
167+
key = "id",
168+
fields = ["src", "dst"],
169+
as = ["source", "target"],
170+
from = "spiders",
171+
type = "lookup",
172+
},
173+
{
174+
targetX = "target.x",
175+
shape = {signal = "shape"},
176+
sourceX = "source.x",
177+
targetY = "target.y",
178+
type = "linkpath",
179+
sourceY = "source.y",
180+
orient = {signal = "orient"},
181+
},
182+
{
183+
as = "color",
184+
expr = "datum.isHadamard ? '#4063D8' : 'black'",
185+
type = "formula",
186+
},
187+
],
188+
},
189+
],
190+
signals = [
191+
{name = "showIds", bind = {input = "checkbox"}, value = true},
192+
{name = "showPhases", bind = {input = "checkbox"}, value = true},
193+
{
194+
name = "spiderSize",
195+
bind = {
196+
step = lattice_unit / 5,
197+
max = 40 * lattice_unit,
198+
min = 2 * lattice_unit,
199+
input = "range",
200+
},
201+
value = 20 * lattice_unit,
202+
},
203+
{
204+
name = "strokeWidth",
205+
bind = {
206+
step = 0.001 * lattice_unit,
207+
max = 3 * lattice_unit / 50,
208+
min = 0,
209+
input = "range",
210+
},
211+
value = 1.5 * lattice_unit / 50,
212+
},
213+
{
214+
name = "edgeWidth",
215+
bind = {
216+
step = 0.001 * lattice_unit,
217+
max = 3 * lattice_unit / 50,
218+
min = 0.002 * lattice_unit,
219+
input = "range",
220+
},
221+
value = 1.5 * lattice_unit / 50,
222+
},
223+
{
224+
name = "orient",
225+
bind = {options = ["horizontal", "vertical"], input = "select"},
226+
value = "horizontal",
227+
},
228+
{
229+
name = "shape",
230+
bind = {
231+
options = ["line", "arc", "curve", "diagonal", "orthogonal"],
232+
input = "select",
233+
},
234+
value = "diagonal",
235+
},
236+
{
237+
name = "whichSymbol",
238+
on = [
239+
{events = "symbol:mousedown", update = "datum"},
240+
{events = "*:mouseup", update = "{}"},
241+
],
242+
value = {},
243+
},
244+
{
245+
name = "newLoc",
246+
on = [
247+
{events = "symbol:mouseout[!event.buttons], window:mouseup", update = "false"},
248+
{events = "symbol:mouseover", update = "{x: x(), y: y()}"},
249+
{
250+
events = "[symbol:mousedown, window:mouseup] > window:mousemove!",
251+
update = "{x: x(), y: y()}",
252+
},
253+
],
254+
value = false,
255+
},
256+
]
257+
)
258+
return spec
259+
end
260+
261+
262+
263+
264+
265+
266+
end

0 commit comments

Comments
 (0)