-
Notifications
You must be signed in to change notification settings - Fork 1
/
routes.jl
executable file
·205 lines (184 loc) · 5.85 KB
/
routes.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
using Genie.Router
using Base64
using Logging
using UUIDs
using HTTP: unescapeuri
using LRUCache
using MacroTools: postwalk
using Mustache
using Quantikz
const whitelist_symbols = [
:P, :H, :Id, :U,
:CNOT, :CPHASE, :SWAP,
:MultiControl, :MultiControlU, :ClassicalDecision,
:Measurement, :ParityMeasurement,
:Noise, :NoiseAll,
:Initialize
]
const MAX_LENGTH = 10000
const CACHE_SIZE = 5000
function eviction(k,v)
@info "$(v).png"
rm("$(v).png")
end
const filecache = LRU{String,UUID}(maxsize=CACHE_SIZE, finalizer=eviction) # TODO consider using hash instead of UUID
# TODO check that evictions always happen: there might be leaks when many cache misses happen at the same time
function parsecircuit(circuitstring)
length(circuitstring) > MAX_LENGTH && return "the circuit string is too long to render on this free service: shorten the circuit or render it by installing Quantikz.jl on your computer"
try
parsed = Meta.parse(strip(circuitstring))
parsed.head ∉ [:vect,:tuple] && return "the provided string does not look like a list (you should use commas for separators and delineate with `[` and `]`)"
all(parsed.args) do x
isa(x, Expr) && x.head == :call # && x.args[1] ∈ whitelist_symbols # skip the whitelist XXX DANGEROUS
end || return """the provided list has to contain only permitted circuit elements: $(join(map(string,whitelist_symbols),", "))"""
all(parsed.args) do x
all(x.args[2:end]) do y
isa(y, String) || (isa(y, Integer) && y<40) || (isa(y, Expr) && y.head == :vect && all(z->isa(z,Integer)&&z<40,y.args))
end
end || return "only Integers smaller than 40, Strings, or lists of Integers may be used as arguments in the construction of a circuit element"
parsed = postwalk(parsed) do x
# isa(x, String) ? replace(x, r"[^a-zA-Z0-9 +\-*/=_^()]"=>"") : x # skip the latex whitelist XXX DANGEROUS
x
end
return parsed
catch e
if isa(e, Meta.ParseError)
return "the provided string contains syntax errors: $(e.msg); $(circuitstring)"
else
return "unknown parsing error, please report a bug: $(e)"
end
end
end
function rendercircuit(warning::String)
return (false, warning)
end
function rendercircuit(circuitast)
try
circuit = eval(circuitast)
circuitstr = string(circuitast)
circuituuid = get!(filecache, circuitstr) do
circuituuid = uuid4()
f = "$(circuituuid).png"
savecircuit(circuit, f)
circuituuid
end
f = "$(circuituuid).png"
data = Base64.base64encode(open(f))
return (true, """
<img src="data:image/png;base64,$(data)">
<details>
<summary>TeX code for this image</summary>
<pre>
$(circuit2string(circuit))
</pre>
</details>
""")
catch e
return (false, "rendering error: $(repr(e))")
end
end
route("/") do
if haskey(params(), :circuit)
circuit = unescapeuri(replace(params(:circuit),"+"=>" "))
parsed = parsecircuit(circuit)
good, rendered = rendercircuit(parsed)
if good
pretty_string = replace(string(parsed),"),"=>"),\n")
textarea = "$(pretty_string)"
aboveform = "<p>$(rendered)</p>"
return TEMPLATE(;textarea,aboveform)
else
textarea = "$(circuit)"
aboveform = "<p>$(rendered)</p>"
return TEMPLATE(;textarea,aboveform)
end
else
textarea = """
[CNOT(1,2),
CPHASE(3,4),
Measurement(1),
Measurement("X", 2),
Measurement("Z", 3, 1)]
"""
aboveform = ""
return TEMPLATE(;textarea,aboveform)
end
end
const TEMPLATE = mt"""
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Quantikz.jl Renderer</title>
<meta name="description" content="Renderer for quantum circuits.">
<meta name="author" content="Stefan Krastanov">
<style type="text/css">
body{
margin:40px auto;
max-width:650px;
line-height:1.6;
font-size:15px;
color:#444;
padding:0 10px;
}
h1,h2,h3{
line-height:1.2;
}
img{
max-height: 200px;
max-width: 100%;
margin: auto;
}
textarea{
width: 100%;
height: 10rem;
margin-top: 1rem;
margin-bottom: 1rem;
}
iframe{
width: 100%;
height: 100vh;
}
pre{
font-size: 0.8rem;
}
summary{
font-size: 0.8rem;
}
</style>
<!-- Matomo -->
<script type="text/javascript">
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//matomo.krastanov.org/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '3']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head>
<body>
{{{:aboveform}}}
<form action="/" method="get" id="form">
<textarea name="circuit" form="form">
{{:textarea}}
</textarea>
<input type="submit" value="Render" onclick="this.form.submit(); this.disabled = true; this.value = 'Rendering...';">
</form>
<p>
Made by <a href="https://blog.krastanov.org">Stefan Krastanov</a> with the <a href="https://github.com/QuantumSavory/Quantikz.jl">Quantikz.jl</a> Julia library, based on the <a href="https://arxiv.org/abs/1809.03842">Alastair Kay's quantikz TeX package</a>. Runs on <a href="https://www.genieframework.com/">Genie</a>.
</p>
<h2>Accepted Commands (from <a href="https://github.com/QuantumSavory/Quantikz.jl">Quantikz.jl</a>):</h2>
<iframe src="https://quantumsavory.github.io/Quantikz.jl/stable/useful/">
</iframe>
<!-- Matomo Image Tracker-->
<img referrerpolicy="no-referrer-when-downgrade" src="https://matomo.krastanov.org/matomo.php?idsite=3&rec=1" style="border:0" alt="" />
<!-- End Matomo -->
</body>
</html>
"""