Skip to content

Commit a6fb68f

Browse files
committed
tests for ir
1 parent b33835f commit a6fb68f

3 files changed

Lines changed: 118 additions & 143 deletions

File tree

src/ZX/ir.jl

Lines changed: 115 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,82 @@
1-
using DocStringExtensions
2-
3-
"""
4-
$(TYPEDSIGNATURES)
5-
6-
Convert a BlockIR to a ZXCircuit.
7-
8-
This function converts YaoHIR's BlockIR representation to a ZXCircuit by translating
9-
each gate operation to the corresponding ZX-diagram representation.
10-
11-
Returns a `ZXCircuit` containing the circuit representation.
12-
13-
See also: [`convert_to_zxd`](@ref)
14-
"""
15-
function convert_to_circuit(root::YaoHIR.BlockIR)
16-
circ = ZXCircuit(root.nqubits)
17-
circuit = canonicalize_single_location(root.circuit)
18-
return gates_to_circ(circ, circuit, root)
1+
YaoHIR.Chain(zxd::AbstractZXCircuit) = convert_to_chain(zxd)
2+
convert_to_chain(circ::ZXCircuit) = convert_to_chain(ZXDiagram(circ))
3+
function convert_to_chain(circ::ZXDiagram{TT, P}) where {TT, P}
4+
spider_seq = spider_sequence(circ)
5+
gates = []
6+
for vs in spider_seq
7+
if length(vs) == 1
8+
v = vs
9+
q = Int(qubit_loc(circ, v))
10+
push_spider_to_chain!(gates, q, phase(circ, v), spider_type(circ, v))
11+
elseif length(vs) == 2
12+
v1, v2 = vs
13+
q1 = Int(qubit_loc(circ, v1))
14+
q2 = Int(qubit_loc(circ, v2))
15+
push_spider_to_chain!(gates, q1, phase(circ, v1), spider_type(circ, v1))
16+
push_spider_to_chain!(gates, q2, phase(circ, v2), spider_type(circ, v2))
17+
if spider_type(circ, v1) == SpiderType.Z && spider_type(circ, v2) == SpiderType.X
18+
push!(gates, Ctrl(Gate(X, Locations(q2)), CtrlLocations(q1)))
19+
elseif spider_type(circ, v1) == SpiderType.X && spider_type(circ, v2) == SpiderType.Z
20+
push!(gates, Ctrl(Gate(X, Locations(q1)), CtrlLocations(q2)))
21+
else
22+
error("Spiders ($v1, $v2) should represent a CNOT")
23+
end
24+
elseif length(vs) == 3
25+
v1, h, v2 = vs
26+
spider_type(circ, h) == SpiderType.H || error("The spider $h should be a H-box")
27+
q1 = Int(qubit_loc(circ, v1))
28+
q2 = Int(qubit_loc(circ, v2))
29+
push_spider_to_chain!(gates, q1, phase(circ, v1), spider_type(circ, v1))
30+
push_spider_to_chain!(gates, q2, phase(circ, v2), spider_type(circ, v2))
31+
if spider_type(circ, v1) == SpiderType.Z && spider_type(circ, v2) == SpiderType.Z
32+
push!(gates, Ctrl(Gate(Z, Locations(q2)), CtrlLocations(q1)))
33+
else
34+
error("Spiders ($v1, $h, $v2) should represent a CZ")
35+
end
36+
else
37+
error("ZXDiagram's without circuit structure are not supported")
38+
end
39+
end
40+
return Chain(gates...)
1941
end
2042

21-
"""
22-
$(TYPEDSIGNATURES)
23-
24-
Convert a BlockIR to a ZXDiagram.
25-
26-
!!! warning "Deprecated"
27-
`convert_to_zxd` is deprecated. Use [`convert_to_circuit`](@ref) instead.
28-
This function internally converts to ZXCircuit and then wraps it in ZXDiagram.
29-
30-
Returns a `ZXDiagram` for backward compatibility.
31-
"""
32-
function convert_to_zxd(root::YaoHIR.BlockIR)
33-
Base.depwarn("convert_to_zxd is deprecated, use convert_to_circuit instead", :convert_to_zxd)
34-
circ = convert_to_circuit(root)
35-
return ZXDiagram(circ)
43+
function push_spider_to_chain!(gates, q::Integer, ps::AbstractPhase, st::SpiderType.SType)
44+
if ps != 0
45+
if st == SpiderType.Z
46+
if ps == 1
47+
push!(gates, Gate(Z, Locations(q)))
48+
elseif ps == 1 // 2
49+
push!(gates, Gate(S, Locations(q)))
50+
elseif ps == 3 // 2
51+
push!(gates, Gate(AdjointOperation(S), Locations(q)))
52+
elseif ps == 1 // 4
53+
push!(gates, Gate(T, Locations(q)))
54+
elseif ps == 7 // 4
55+
push!(gates, Gate(AdjointOperation(T), Locations(q)))
56+
elseif ps != 0
57+
θ = ps * π
58+
if θ isa Phase
59+
θ = θ.ex
60+
end
61+
push!(gates, Gate(shift(θ), Locations(q)))
62+
end
63+
elseif st == SpiderType.X
64+
if ps == 1
65+
push!(gates, Gate(X, Locations(q)))
66+
else
67+
ps != 0
68+
θ = ps * π
69+
if θ isa Phase
70+
θ = θ.ex
71+
end
72+
push!(gates, Gate(Rx(θ), Locations(q)))
73+
end
74+
elseif st == SpiderType.H
75+
push!(gates, Gate(H, Locations(q)))
76+
end
77+
end
3678
end
3779

