-
Notifications
You must be signed in to change notification settings - Fork 3
/
qasm.jl
145 lines (127 loc) · 4.7 KB
/
qasm.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
using OpenQASM.Types
using OpenQASM.RBNF: Token
#todo support custom yao gates to qasm
"""
convert_to_qasm(qc, ncreg)
Parses an `AbstractBlock` into code based on the `OpenQASM` spec
- `qc`: A `ChainBlock`(circuit that is to be run).
- `ncreg` (optional) : Number of classical registers
While performing operations like measuring, one can input desired number of classical regs(each size equal to number of qubits). Defaults to 1.
"""
function convert_to_qasm(qc::AbstractBlock{N}, ncreg::Int = 1) where {N}
prog = generate_prog(qc, ncreg)
MainProgram(v"2", prog)
end
"""
generate_prog(qc)
Parses the YaoIR into a list of `QASM` instructions
- `qc`: A `ChainBlock`(circuit that is to be run).
"""
function generate_prog(qc::AbstractBlock{N}, ncreg::Int) where {N}
prog = []
generate_defs(prog, N, ncreg)
generate_prog!(prog, basicstyle(qc), [0:N-1...], Int[])
return prog
end
function generate_defs(prog, nq::Int, ncreg::Int)
qregs = RegDecl(Token{:reserved}("qreg"), Token{:type}("q"), Token{:int}("$nq"))
cregs = collect(
RegDecl(Token{:reserved}("creg"), Token{:type}("c$i"), Token{:int}("$nq")) for
i = 1:ncreg
)
push!(prog, Include(Bit("\"qelib1.inc\"")), qregs, cregs...)
end
function generate_prog!(prog, qc_simpl::ChainBlock, locs, controls)
for block in subblocks(qc_simpl)
generate_prog!(prog, block, locs, controls)
end
end
function generate_prog!(prog, blk::PutBlock{N,M}, locs, controls) where {N,M}
generate_prog!(prog, blk.content, sublocs(blk.locs, locs), controls)
end
function generate_prog!(prog, blk::ControlBlock{N,GT,C}, locs, controls) where {N,GT,C}
any(==(0), blk.ctrl_config) && error("Inverse Control used in Control gate context")
generate_prog!(
prog,
blk.content,
sublocs(blk.locs, locs),
[controls..., sublocs(blk.ctrl_locs, locs)...],
)
end
function generate_prog!(prog, m::YaoBlocks.Measure{N}, locs, controls) where {N}
mlocs = sublocs(m.locations isa AllLocs ? [1:N...] : [m.locations...], locs)
(length(controls) == 0) || error("controlled measure is not supported")
if !(m.operator isa ComputationalBasis) && m.operator isa AbstractBlock
generate_prog!(prog, m.operator, mlocs, ())
end
# can be improved
for i in mlocs
cargs = Bit("c1", i)
qargs = Bit("q", i)
inst = Types.Measure(qargs, cargs)
push!(prog, inst)
end
end
# IBMQ Chip only supports ["id", "u1", "u2", "u3", "cx"]
# x, y, z and control x, y, z, id, t, swap and other primitive gates
for (GT, NAME, MAXC) in [
(:XGate, "x", 2),
(:YGate, "y", 2),
(:ZGate, "z", 2),
(:I2Gate, "id", 0),
(:TGate, "t", 0),
(:SWAPGate, "swap", 0),
]
@eval function generate_prog!(prog, ::$GT, locs, controls)
if length(controls) <= $MAXC
# push!(prog, )
name = "c"^(length(controls)) * $NAME
if name != "cx" && name != "swap"
cargs = [] #empty for now
qargs =
isempty(controls) ? [Bit("q", locs...)] :
[Bit("q", controls...), Bit("q", locs...)]
inst = Instruction(name, cargs, qargs)
elseif name == "swap"
cargs = [] #empty for now
qargs = [Bit("q", i) for i in locs]
inst = Instruction(name, cargs, qargs)
else
inst = CXGate(Bit("q", controls...), Bit("q", locs...))
end
push!(prog, inst)
else
error("too many control bits!")
end
end
end
for (GT, NAME, PARAMS, MAXC) in [
(:(RotationGate{1,T,XGate} where {T}), "rx", :(b.theta), 0),
(:(RotationGate{1,T,YGate} where {T}), "ry", :(b.theta), 0),
(:(RotationGate{1,T,ZGate} where {T}), "rz", :(b.theta), 0),
(:(ShiftGate), "p", :(b.theta), 1),
(:(HGate), "h", :(nothing), 0),
]
@eval function generate_prog!(prog, b::$GT, locs, controls)
if length(controls) <= $MAXC
name = "c"^(length(controls)) * $NAME
if $PARAMS === nothing
cargs = []
qargs = [Bit("q", locs...)]
else
params = $PARAMS
cargs = [Token{:float64}("$params")]
qargs =
isempty(controls) ? [Bit("q", locs...)] :
[Bit("q", controls...), Bit("q", locs...)]
end
push!(prog, Instruction(name, cargs, qargs))
else
error("too many control bits! got $controls (length > $($(MAXC)))")
end
end
end
sublocs(subs, locs) = [locs[i] for i in subs]
function basicstyle(blk::AbstractBlock)
YaoBlocks.Optimise.simplify(blk, rules = [YaoBlocks.Optimise.to_basictypes])
end