38-
ZXDiagram(bir::BlockIR) = ZXDiagram(convert_to_circuit(bir))
39-
ZXCircuit(bir::BlockIR) = convert_to_circuit(bir)
40-
YaoHIR.Chain(zxd::ZXDiagram) = convert_to_chain(zxd)
41-
4280
convert_to_gate(::Val{:X}, loc) = Gate(X, Locations(loc))
4381
convert_to_gate(::Val{:Z}, loc) = Gate(Z, Locations(loc))
4482
convert_to_gate(::Val{:H}, loc) = Gate(H, Locations(loc))
@@ -120,7 +158,46 @@ function canonicalize_single_location(node::YaoHIR.Gate)
120158
return YaoHIR.Gate(node.operation, node.locations[1])
121159
end
122160

123-
function gates_to_circ(circ, circuit, root)
161+
"""
162+
$(TYPEDSIGNATURES)
163+
164+
Convert a BlockIR to a ZXCircuit.
165+
166+
This function converts YaoHIR's BlockIR representation to a ZXCircuit by translating
167+
each gate operation to the corresponding ZX-diagram representation.
168+
169+
Returns a `ZXCircuit` containing the circuit representation.
170+
171+
See also: [`convert_to_zxd`](@ref)
172+
"""
173+
function convert_to_circuit(root::YaoHIR.BlockIR)
174+
circ = ZXCircuit(root.nqubits)
175+
circuit = canonicalize_single_location(root.circuit)
176+
return _append_chain_to_zx_circ!(circ, circuit, root)
177+
end
178+
179+
"""
180+
$(TYPEDSIGNATURES)
181+
182+
Convert a BlockIR to a ZXDiagram.
183+
184+
!!! warning "Deprecated"
185+
186+
`convert_to_zxd` is deprecated. Use [`convert_to_circuit`](@ref) instead.
187+
This function internally converts to ZXCircuit and then wraps it in ZXDiagram.
188+
189+
Returns a `ZXDiagram` for backward compatibility.
190+
"""
191+
function convert_to_zxd(root::YaoHIR.BlockIR)
192+
Base.depwarn("Use convert_to_circuit instead", :convert_to_zxd)
193+
circ = convert_to_circuit(root)
194+
return ZXDiagram(circ)
195+
end
196+
197+
ZXDiagram(bir::BlockIR) = ZXDiagram(convert_to_circuit(bir))
198+
ZXCircuit(bir::BlockIR) = convert_to_circuit(bir)
199+
200+
function _append_chain_to_zx_circ!(circ::AbstractZXCircuit, circuit, root)
124201
for gate in YaoHIR.leaves(circuit)
125202
@switch gate begin
126203
@case Gate(&Z, loc::Locations{Int})
@@ -169,81 +246,3 @@ function gates_to_circ(circ, circuit, root)
169246
end
170247
return circ
171248
end
172-
173-
function push_spider_to_chain!(qc, q, ps, st)
174-
if ps != 0
175-
if st == SpiderType.Z
176-
if ps == 1
177-
push!(qc, Gate(Z, Locations(q)))
178-
elseif ps == 1 // 2
179-
push!(qc, Gate(S, Locations(q)))
180-
elseif ps == 3 // 2
181-
push!(qc, Gate(AdjointOperation(S), Locations(q)))
182-
elseif ps == 1 // 4
183-
push!(qc, Gate(T, Locations(q)))
184-
elseif ps == 7 // 4
185-
push!(qc, Gate(AdjointOperation(T), Locations(q)))
186-
elseif ps != 0
187-
θ = ps * π
188-
if θ isa Phase
189-
θ = θ.ex
190-
end
191-
push!(qc, Gate(shift(θ), Locations(q)))
192-
end
193-
elseif st == SpiderType.X
194-
if ps == 1
195-
push!(qc, Gate(X, Locations(q)))
196-
else
197-
ps != 0
198-
θ = ps * π
199-
if θ isa Phase
200-
θ = θ.ex
201-
end
202-
push!(qc, Gate(Rx(θ), Locations(q)))
203-
end
204-
elseif st == SpiderType.H
205-
push!(qc, Gate(H, Locations(q)))
206-
end
207-
end
208-
end
209-
210-
function convert_to_chain(circ::ZXDiagram{TT, P}) where {TT, P}
211-
spider_seq = spider_sequence(circ)
212-
qc = []
213-
for vs in spider_seq
214-
if length(vs) == 1
215-
v = vs
216-
q = Int(qubit_loc(circ, v))
217-
push_spider_to_chain!(qc, q, phase(circ, v), spider_type(circ, v))
218-
elseif length(vs) == 2
219-
v1, v2 = vs
220-
q1 = Int(qubit_loc(circ, v1))
221-
q2 = Int(qubit_loc(circ, v2))
222-
push_spider_to_chain!(qc, q1, phase(circ, v1), spider_type(circ, v1))
223-
push_spider_to_chain!(qc, q2, phase(circ, v2), spider_type(circ, v2))
224-
if spider_type(circ, v1) == SpiderType.Z && spider_type(circ, v2) == SpiderType.X
225-
push!(qc, Ctrl(Gate(X, Locations(q2)), CtrlLocations(q1)))
226-
elseif spider_type(circ, v1) == SpiderType.X && spider_type(circ, v2) == SpiderType.Z
227-
push!(qc, Ctrl(Gate(X, Locations(q1)), CtrlLocations(q2)))
228-
else
229-
error("Spiders ($v1, $v2) should represent a CNOT")
230-
end
231-
elseif length(vs) == 3
232-
v1, h, v2 = vs
233-
spider_type(circ, h) == SpiderType.H || error("The spider $h should be a H-box")
234-
q1 = Int(qubit_loc(circ, v1))
235-
q2 = Int(qubit_loc(circ, v2))
236-
push_spider_to_chain!(qc, q1, phase(circ, v1), spider_type(circ, v1))
237-
push_spider_to_chain!(qc, q2, phase(circ, v2), spider_type(circ, v2))
238-
if spider_type(circ, v1) == SpiderType.Z && spider_type(circ, v2) == SpiderType.Z
239-
push!(qc, Ctrl(Gate(Z, Locations(q2)), CtrlLocations(q1)))
240-
else
241-
error("Spiders ($v1, $h, $v2) should represent a CZ")
242-
end
243-
else
244-
error("ZXDiagram's without circuit structure are not supported")
245-
end
246-
end
247-
return Chain(qc...)
248-
end
249-

test/ZX/ir.jl

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ end
298298

299299
@testset "gates_to_circ with addition Ry" begin
300300
n_qubits = 4
301-
# TODO add tests for Ry gate
302301
chain_a = Chain()
303302
push_gate!(chain_a, Val(:Ry), n_qubits, Phase(1 // 1))
304303
push_gate!(chain_a, Val(:Rz), 4, Phase(1 // 1))
@@ -307,13 +306,4 @@ end
307306
diagram = ZXDiagram(n_qubits)
308307
ZX.gates_to_circ(diagram, chain_a, bir)
309308
end
310-
311-
# TODO add test that checks if error is thrown for unkown gate
312-
313-
@testset "Chain of ZXDiagram" begin
314-
# FIXME add better equal for Chain
315-
# @test chain.args == Chain(ZXDiagram(bir)).args
316-
# @test chain.args == Chain(ZXDiagram(bir)).args
317-
@test !isnothing(Chain(zxd))
318-
end
319309
end

test/ZX/zx_circuit_basic.jl

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ using ZXCalculus.ZX
33
using ZXCalculus.Utils: Phase
44
using ZXCalculus.ZX: SpiderType
55
using Graphs
6+
using YaoHIR, YaoLocations
7+
using YaoHIR.IntrinsicOperation
68

79
@testset "ZXCircuit basic constructor" begin
810
# Test nbits constructor
@@ -62,19 +64,6 @@ end
6264
@test nqubits(zxd2) == 2
6365
end
6466

65-
@testset "ZXCircuit circuit extraction" begin
66-
circ = ZXCircuit(2)
67-
push_gate!(circ, Val(:H), 1)
68-
push_gate!(circ, Val(:CNOT), 2, 1)
69-
push_gate!(circ, Val(:H), 1)
70-
71-
# Test ancilla extraction returns ZXCircuit
72-
# TODO: fix ancilla_extraction
73-
# result = ancilla_extraction(circ)
74-
# @test result isa ZXCircuit
75-
# @test nqubits(result) == nqubits(circ)
76-
end
77-
7867
@testset "ZXCircuit equality verification" begin
7968
# Create two identical circuits
8069
circ1 = ZXCircuit(2)
@@ -90,9 +79,6 @@ end
9079
end
9180

9281
@testset "ZXCircuit IR conversion" begin
93-
using YaoHIR, YaoLocations
94-
using YaoHIR.IntrinsicOperation
95-
9682
# Create a simple BlockIR
9783
circuit = Chain(
9884
Gate(H, Locations(1)),
@@ -111,7 +97,7 @@ end
11197
@test nqubits(circ2) == 2
11298

11399
# Test deprecated convert_to_zxd still works
114-
@test_deprecated zxd = convert_to_zxd(bir)
100+
zxd = convert_to_zxd(bir)
115101
@test zxd isa ZXDiagram
116102
@test nqubits(zxd) == 2
117103
end

0 commit comments

Comments
 (0)