Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | // Copyright 2019-2022 Cambridge Quantum Computing | |||
2 | // | |||
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | |||
4 | // you may not use this file except in compliance with the License. | |||
5 | // You may obtain a copy of the License at | |||
6 | // | |||
7 | // http://www.apache.org/licenses/LICENSE-2.0 | |||
8 | // | |||
9 | // Unless required by applicable law or agreed to in writing, software | |||
10 | // distributed under the License is distributed on an "AS IS" BASIS, | |||
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
12 | // See the License for the specific language governing permissions and | |||
13 | // limitations under the License. | |||
14 | ||||
15 | #include "Circuit/CircPool.hpp" | |||
16 | #include "Converters.hpp" | |||
17 | #include "ZX/Flow.hpp" | |||
18 | #include "ZX/ZXDiagram.hpp" | |||
19 | ||||
20 | namespace tket { | |||
21 | ||||
22 | using namespace zx; | |||
23 | ||||
24 | enum class ZXPortType { In, Out }; | |||
25 | typedef std::pair<VertPort, ZXPortType> TypedVertPort; | |||
26 | typedef std::pair<ZXVert, std::optional<unsigned>> ZXVertPort; | |||
27 | typedef std::vector<ZXVertPort> ZXVertPortVec; | |||
28 | typedef boost::bimap<ZXVert, Vertex> BoundaryVertMap; | |||
29 | ||||
30 | 366 | bool is_spiderless_optype(const OpType& optype) { | ||
31 |
4/4✓ Branch 0 taken 338 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 314 times.
✓ Branch 3 taken 24 times.
|
680 | return optype == OpType::Barrier || optype == OpType::SWAP || | |
32 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 306 times.
|
680 | optype == OpType::noop; | |
33 | } | |||
34 | ||||
35 | // Add a swicth with the on-state controlled by the on_value. | |||
36 | // qtype indicates the quantum type of the switch. | |||
37 | 32 | std::pair<ZXVertPort, ZXVertPort> add_switch( | ||
38 | ZXDiagram& zxd, const bool& on_value, const QuantumType& qtype) { | |||
39 |
2/4✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
|
32 | zxd.multiply_scalar(std::sqrt(2.)); | |
40 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | ZXVert triangle = zxd.add_vertex(ZXType::Triangle, qtype); | |
41 |
2/4✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
|
32 | ZXVert x = zxd.add_vertex(ZXType::XSpider, 0, qtype); | |
42 |
1/2✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
|
32 | zxd.add_wire(triangle, x, ZXWireType::Basic, qtype, 1); | |
43 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
|
2/2✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 16 times.
|
32 | if (on_value) { |
44 | // Turn on the switch if the input is 1 | |||
45 |
2/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 | ZXVert negate = zxd.add_vertex(ZXType::XSpider, 1, qtype); | |
46 |
1/2✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
|
16 | zxd.add_wire(triangle, negate, ZXWireType::Basic, qtype, 0); | |
47 | 16 | return {{negate, std::nullopt}, {x, std::nullopt}}; | ||
48 | } | |||
49 | 16 | return {{triangle, 0}, {x, std::nullopt}}; | ||
50 | } | |||
51 | ||||
52 | // --o--s---o-- | |||
53 | // | | | |||
54 | // n n | |||
55 | // |--G-o-| | |||
56 | // | | |||
57 | // s | |||
58 | // |-discard | |||
59 | // s, n are switches, G is the conditional zx diagram specified by 'left' and | |||
60 | // 'right'. s is on when the input is 0, n is on when the input is 1. | |||
61 | // return the input and the output of the conditional zx along with a vector of | |||
62 | // control spiders | |||
63 | 8 | std::pair<std::pair<ZXVertPort, ZXVertPort>, ZXVertPortVec> add_conditional_zx( | ||
64 | ZXDiagram& zxd, const ZXVert& left, const ZXVert& right, | |||
65 | const QuantumType& qtype) { | |||
66 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert in = zxd.add_vertex(ZXType::ZSpider, 0, qtype); | |
67 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert out = zxd.add_vertex(ZXType::ZSpider, 0, qtype); | |
68 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert discard_ctr = zxd.add_vertex(ZXType::ZSpider, 0, qtype); | |
69 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert discard = zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
70 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto switch_s0 = add_switch(zxd, false, qtype); | |
71 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto switch_n0 = add_switch(zxd, true, qtype); | |
72 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto switch_n1 = add_switch(zxd, true, qtype); | |
73 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto switch_s1 = add_switch(zxd, false, qtype); | |
74 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(in, switch_s0.second.first, ZXWireType::Basic, qtype); | |
75 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(out, switch_s0.second.first, ZXWireType::Basic, qtype); | |
76 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(in, switch_n0.second.first, ZXWireType::Basic, qtype); | |
77 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(left, switch_n0.second.first, ZXWireType::Basic, qtype); | |
78 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(right, discard_ctr, ZXWireType::Basic, qtype); | |
79 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(discard_ctr, switch_n1.second.first, ZXWireType::Basic, qtype); | |
80 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(out, switch_n1.second.first, ZXWireType::Basic, qtype); | |
81 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(discard_ctr, switch_s1.second.first, ZXWireType::Basic, qtype); | |
82 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | zxd.add_wire(discard, switch_s1.second.first, ZXWireType::Basic, qtype); | |
83 | return { | |||
84 | {{in, std::nullopt}, {out, std::nullopt}}, | |||
85 |
2/4✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
8 | {switch_s0.first, switch_s1.first, switch_n0.first, switch_n1.first}}; | |
86 | } | |||
87 | ||||
88 | // n-bit AND spider to control the switches | |||
89 | // https://arxiv.org/abs/1910.06818 | |||
90 | 2 | std::pair<ZXVertPortVec, ZXVertPort> add_n_bit_and( | ||
91 | ZXDiagram& zxd, unsigned n, const QuantumType& qtype) { | |||
92 | TKET_ASSERT(n > 1); | |||
93 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | ZXVert z_vert = zxd.add_vertex(ZXType::ZSpider, 0, qtype); | |
94 | // Add Triangle -1 | |||
95 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | ZXVert z_pi_0 = zxd.add_vertex(ZXType::ZSpider, 1, qtype); | |
96 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ZXVert tri_1 = zxd.add_vertex(ZXType::Triangle, qtype); | |
97 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | ZXVert z_pi_1 = zxd.add_vertex(ZXType::ZSpider, 1, qtype); | |
98 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | zxd.add_wire(z_vert, z_pi_0, ZXWireType::Basic, qtype); | |
99 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | zxd.add_wire(tri_1, z_pi_0, ZXWireType::Basic, qtype, 0); | |
100 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | zxd.add_wire(tri_1, z_pi_1, ZXWireType::Basic, qtype, 1); | |
101 | 2 | ZXVertPortVec inputs; | ||
102 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 2 times.
|
7 | for (unsigned i = 0; i < n; i++) { |
103 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | ZXVert tri_0 = zxd.add_vertex(ZXType::Triangle, qtype); | |
104 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | zxd.add_wire(tri_0, z_vert, ZXWireType::Basic, qtype, 1); | |
105 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | inputs.push_back({tri_0, 0}); | |
106 | } | |||
107 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | return {inputs, {z_pi_1, std::nullopt}}; | |
108 | 2 | } | ||
109 | ||||
110 | // Add converted circ into zxd. Set add_boundary to true | |||
111 | // if boundary spiders are to be added to the boundary. | |||
112 | 38 | BoundaryVertMap circuit_to_zx_recursive( | ||
113 | const Circuit& circ, ZXDiagram& zxd, bool add_boundary) { | |||
114 | 38 | std::map<TypedVertPort, ZXVertPort> vert_lookup; | ||
115 | 38 | std::map<VertPort, ZXVertPort> boolean_outport_lookup; | ||
116 |
1/2✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
38 | BoundaryVertMap bmap; | |
117 | ||||
118 | // Convert each vertex to ZXDiagram, raise error if not supported | |||
119 |
7/8✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 221 times.
✓ Branch 6 taken 37 times.
✓ Branch 8 taken 221 times.
✓ Branch 9 taken 37 times.
✓ Branch 11 taken 37 times.
✓ Branch 12 taken 38 times.
|
296 | BGL_FORALL_VERTICES(vert, circ.dag, DAG) { | |
120 | // We currently throw an error if the vertex is either classical or flow | |||
121 |
1/2✓ Branch 1 taken 221 times.
✗ Branch 2 not taken.
|
221 | Op_ptr op = circ.get_Op_ptr_from_Vertex(vert); | |
122 |
5/10✓ Branch 3 taken 221 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 221 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 221 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 221 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 221 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 221 times.
|
221 | if (is_flowop_type(op->get_type()) || is_classical_type(op->get_type())) { |
123 | ✗ | throw Unsupported( | ||
124 | ✗ | "Cannot convert OpType: " + op->get_name() + " to a ZX node. \n"); | ||
125 | } | |||
126 |
19/19✓ Branch 2 taken 62 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 4 times.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 2 times.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 6 times.
✓ Branch 20 taken 3 times.
|
221 | switch (op->get_type()) { | |
127 |
1/1✓ Decision 'true' taken 62 times.
|
62 | case OpType::Input: { | |
128 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
62 | ZXVert zx_vert = zxd.add_vertex(ZXType::Input, QuantumType::Quantum); | |
129 |
3/4✓ Branch 0 taken 47 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 62 times.
✗ Decision 'false' not taken.
|
62 | if (add_boundary) zxd.add_boundary(zx_vert); |
130 |
1/2✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
|
62 | vert_lookup.insert( | |
131 | 62 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
132 |
2/4✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
62 | bmap.insert({zx_vert, vert}); | |
133 | 62 | break; | ||
134 | } | |||
135 |
1/1✓ Decision 'true' taken 62 times.
|
62 | case OpType::Output: { | |
136 |
1/2✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
|
62 | ZXVert zx_vert = zxd.add_vertex(ZXType::Output, QuantumType::Quantum); | |
137 |
3/4✓ Branch 0 taken 47 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 62 times.
✗ Decision 'false' not taken.
|
62 | if (add_boundary) zxd.add_boundary(zx_vert); |
138 |
1/2✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
|
62 | vert_lookup.insert( | |
139 | 62 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
140 |
2/4✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
|
62 | bmap.insert({zx_vert, vert}); | |
141 | 62 | break; | ||
142 | } | |||
143 |
1/1✓ Decision 'true' taken 15 times.
|
15 | case OpType::ClInput: { | |
144 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | ZXVert zx_vert = zxd.add_vertex(ZXType::Input, QuantumType::Classical); | |
145 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 15 times.
✗ Decision 'false' not taken.
|
15 | if (add_boundary) zxd.add_boundary(zx_vert); |
146 |
1/2✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
|
15 | vert_lookup.insert( | |
147 | 15 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
148 |
2/4✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | bmap.insert({zx_vert, vert}); | |
149 | 15 | break; | ||
150 | } | |||
151 |
1/1✓ Decision 'true' taken 15 times.
|
15 | case OpType::ClOutput: { | |
152 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | ZXVert zx_vert = zxd.add_vertex(ZXType::Output, QuantumType::Classical); | |
153 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
1/2✓ Decision 'true' taken 15 times.
✗ Decision 'false' not taken.
|
15 | if (add_boundary) zxd.add_boundary(zx_vert); |
154 |
1/2✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
|
15 | vert_lookup.insert( | |
155 | 15 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
156 |
2/4✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
15 | bmap.insert({zx_vert, vert}); | |
157 | 15 | break; | ||
158 | } | |||
159 | // Spiderless ops are handled during vertex wiring | |||
160 | 17 | case OpType::Barrier: | ||
161 | case OpType::noop: | |||
162 | case OpType::SWAP: { | |||
163 | 17 | continue; | ||
164 | } | |||
165 |
1/1✓ Decision 'true' taken 9 times.
|
9 | case OpType::H: { | |
166 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | ZXVert zx_vert = zxd.add_vertex(ZXType::Hbox, QuantumType::Quantum); | |
167 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | vert_lookup.insert( | |
168 | 9 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
169 |
1/2✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
|
9 | vert_lookup.insert( | |
170 | 9 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
171 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | zxd.multiply_scalar(0.5); | |
172 | 9 | break; | ||
173 | } | |||
174 |
1/1✓ Decision 'true' taken 7 times.
|
7 | case OpType::Rz: { | |
175 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | ZXVert zx_vert = zxd.add_vertex( | |
176 |
1/2✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
14 | ZXType::ZSpider, op->get_params()[0], QuantumType::Quantum); | |
177 |
1/2✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
|
7 | vert_lookup.insert( | |
178 | 7 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
179 |
1/2✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
|
7 | vert_lookup.insert( | |
180 | 7 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
181 | 7 | break; | ||
182 | } | |||
183 |
1/1✓ Decision 'true' taken 2 times.
|
2 | case OpType::Rx: { | |
184 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ZXVert zx_vert = zxd.add_vertex( | |
185 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | ZXType::XSpider, op->get_params()[0], QuantumType::Quantum); | |
186 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
187 | 2 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
188 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
189 | 2 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
190 | 2 | break; | ||
191 | } | |||
192 | 5 | case OpType::X: { | ||
193 | ZXVert zx_vert = | |||
194 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | zxd.add_vertex(ZXType::XSpider, 1, QuantumType::Quantum); | |
195 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | vert_lookup.insert( | |
196 | 5 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
197 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | vert_lookup.insert( | |
198 | 5 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
199 | 5 | break; | ||
200 | } | |||
201 | 1 | case OpType::Z: { | ||
202 | ZXVert zx_vert = | |||
203 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | zxd.add_vertex(ZXType::ZSpider, 1, QuantumType::Quantum); | |
204 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1 | vert_lookup.insert( | |
205 | 1 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
206 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1 | vert_lookup.insert( | |
207 | 1 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
208 | 1 | break; | ||
209 | } | |||
210 | 4 | case OpType::CX: { | ||
211 | ZXVert zx_x_vert = | |||
212 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | zxd.add_vertex(ZXType::XSpider, 0, QuantumType::Quantum); | |
213 | ZXVert zx_z_vert = | |||
214 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Quantum); | |
215 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | zxd.add_wire(zx_x_vert, zx_z_vert); | |
216 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
217 | 4 | {{{vert, 0}, ZXPortType::In}, {zx_z_vert, std::nullopt}}); | ||
218 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
219 | 4 | {{{vert, 0}, ZXPortType::Out}, {zx_z_vert, std::nullopt}}); | ||
220 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
221 | 4 | {{{vert, 1}, ZXPortType::In}, {zx_x_vert, std::nullopt}}); | ||
222 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
223 | 4 | {{{vert, 1}, ZXPortType::Out}, {zx_x_vert, std::nullopt}}); | ||
224 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | zxd.multiply_scalar(2); | |
225 | 4 | break; | ||
226 | } | |||
227 | 3 | case OpType::CZ: { | ||
228 | ZXVert zx_za_vert = | |||
229 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Quantum); | |
230 | ZXVert zx_zb_vert = | |||
231 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Quantum); | |
232 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | zxd.add_wire(zx_za_vert, zx_zb_vert, ZXWireType::H); | |
233 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | vert_lookup.insert( | |
234 | 3 | {{{vert, 0}, ZXPortType::In}, {zx_za_vert, std::nullopt}}); | ||
235 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | vert_lookup.insert( | |
236 | 3 | {{{vert, 0}, ZXPortType::Out}, {zx_za_vert, std::nullopt}}); | ||
237 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | vert_lookup.insert( | |
238 | 3 | {{{vert, 1}, ZXPortType::In}, {zx_zb_vert, std::nullopt}}); | ||
239 |
1/2✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | vert_lookup.insert( | |
240 | 3 | {{{vert, 1}, ZXPortType::Out}, {zx_zb_vert, std::nullopt}}); | ||
241 | 3 | break; | ||
242 | } | |||
243 |
0/1✗ Decision 'true' not taken.
|
4 | case OpType::Measure: { | |
244 | // Add a decoherence node | |||
245 | ZXVert zx_measure_vert = | |||
246 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
247 | // Add a delete operator | |||
248 | ZXVert zx_delete_vert = | |||
249 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
250 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
251 | 4 | {{{vert, 0}, ZXPortType::In}, {zx_measure_vert, std::nullopt}}); | ||
252 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
253 | 4 | {{{vert, 0}, ZXPortType::Out}, {zx_measure_vert, std::nullopt}}); | ||
254 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
255 | 4 | {{{vert, 1}, ZXPortType::In}, {zx_delete_vert, std::nullopt}}); | ||
256 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | vert_lookup.insert( | |
257 | 4 | {{{vert, 1}, ZXPortType::Out}, {zx_measure_vert, std::nullopt}}); | ||
258 | 4 | break; | ||
259 | } | |||
260 |
0/1✗ Decision 'true' not taken.
|
2 | case OpType::Reset: { | |
261 | // Discard | |||
262 | ZXVert zx_discard_vert = | |||
263 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
264 | // Add a node to prepare |0> | |||
265 | ZXVert zx_reset_vert = | |||
266 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | zxd.add_vertex(ZXType::XSpider, 0, QuantumType::Quantum); | |
267 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | zxd.multiply_scalar(0.5); | |
268 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
269 | 2 | {{{vert, 0}, ZXPortType::In}, {zx_discard_vert, std::nullopt}}); | ||
270 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
271 | 2 | {{{vert, 0}, ZXPortType::Out}, {zx_reset_vert, std::nullopt}}); | ||
272 | 2 | break; | ||
273 | } | |||
274 | 2 | case OpType::Collapse: { | ||
275 | ZXVert zx_vert = | |||
276 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | zxd.add_vertex(ZXType::ZSpider, QuantumType::Classical); | |
277 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
278 | 2 | {{{vert, 0}, ZXPortType::In}, {zx_vert, std::nullopt}}); | ||
279 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | vert_lookup.insert( | |
280 | 2 | {{{vert, 0}, ZXPortType::Out}, {zx_vert, std::nullopt}}); | ||
281 | 2 | break; | ||
282 | } | |||
283 | 1 | case OpType::Create: { | ||
284 | ZXVert zx_init_vert = | |||
285 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | zxd.add_vertex(ZXType::XSpider, 0, QuantumType::Quantum); | |
286 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | zxd.multiply_scalar(0.5); | |
287 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1 | vert_lookup.insert( | |
288 | 1 | {{{vert, 0}, ZXPortType::Out}, {zx_init_vert, std::nullopt}}); | ||
289 | 1 | break; | ||
290 | } | |||
291 | 1 | case OpType::Discard: { | ||
292 | ZXVert zx_discard_vert = | |||
293 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
294 |
1/2✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
1 | vert_lookup.insert( | |
295 | 1 | {{{vert, 0}, ZXPortType::In}, {zx_discard_vert, std::nullopt}}); | ||
296 | 1 | break; | ||
297 | } | |||
298 |
0/1✗ Decision 'true' not taken.
|
6 | case OpType::Conditional: { | |
299 | // Stores the condition for each port index | |||
300 | 6 | std::vector<bool> port_conditions; | ||
301 | ||||
302 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | op_signature_t parent_sig = op->get_signature(); | |
303 | ||||
304 | // Find the nested quantum op and its overall conditions | |||
305 | // Assume bool ports are always the first few ports | |||
306 |
2/2✓ Branch 2 taken 7 times.
✓ Branch 3 taken 6 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 6 times.
|
13 | while (op->get_type() == OpType::Conditional) { |
307 | 7 | const Conditional& cond = static_cast<const Conditional&>(*op); | ||
308 |
3/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 7 times.
|
0/1? Decision couldn't be analyzed.
|
16 | for (unsigned i = 0; i < cond.get_width(); i++) { |
309 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | bool set = cond.get_value() & (1 << (cond.get_width() - i - 1)); | |
310 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | port_conditions.push_back(set); | |
311 | } | |||
312 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | op = cond.get_op(); | |
313 | } | |||
314 | unsigned port_conditions_size = | |||
315 | 6 | static_cast<unsigned>(port_conditions.size()); | ||
316 | // Convert the underlying op to zx. | |||
317 | // If the op is a quantum gate, construct a 1 gate circuit | |||
318 | // If the op is a box, obtain its circuit decomposition | |||
319 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | op_signature_t inner_sig = op->get_signature(); | |
320 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | Circuit replacement; | |
321 |
3/4✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
|
6 | if (is_box_type(op->get_type())) { |
322 | 1 | const Box& b = static_cast<const Box&>(*op); | ||
323 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | replacement = *b.to_circuit(); | |
324 | } else { | |||
325 | 5 | unit_vector_t args; | ||
326 | 5 | unsigned q_index = 0; | ||
327 | 5 | unsigned c_index = 0; | ||
328 |
2/2✓ Branch 5 taken 6 times.
✓ Branch 6 taken 5 times.
|
2/2✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 5 times.
|
11 | for (const EdgeType& etype : inner_sig) { |
329 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
|
6 | if (etype == EdgeType::Quantum) { |
330 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | args.push_back(Qubit(q_index++)); | |
331 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
|
1 | } else if (etype == EdgeType::Classical) { |
332 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | args.push_back(Bit(c_index++)); | |
333 | } | |||
334 | TKET_ASSERT(etype != EdgeType::Boolean); | |||
335 | } | |||
336 |
2/4✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | replacement = Circuit(q_index, c_index); | |
337 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | replacement.add_op(op, args); | |
338 | 5 | } | ||
339 | BoundaryVertMap box_bm = | |||
340 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | circuit_to_zx_recursive(replacement, zxd, false); | |
341 | ||||
342 | // The Z spider controlling all switches | |||
343 | ZXVert master_switch = | |||
344 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
345 | ||||
346 | // For each qubit/bit path in the inner op, convert it into a | |||
347 | // conditional path. | |||
348 | 6 | unsigned q_index = 0; | ||
349 | 6 | unsigned c_index = 0; | ||
350 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 6 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 6 times.
|
14 | for (unsigned i = 0; i < inner_sig.size(); i++) { |
351 | QuantumType qtype; | |||
352 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | UnitID reg; | |
353 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 1 times.
|
8 | if (inner_sig[i] == EdgeType::Quantum) { |
354 | 7 | qtype = QuantumType::Quantum; | ||
355 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | reg = Qubit(q_index++); | |
356 | } else { | |||
357 | 1 | qtype = QuantumType::Classical; | ||
358 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | reg = Bit(c_index++); | |
359 | } | |||
360 | 8 | std::pair<ZXVertPort, ZXVertPort> boundary; | ||
361 | 8 | ZXVertPortVec controls; | ||
362 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | Vertex inp = replacement.get_in(reg); | |
363 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ZXVert zx_inp = box_bm.right.at(inp); | |
364 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | Vertex outp = replacement.get_out(reg); | |
365 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ZXVert zx_outp = box_bm.right.at(outp); | |
366 | // Convert the path between zx_inp and zx_outp into a conditional | |||
367 | // path | |||
368 | 8 | std::tie(boundary, controls) = | ||
369 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | add_conditional_zx(zxd, zx_inp, zx_outp, qtype); | |
370 | // Connect each switch to the master switch | |||
371 |
2/2✓ Branch 4 taken 32 times.
✓ Branch 5 taken 8 times.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 8 times.
|
40 | for (const ZXVertPort& ctr : controls) { |
372 | 32 | zxd.add_wire( | ||
373 | 32 | ctr.first, master_switch, ZXWireType::Basic, | ||
374 |
3/6✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 32 times.
✗ Branch 8 not taken.
|
32 | zxd.get_qtype(ctr.first).value(), ctr.second); | |
375 | } | |||
376 | // Update lookup | |||
377 | TKET_ASSERT(parent_sig[i + port_conditions_size] == inner_sig[i]); | |||
378 | // Since we assume that the conditions always use the first few | |||
379 | // ports, the gate path should use the i + port_conditions.size() | |||
380 | // port. | |||
381 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | vert_lookup.insert( | |
382 | 8 | {{{vert, i + port_conditions_size}, ZXPortType::In}, | ||
383 | boundary.first}); | |||
384 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | vert_lookup.insert( | |
385 | 8 | {{{vert, i + port_conditions_size}, ZXPortType::Out}, | ||
386 | boundary.second}); | |||
387 | 8 | } | ||
388 | // Use either a Z spider or a AND operator to connect the master | |||
389 | // switch and the boolean inputs | |||
390 | 6 | ZXVertPortVec and_inputs; | ||
391 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 2 times.
|
6 | if (port_conditions_size == 1) { |
392 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | and_inputs.push_back({master_switch, std::nullopt}); | |
393 | } else { | |||
394 | 2 | ZXVertPort and_output; | ||
395 | 2 | std::tie(and_inputs, and_output) = | ||
396 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | add_n_bit_and(zxd, port_conditions_size, QuantumType::Classical); | |
397 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | zxd.add_wire( | |
398 | and_output.first, master_switch, ZXWireType::Basic, | |||
399 | QuantumType::Classical, and_output.second); | |||
400 | } | |||
401 | // Connect inputs to the nodes obtained from above | |||
402 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
|
2/2✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 6 times.
|
15 | for (unsigned i = 0; i < port_conditions_size; i++) { |
403 | // Each boolean edge shares a source port with other | |||
404 | // classical/boolean edges. Use the classical Z spider to explicitly | |||
405 | // implement this copy operation | |||
406 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | Edge in_edge = circ.get_nth_in_edge(vert, i); | |
407 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | port_t source_port = circ.get_source_port(in_edge); | |
408 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | Vertex vert_s = circ.source(in_edge); | |
409 | // During the wiring stage, each edge originated from {vert_s, | |||
410 | // p_s} needs go through copy_vert | |||
411 |
1/2✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 1 times.
|
9 | if (boolean_outport_lookup.find({vert_s, source_port}) == |
412 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 times.
|
18 | boolean_outport_lookup.end()) { | |
413 | ZXVert copy_vert = | |||
414 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | zxd.add_vertex(ZXType::ZSpider, 0, QuantumType::Classical); | |
415 |
1/2✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | boolean_outport_lookup.insert( | |
416 | {{vert_s, source_port}, {copy_vert, std::nullopt}}); | |||
417 | } | |||
418 |
3/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 2 times.
|
2/2✓ Decision 'true' taken 7 times.
✓ Decision 'false' taken 2 times.
|
9 | if (port_conditions[i]) { |
419 |
1/2✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
|
7 | vert_lookup.insert({{{vert, i}, ZXPortType::In}, and_inputs[i]}); | |
420 | } else { | |||
421 | ZXVert x_vert = | |||
422 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | zxd.add_vertex(ZXType::XSpider, 1, QuantumType::Classical); | |
423 | 2 | zxd.add_wire( | ||
424 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | and_inputs[i].first, x_vert, ZXWireType::Basic, | |
425 | 2 | QuantumType::Classical, and_inputs[i].second); | ||
426 |
1/2✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | vert_lookup.insert( | |
427 | 4 | {{{vert, i}, ZXPortType::In}, {x_vert, std::nullopt}}); | ||
428 | } | |||
429 | } | |||
430 | 6 | break; | ||
431 | 6 | } | ||
432 |
1/1✓ Decision 'true' taken 3 times.
|
3 | default: | |
433 |
2/4✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
1/2✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
|
3 | if (is_box_type(op->get_type())) { |
434 | EdgeVec b_in_holes = | |||
435 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.get_in_edges_of_type(vert, EdgeType::Boolean); | |
436 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
|
3 | if (b_in_holes.size() > 0) { |
437 | ✗ | throw Unsupported("Cannot convert box type: " + op->get_name()); | ||
438 | } | |||
439 | 3 | const Box& b = static_cast<const Box&>(*op); | ||
440 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
3 | Circuit replacement = *b.to_circuit(); | |
441 | // First, add the converted box to diagram. | |||
442 | BoundaryVertMap box_bm = | |||
443 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circuit_to_zx_recursive(replacement, zxd, false); | |
444 | // Then, map the vertports in the box boundary to zx nodes. | |||
445 | // Assume that a box can't have Boolean input edges, and all Boolean | |||
446 | // output edges share ports with Classical edges. Therefore we don't | |||
447 | // have to map Boolean vertports. | |||
448 | EdgeVec q_in_holes = | |||
449 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.get_in_edges_of_type(vert, EdgeType::Quantum); | |
450 | EdgeVec q_out_holes = | |||
451 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.get_out_edges_of_type(vert, EdgeType::Quantum); | |
452 | EdgeVec c_in_holes = | |||
453 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.get_in_edges_of_type(vert, EdgeType::Classical); | |
454 | EdgeVec c_out_holes = | |||
455 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | circ.get_out_edges_of_type(vert, EdgeType::Classical); | |
456 | ||||
457 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 3 times.
|
11 | for (unsigned i = 0; i < q_in_holes.size(); i++) { |
458 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | port_t port = circ.get_target_port(q_in_holes[i]); | |
459 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | Vertex inp = replacement.get_in(Qubit(i)); | |
460 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
16 | vert_lookup.insert( | |
461 | 16 | {{{vert, port}, ZXPortType::In}, | ||
462 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | {box_bm.right.at(inp), std::nullopt}}); | |
463 | } | |||
464 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 3 times.
|
11 | for (unsigned i = 0; i < q_out_holes.size(); i++) { |
465 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | port_t port = circ.get_source_port(q_out_holes[i]); | |
466 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | Vertex outp = replacement.get_out(Qubit(i)); | |
467 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
16 | vert_lookup.insert( | |
468 | 16 | {{{vert, port}, ZXPortType::Out}, | ||
469 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | {box_bm.right.at(outp), std::nullopt}}); | |
470 | } | |||
471 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
|
3 | for (unsigned i = 0; i < c_in_holes.size(); i++) { |
472 | ✗ | port_t port = circ.get_target_port(c_in_holes[i]); | ||
473 | ✗ | Vertex inp = replacement.get_in(Bit(i)); | ||
474 | ✗ | vert_lookup.insert( | ||
475 | ✗ | {{{vert, port}, ZXPortType::In}, | ||
476 | ✗ | {box_bm.right.at(inp), std::nullopt}}); | ||
477 | } | |||
478 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 3 times.
|
3 | for (unsigned i = 0; i < c_out_holes.size(); i++) { |
479 | ✗ | port_t port = circ.get_source_port(c_out_holes[i]); | ||
480 | ✗ | Vertex outp = replacement.get_out(Bit(i)); | ||
481 | ✗ | vert_lookup.insert( | ||
482 | ✗ | {{{vert, port}, ZXPortType::Out}, | ||
483 | ✗ | {box_bm.right.at(outp), std::nullopt}}); | ||
484 | } | |||
485 | 3 | } else { | ||
486 | ✗ | throw Unsupported( | ||
487 | ✗ | "Cannot convert gate type: " + op->get_name() + | ||
488 | " to a ZX node, try rebase the gates to use Rx, Rz, " | |||
489 | "X, Z, H, CZ " | |||
490 | ✗ | "or CX. \n"); | ||
491 | } | |||
492 | 17 | } | ||
493 |
2/2✓ Branch 1 taken 204 times.
✓ Branch 2 taken 17 times.
|
221 | } | |
494 | ||||
495 | // Connect the ZX nodes | |||
496 |
12/18✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 183 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 220 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 183 times.
✓ Branch 13 taken 37 times.
✓ Branch 15 taken 183 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 183 times.
✓ Branch 18 taken 37 times.
✓ Branch 20 taken 75 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 37 times.
✓ Branch 23 taken 38 times.
|
258 | BGL_FORALL_EDGES(edge, circ.dag, DAG) { | |
497 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | Vertex v_s = circ.source(edge); | |
498 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | Vertex v_t = circ.target(edge); | |
499 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | port_t p_s = circ.get_source_port(edge); | |
500 |
1/2✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
|
183 | port_t p_t = circ.get_target_port(edge); | |
501 | // Handle Spiderless ops | |||
502 |
4/6✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 153 times.
|
2/2✓ Decision 'true' taken 30 times.
✓ Decision 'false' taken 153 times.
|
183 | if (is_spiderless_optype(circ.get_OpType_from_Vertex(v_s))) { |
503 | // We only handle in-edges | |||
504 | 30 | continue; | ||
505 | } | |||
506 |
4/6✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 153 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 138 times.
|
2/2✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 138 times.
|
153 | if (is_spiderless_optype(circ.get_OpType_from_Vertex(v_t))) { |
507 | // Traverse the path to find the next non-spiderless op | |||
508 | 15 | Edge next_e = edge; | ||
509 | do { | |||
510 |
3/4✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 18 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 18 times.
|
30 | if (circ.get_OpType_from_Vertex(v_t) == OpType::SWAP) { |
511 | 12 | next_e = circ.get_nth_out_edge( | ||
512 |
2/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
12 | v_t, (circ.get_target_port(next_e) + 1) % 2); | |
513 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | v_t = circ.target(next_e); | |
514 | } else { | |||
515 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | std::tie(v_t, next_e) = circ.get_next_pair(v_t, next_e); | |
516 | } | |||
517 |
4/6✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 15 times.
|
0/1? Decision couldn't be analyzed.
|
30 | } while (is_spiderless_optype(circ.get_OpType_from_Vertex(v_t))); |
518 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | p_t = circ.get_target_port(next_e); | |
519 | } | |||
520 | ||||
521 | ZXVertPort zx_vp_s = | |||
522 |
1/2✓ Branch 3 taken 153 times.
✗ Branch 4 not taken.
|
153 | vert_lookup.at(TypedVertPort(VertPort(v_s, p_s), ZXPortType::Out)); | |
523 | ZXVertPort zx_vp_t = | |||
524 |
1/2✓ Branch 3 taken 153 times.
✗ Branch 4 not taken.
|
153 | vert_lookup.at(TypedVertPort(VertPort(v_t, p_t), ZXPortType::In)); | |
525 |
3/4✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 29 times.
|
2/2✓ Decision 'true' taken 124 times.
✓ Decision 'false' taken 29 times.
|
153 | if (circ.get_edgetype(edge) == EdgeType::Quantum) { |
526 |
1/2✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
|
124 | zxd.add_wire( | |
527 | zx_vp_s.first, zx_vp_t.first, ZXWireType::Basic, QuantumType::Quantum, | |||
528 | zx_vp_s.second, zx_vp_t.second); | |||
529 | } else { | |||
530 |
1/2✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
29 | auto bool_it = boolean_outport_lookup.find(VertPort(v_s, p_s)); | |
531 |
2/2✓ Branch 2 taken 12 times.
✓ Branch 3 taken 17 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 17 times.
|
29 | if (bool_it == boolean_outport_lookup.end()) { |
532 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | zxd.add_wire( | |
533 | zx_vp_s.first, zx_vp_t.first, ZXWireType::Basic, | |||
534 | QuantumType::Classical, zx_vp_s.second, zx_vp_t.second); | |||
535 | } else { | |||
536 | // If the source port is boolean, then connect the copy spider to the | |||
537 | // source vertex. All out-edges originated from the source port should | |||
538 | // be connected to the copy spider. | |||
539 |
3/4✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 9 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 9 times.
|
17 | if (zxd.degree(bool_it->second.first) == 0) { |
540 | 8 | zxd.add_wire( | ||
541 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | zx_vp_s.first, bool_it->second.first, ZXWireType::Basic, | |
542 | 8 | QuantumType::Classical, zx_vp_s.second, bool_it->second.second); | ||
543 | } | |||
544 | 17 | zxd.add_wire( | ||
545 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | bool_it->second.first, zx_vp_t.first, ZXWireType::Basic, | |
546 | 17 | QuantumType::Classical, bool_it->second.second, zx_vp_t.second); | ||
547 | } | |||
548 | } | |||
549 | } | |||
550 | 76 | return bmap; | ||
551 | 38 | } | ||
552 | ||||
553 | 29 | std::pair<ZXDiagram, BoundaryVertMap> circuit_to_zx(const Circuit& circ) { | ||
554 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | ZXDiagram zxd; | |
555 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | BoundaryVertMap bmap = circuit_to_zx_recursive(circ, zxd, true); | |
556 | // Remove internal boundary vertices produced by the recursion | |||
557 |
1/2✓ Branch 3 taken 29 times.
✗ Branch 4 not taken.
|
29 | ZXVertVec true_boundary = zxd.get_boundary(); | |
558 | 29 | ZXVertIterator vi, vi_end, next; | ||
559 |
2/4✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 29 times.
✗ Branch 6 not taken.
|
29 | tie(vi, vi_end) = boost::vertices(*zxd.get_graph()); | |
560 |
2/2✓ Branch 1 taken 349 times.
✓ Branch 2 taken 29 times.
|
2/2✓ Decision 'true' taken 349 times.
✓ Decision 'false' taken 29 times.
|
378 | for (next = vi; vi != vi_end; vi = next) { |
561 | 349 | ++next; | ||
562 |
1/2✓ Branch 2 taken 349 times.
✗ Branch 3 not taken.
|
2/2✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 317 times.
|
349 | if ((zxd.get_zxtype(*vi) == ZXType::Input || |
563 |
7/8✓ Branch 0 taken 272 times.
✓ Branch 1 taken 77 times.
✓ Branch 4 taken 272 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 77 times.
✓ Branch 7 taken 195 times.
✓ Branch 8 taken 32 times.
✓ Branch 9 taken 122 times.
|
503 | zxd.get_zxtype(*vi) == ZXType::Output) && | |
564 |
1/2✓ Branch 4 taken 154 times.
✗ Branch 5 not taken.
|
154 | std::find(true_boundary.begin(), true_boundary.end(), *vi) == | |
565 |
2/2✓ Branch 1 taken 32 times.
✓ Branch 2 taken 317 times.
|
503 | true_boundary.end()) { | |
566 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | WireVec adj_wires = zxd.adj_wires(*vi); | |
567 | TKET_ASSERT(adj_wires.size() == 2); | |||
568 | TKET_ASSERT(zxd.get_qtype(adj_wires[0]) == zxd.get_qtype(adj_wires[1])); | |||
569 |
3/108✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 32 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 75 not taken.
✗ Branch 76 not taken.
✗ Branch 78 not taken.
✗ Branch 79 not taken.
✗ Branch 81 not taken.
✗ Branch 82 not taken.
✗ Branch 84 not taken.
✗ Branch 85 not taken.
✗ Branch 87 not taken.
✗ Branch 88 not taken.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 100 not taken.
✗ Branch 101 not taken.
✗ Branch 103 not taken.
✗ Branch 104 not taken.
✗ Branch 106 not taken.
✗ Branch 107 not taken.
✗ Branch 109 not taken.
✗ Branch 110 not taken.
✗ Branch 112 not taken.
✗ Branch 113 not taken.
✗ Branch 116 not taken.
✗ Branch 117 not taken.
✗ Branch 120 not taken.
✗ Branch 121 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✗ Branch 129 not taken.
✗ Branch 130 not taken.
✗ Branch 132 not taken.
✗ Branch 133 not taken.
✗ Branch 135 not taken.
✗ Branch 136 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 141 not taken.
✗ Branch 142 not taken.
✗ Branch 144 not taken.
✗ Branch 145 not taken.
✗ Branch 147 not taken.
✗ Branch 148 not taken.
✗ Branch 150 not taken.
✗ Branch 151 not taken.
✗ Branch 153 not taken.
✗ Branch 154 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✗ Branch 162 not taken.
✗ Branch 163 not taken.
✗ Branch 165 not taken.
✗ Branch 166 not taken.
✗ Branch 169 not taken.
✗ Branch 170 not taken.
✗ Branch 173 not taken.
✗ Branch 174 not taken.
✗ Branch 176 not taken.
✗ Branch 177 not taken.
|
32 | TKET_ASSERT( | |
570 | zxd.get_wire_type(adj_wires[0]) == zxd.get_wire_type(adj_wires[1])); | |||
571 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | ZXVertVec neighbours = zxd.neighbours(*vi); | |
572 |
3/6✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 32 times.
✗ Branch 10 not taken.
|
128 | zxd.add_wire( | |
573 | 64 | neighbours[0], neighbours[1], zxd.get_wire_type(adj_wires[0]), | ||
574 | 32 | zxd.get_qtype(adj_wires[0])); | ||
575 |
1/2✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
32 | zxd.remove_vertex(*vi); | |
576 | 32 | } | ||
577 | } | |||
578 |
1/2✓ Branch 3 taken 29 times.
✗ Branch 4 not taken.
|
58 | return {std::move(zxd), std::move(bmap)}; | |
579 | 29 | } | ||
580 | ||||
581 | 50 | void clean_frontier( | ||
582 | ZXDiagram& diag, ZXVertVec& frontier, Circuit& circ, | |||
583 | std::map<ZXVert, unsigned>& qubit_map) { | |||
584 | 50 | std::set<ZXVert> frontier_lookup; | ||
585 | 50 | std::list<std::pair<ZXVert, ZXVert>> czs; | ||
586 |
2/2✓ Branch 5 taken 205 times.
✓ Branch 6 taken 50 times.
|
2/2✓ Decision 'true' taken 205 times.
✓ Decision 'false' taken 50 times.
|
255 | for (const ZXVert& f : frontier) { |
587 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | frontier_lookup.insert(f); | |
588 |
3/4✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 631 times.
✓ Branch 9 taken 205 times.
|
0/1? Decision couldn't be analyzed.
|
836 | for (const Wire& w : diag.adj_wires(f)) { |
589 |
1/2✓ Branch 1 taken 631 times.
✗ Branch 2 not taken.
|
631 | ZXVert n = diag.other_end(w, f); | |
590 |
3/4✓ Branch 1 taken 631 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 205 times.
✓ Branch 4 taken 426 times.
|
2/2✓ Decision 'true' taken 205 times.
✓ Decision 'false' taken 426 times.
|
631 | if (diag.get_zxtype(n) == ZXType::Output) { |
591 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | unsigned q = qubit_map.at(n); | |
592 |
3/4✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 157 times.
|
2/2✓ Decision 'true' taken 48 times.
✓ Decision 'false' taken 157 times.
|
205 | if (diag.get_wire_type(w) == ZXWireType::H) { |
593 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | diag.set_wire_type(w, ZXWireType::Basic); | |
594 |
2/4✓ Branch 3 taken 48 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 48 times.
✗ Branch 7 not taken.
|
48 | circ.add_op<unsigned>(OpType::H, {q}); | |
595 | } | |||
596 |
3/7✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 167 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
205 | switch (diag.get_zxtype(f)) { | |
597 |
0/1✗ Decision 'true' not taken.
|
✗ | case ZXType::Input: { | |
598 | ✗ | break; | ||
599 | } | |||
600 |
1/1✓ Decision 'true' taken 38 times.
|
38 | case ZXType::XY: { | |
601 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | const PhasedGen& f_gen = diag.get_vertex_ZXGen<PhasedGen>(f); | |
602 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | Expr ph = f_gen.get_param(); | |
603 |
3/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 17 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 17 times.
|
38 | if (!equiv_0(ph)) { |
604 |
3/6✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 21 times.
✗ Branch 10 not taken.
|
21 | circ.add_op<unsigned>(OpType::U1, -ph, {q}); | |
605 | } | |||
606 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | diag.set_vertex_ZXGen_ptr( | |
607 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
76 | f, ZXGen::create_gen(ZXType::PX, QuantumType::Quantum)); | |
608 | 38 | break; | ||
609 | 38 | } | ||
610 |
1/1✓ Decision 'true' taken 167 times.
|
167 | case ZXType::PX: { | |
611 |
1/2✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
|
167 | const CliffordGen& f_gen = diag.get_vertex_ZXGen<CliffordGen>(f); | |
612 |
2/4✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 167 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 167 times.
|
167 | if (f_gen.get_param()) { |
613 | ✗ | circ.add_op<unsigned>(OpType::Z, {q}); | ||
614 | ✗ | diag.set_vertex_ZXGen_ptr( | ||
615 | ✗ | f, ZXGen::create_gen(ZXType::PX, QuantumType::Quantum)); | ||
616 | } | |||
617 | 167 | break; | ||
618 | } | |||
619 |
0/1✗ Decision 'true' not taken.
|
✗ | case ZXType::PY: { | |
620 | ✗ | const CliffordGen& f_gen = diag.get_vertex_ZXGen<CliffordGen>(f); | ||
621 | ✗ | circ.add_op<unsigned>( | ||
622 | ✗ | f_gen.get_param() ? OpType::S : OpType::Sdg, {q}); | ||
623 | ✗ | diag.set_vertex_ZXGen_ptr( | ||
624 | ✗ | f, ZXGen::create_gen(ZXType::PX, QuantumType::Quantum)); | ||
625 | ✗ | break; | ||
626 | } | |||
627 |
0/1✗ Decision 'true' not taken.
|
✗ | default: | |
628 | ✗ | throw ZXError( | ||
629 | "Error during extraction from ZX diagram: unexpected ZXType in " | |||
630 | ✗ | "frontier"); | ||
631 | } | |||
632 |
3/4✓ Branch 2 taken 426 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✓ Branch 6 taken 398 times.
|
2/2✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 398 times.
|
426 | } else if (frontier_lookup.find(n) != frontier_lookup.end()) { |
633 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | czs.push_back({f, n}); | |
634 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | diag.remove_wire(w); | |
635 | } | |||
636 | 205 | } | ||
637 | } | |||
638 |
2/2✓ Branch 4 taken 28 times.
✓ Branch 5 taken 50 times.
|
2/2✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 50 times.
|
78 | for (const std::pair<ZXVert, ZXVert>& pair : czs) { |
639 |
2/4✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
|
56 | circ.add_op<unsigned>( | |
640 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | OpType::CZ, {qubit_map.at(pair.first), qubit_map.at(pair.second)}); | |
641 | } | |||
642 | 100 | ZXVertVec new_frontier; | ||
643 |
2/2✓ Branch 5 taken 205 times.
✓ Branch 6 taken 50 times.
|
2/2✓ Decision 'true' taken 205 times.
✓ Decision 'false' taken 50 times.
|
255 | for (const ZXVert& f : frontier) { |
644 | 205 | bool removed = false; | ||
645 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | ZXVertVec ns = diag.neighbours(f); | |
646 |
2/2✓ Branch 1 taken 96 times.
✓ Branch 2 taken 109 times.
|
2/2✓ Decision 'true' taken 96 times.
✓ Decision 'false' taken 109 times.
|
205 | if (ns.size() == 2) { |
647 |
2/4✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 96 times.
✗ Branch 5 not taken.
|
96 | ZXType nt0 = diag.get_zxtype(ns.at(0)); | |
648 |
2/4✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 96 times.
✗ Branch 5 not taken.
|
96 | ZXType nt1 = diag.get_zxtype(ns.at(1)); | |
649 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 27 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 88 times.
|
96 | if ((nt0 == ZXType::Input && nt1 == ZXType::Output) || |
650 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 61 times.
|
69 | (nt0 == ZXType::Output && nt1 == ZXType::Input)) { | |
651 |
3/6✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
|
8 | diag.add_wire(ns.at(0), ns.at(1)); | |
652 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | diag.remove_vertex(f); | |
653 | 8 | removed = true; | ||
654 | } | |||
655 | } | |||
656 |
6/8✓ Branch 0 taken 197 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 197 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 197 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 197 times.
✓ Branch 8 taken 8 times.
|
2/2✓ Decision 'true' taken 197 times.
✓ Decision 'false' taken 8 times.
|
205 | if (!removed && diag.get_zxtype(f) != ZXType::Input) |
657 |
1/2✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
|
197 | new_frontier.push_back(f); | |
658 | 205 | } | ||
659 |
1/2✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
|
50 | frontier = new_frontier; | |
660 | 50 | } | ||
661 | ||||
662 | 38 | ZXVertSeqSet neighbours_of_frontier( | ||
663 | const ZXDiagram& diag, const ZXVertVec& frontier) { | |||
664 | 38 | ZXVertSeqSet n_set; | ||
665 |
2/2✓ Branch 5 taken 147 times.
✓ Branch 6 taken 38 times.
|
2/2✓ Decision 'true' taken 147 times.
✓ Decision 'false' taken 38 times.
|
185 | for (const ZXVert& f : frontier) { |
666 |
3/4✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 395 times.
✓ Branch 9 taken 147 times.
|
0/1? Decision couldn't be analyzed.
|
542 | for (const Wire& w : diag.adj_wires(f)) { |
667 |
1/2✓ Branch 1 taken 395 times.
✗ Branch 2 not taken.
|
395 | ZXVert n = diag.other_end(w, f); | |
668 |
1/2✓ Branch 1 taken 395 times.
✗ Branch 2 not taken.
|
395 | ZXType n_type = diag.get_zxtype(n); | |
669 |
3/4✓ Branch 0 taken 248 times.
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 248 times.
|
2/2✓ Decision 'true' taken 248 times.
✓ Decision 'false' taken 147 times.
|
395 | if (n_type == ZXType::Output || n_type == ZXType::Input) continue; |
670 |
1/2✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
|
248 | n_set.insert(n); | |
671 | 147 | } | ||
672 | } | |||
673 | 38 | return n_set; | ||
674 | } | |||
675 | ||||
676 | 50 | static void bipartite_complementation( | ||
677 | ZXDiagram& diag, const ZXVertSeqSet& sa, const ZXVertSeqSet& sb) { | |||
678 |
5/8✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 40 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 90 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 40 times.
✓ Branch 13 taken 50 times.
|
0/1? Decision couldn't be analyzed.
|
90 | for (const ZXVert& a : sa.get<TagSeq>()) { |
679 |
5/8✓ Branch 4 taken 161 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 161 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 201 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 161 times.
✓ Branch 13 taken 40 times.
|
0/1? Decision couldn't be analyzed.
|
201 | for (const ZXVert& b : sb.get<TagSeq>()) { |
680 |
1/2✓ Branch 1 taken 161 times.
✗ Branch 2 not taken.
|
161 | std::optional<Wire> wire = diag.wire_between(a, b); | |
681 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 83 times.
|
2/2✓ Decision 'true' taken 78 times.
✓ Decision 'false' taken 83 times.
|
161 | if (wire) |
682 |
1/2✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | diag.remove_wire(*wire); | |
683 | else | |||
684 |
1/2✓ Branch 3 taken 83 times.
✗ Branch 4 not taken.
|
83 | diag.add_wire(a, b, ZXWireType::H); | |
685 | } | |||
686 | } | |||
687 | 50 | } | ||
688 | ||||
689 | 100 | void extend_if_input( | ||
690 | ZXDiagram& diag, const ZXVert& v, std::map<ZXVert, ZXVert>& input_qubits) { | |||
691 |
1/2✓ Branch 1 taken 100 times.
✗ Branch 2 not taken.
|
100 | std::map<ZXVert, ZXVert>::iterator found = input_qubits.find(v); | |
692 |
2/2✓ Branch 2 taken 5 times.
✓ Branch 3 taken 95 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 95 times.
|
100 | if (found != input_qubits.end()) { |
693 | 5 | ZXVert in = found->second; | ||
694 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | ZXVert ext0 = diag.add_vertex(ZXType::XY); | |
695 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | ZXVert ext1 = diag.add_vertex(ZXType::XY); | |
696 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
|
5 | diag.remove_wire(diag.adj_wires(in).at(0)); | |
697 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | diag.add_wire(in, ext0); | |
698 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | diag.add_wire(ext0, ext1, ZXWireType::H); | |
699 |
1/2✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | diag.add_wire(ext1, v, ZXWireType::H); | |
700 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | input_qubits.erase(found); | |
701 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | input_qubits.insert({ext0, in}); | |
702 | } | |||
703 | 100 | } | ||
704 | ||||
705 | 38 | bool remove_all_gadgets( | ||
706 | ZXDiagram& diag, const ZXVertVec& frontier, | |||
707 | std::map<ZXVert, ZXVert>& input_qubits) { | |||
708 | 38 | bool removed_gadget = false; | ||
709 |
2/2✓ Branch 5 taken 147 times.
✓ Branch 6 taken 38 times.
|
2/2✓ Decision 'true' taken 147 times.
✓ Decision 'false' taken 38 times.
|
185 | for (const ZXVert& f : frontier) { |
710 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | ZXVertVec f_ns = diag.neighbours(f); | |
711 | 147 | std::optional<ZXVert> found_output; | ||
712 |
1/2✓ Branch 5 taken 282 times.
✗ Branch 6 not taken.
|
1/2✓ Decision 'true' taken 282 times.
✗ Decision 'false' not taken.
|
282 | for (const ZXVert& n : f_ns) { |
713 | // Each frontier vertex is connected to a unique output, find it | |||
714 |
3/4✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 147 times.
✓ Branch 4 taken 135 times.
|
2/2✓ Decision 'true' taken 147 times.
✓ Decision 'false' taken 135 times.
|
282 | if (diag.get_zxtype(n) == ZXType::Output) { |
715 | 147 | found_output = n; | ||
716 | 147 | break; | ||
717 | } | |||
718 | } | |||
719 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 147 times.
|
147 | if (!found_output) |
720 | ✗ | throw ZXError( | ||
721 | "Error during extraction from ZXDiagram: frontier vertex not " | |||
722 | ✗ | "adjacent to an output"); | ||
723 | 147 | ZXVert o = *found_output; | ||
724 |
2/2✓ Branch 5 taken 385 times.
✓ Branch 6 taken 137 times.
|
2/2✓ Decision 'true' taken 385 times.
✓ Decision 'false' taken 137 times.
|
522 | for (const ZXVert& n : f_ns) { |
725 |
3/4✓ Branch 1 taken 385 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 375 times.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 375 times.
|
385 | if (diag.get_zxtype(n) == ZXType::YZ) { |
726 | // Pivot | |||
727 | // Identify three subsets of neighbours | |||
728 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | ZXVertSeqSet excl_f; | |
729 | // Need to recalculate neighbours rather than use f_ns as we might have | |||
730 | // extended | |||
731 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | extend_if_input(diag, f, input_qubits); | |
732 |
3/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 65 times.
✓ Branch 9 taken 10 times.
|
0/1? Decision couldn't be analyzed.
|
75 | for (const ZXVert& n : diag.neighbours(f)) { |
733 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | extend_if_input(diag, n, input_qubits); | |
734 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | excl_f.insert(n); | |
735 | 10 | } | ||
736 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | excl_f.get<TagKey>().erase(n); | |
737 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | excl_f.get<TagKey>().erase(o); | |
738 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | ZXVertSeqSet excl_n, joint; | |
739 | 10 | auto& lookup_f = excl_f.get<TagKey>(); | ||
740 |
3/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 25 times.
✓ Branch 9 taken 10 times.
|
0/1? Decision couldn't be analyzed.
|
35 | for (const ZXVert& nn : diag.neighbours(n)) { |
741 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | extend_if_input(diag, nn, input_qubits); | |
742 |
4/6✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 20 times.
|
2/2✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 20 times.
|
25 | if (lookup_f.find(nn) != lookup_f.end()) |
743 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | joint.insert(nn); | |
744 | else | |||
745 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | excl_n.insert(nn); | |
746 | 10 | } | ||
747 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | excl_n.get<TagKey>().erase(f); | |
748 |
5/8✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✓ Branch 13 taken 10 times.
|
0/1? Decision couldn't be analyzed.
|
15 | for (const ZXVert& nn : joint.get<TagSeq>()) |
749 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | excl_f.get<TagKey>().erase(nn); | |
750 | // The is_MBQC check in zx_to_circuit guarantees QuantumType::Quantum | |||
751 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | bipartite_complementation(diag, joint, excl_n); | |
752 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | bipartite_complementation(diag, joint, excl_f); | |
753 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | bipartite_complementation(diag, excl_n, excl_f); | |
754 | // In place of switching vertices f and n, we invert their | |||
755 | // connectivities | |||
756 |
1/2✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
|
10 | excl_n.insert(excl_f.begin(), excl_f.end()); | |
757 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
|
10 | bipartite_complementation(diag, {f}, excl_n); | |
758 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
|
10 | bipartite_complementation(diag, {n}, excl_n); | |
759 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | Wire ow = *diag.wire_between(f, o); | |
760 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | diag.set_wire_type( | |
761 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
|
10 | ow, (diag.get_wire_type(ow) == ZXWireType::Basic) | |
762 | ? ZXWireType::H | |||
763 | : ZXWireType::Basic); | |||
764 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | const PhasedGen& yz_gen = diag.get_vertex_ZXGen<PhasedGen>(n); | |
765 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | diag.set_vertex_ZXGen_ptr( | |
766 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
20 | n, ZXGen::create_gen( | |
767 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
20 | ZXType::XY, -yz_gen.get_param(), QuantumType::Quantum)); | |
768 |
5/8✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✓ Branch 13 taken 10 times.
|
0/1? Decision couldn't be analyzed.
|
15 | for (const ZXVert& nn : joint.get<TagSeq>()) { |
769 | 5 | ZXGen_ptr new_gen; | ||
770 |
2/7✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
5 | switch (diag.get_zxtype(nn)) { | |
771 |
1/1✓ Decision 'true' taken 5 times.
|
5 | case ZXType::XY: { | |
772 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | const PhasedGen& ph_gen = diag.get_vertex_ZXGen<PhasedGen>(nn); | |
773 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
10 | new_gen = ZXGen::create_gen( | |
774 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
|
15 | ZXType::XY, ph_gen.get_param() + 1., QuantumType::Quantum); | |
775 | 5 | break; | ||
776 | } | |||
777 | ✗ | case ZXType::PX: | ||
778 | case ZXType::PY: { | |||
779 | const CliffordGen& cl_gen = | |||
780 | ✗ | diag.get_vertex_ZXGen<CliffordGen>(nn); | ||
781 | ✗ | new_gen = ZXGen::create_gen( | ||
782 | ✗ | cl_gen.get_type(), !cl_gen.get_param(), QuantumType::Quantum); | ||
783 | ✗ | break; | ||
784 | } | |||
785 | ✗ | case ZXType::XZ: | ||
786 | case ZXType::YZ: { | |||
787 | ✗ | const PhasedGen& ph_gen = diag.get_vertex_ZXGen<PhasedGen>(nn); | ||
788 | ✗ | new_gen = ZXGen::create_gen( | ||
789 | ✗ | ph_gen.get_type(), -ph_gen.get_param(), QuantumType::Quantum); | ||
790 | ✗ | break; | ||
791 | } | |||
792 |
0/1✗ Decision 'true' not taken.
|
✗ | case ZXType::PZ: { | |
793 | ✗ | new_gen = diag.get_vertex_ZXGen_ptr(nn); | ||
794 | ✗ | break; | ||
795 | } | |||
796 |
0/1✗ Decision 'true' not taken.
|
✗ | default: | |
797 | ✗ | throw ZXError( | ||
798 | "Error during extraction from ZX diagram: unexpected ZXType " | |||
799 | ✗ | "during local complementation"); | ||
800 | } | |||
801 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | diag.set_vertex_ZXGen_ptr(nn, new_gen); | |
802 | 5 | } | ||
803 | 10 | removed_gadget = true; | ||
804 | 10 | break; | ||
805 | 10 | } | ||
806 | } | |||
807 | 147 | } | ||
808 | 38 | return removed_gadget; | ||
809 | } | |||
810 | ||||
811 | 2 | Circuit zx_to_circuit(const ZXDiagram& d) { | ||
812 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ZXDiagram diag = d; | |
813 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (!diag.is_MBQC()) |
814 | ✗ | throw ZXError("Can only extract a circuit from a ZX diagram in MBQC form"); | ||
815 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | ZXVertVec ins = diag.get_boundary(ZXType::Input); | |
816 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | ZXVertVec outs = diag.get_boundary(ZXType::Output); | |
817 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (ins.size() != outs.size()) |
818 | ✗ | throw ZXError("Can only extract a circuit from a unitary ZX diagram"); | ||
819 | ||||
820 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
2 | Circuit circ(ins.size()); | |
821 | ||||
822 | 2 | ZXVertVec frontier; | ||
823 | 2 | std::map<ZXVert, unsigned> qubit_map; | ||
824 | 2 | unsigned q = 0; | ||
825 |
2/2✓ Branch 4 taken 8 times.
✓ Branch 5 taken 2 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 2 times.
|
10 | for (const ZXVert& o : outs) { |
826 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert f_i = diag.neighbours(o).at(0); | |
827 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | frontier.push_back(f_i); | |
828 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | qubit_map.insert({o, q}); | |
829 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | qubit_map.insert({f_i, q}); | |
830 | 8 | ++q; | ||
831 | } | |||
832 | 2 | std::map<ZXVert, ZXVert> input_qubits; | ||
833 |
2/2✓ Branch 4 taken 8 times.
✓ Branch 5 taken 2 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 2 times.
|
10 | for (const ZXVert& i : ins) |
834 |
3/6✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
|
8 | input_qubits.insert({diag.neighbours(i).at(0), i}); | |
835 | ||||
836 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | clean_frontier(diag, frontier, circ, qubit_map); | |
837 |
2/2✓ Branch 1 taken 38 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 38 times.
✓ Decision 'false' taken 2 times.
|
40 | while (!frontier.empty()) { |
838 |
3/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 28 times.
|
2/2✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 28 times.
|
38 | if (remove_all_gadgets(diag, frontier, input_qubits)) { |
839 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | clean_frontier(diag, frontier, circ, qubit_map); | |
840 | } | |||
841 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | ZXVertSeqSet neighbours = neighbours_of_frontier(diag, frontier); | |
842 |
3/6✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 38 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 38 times.
✗ Branch 11 not taken.
|
114 | boost::bimap<ZXVert, unsigned> correctors, preserve, ys; | |
843 | 38 | ZXVertVec to_solve; | ||
844 |
2/2✓ Branch 5 taken 147 times.
✓ Branch 6 taken 38 times.
|
2/2✓ Decision 'true' taken 147 times.
✓ Decision 'false' taken 38 times.
|
185 | for (const ZXVert& f : frontier) { |
845 |
2/4✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 147 times.
✗ Branch 6 not taken.
|
1/2✓ Decision 'true' taken 147 times.
✗ Decision 'false' not taken.
|
147 | if (input_qubits.find(f) == input_qubits.end()) |
846 |
3/6✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 147 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 147 times.
✗ Branch 8 not taken.
|
147 | correctors.insert({f, (unsigned)correctors.size()}); | |
847 | } | |||
848 |
5/8✓ Branch 4 taken 176 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 176 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 214 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 176 times.
✓ Branch 13 taken 38 times.
|
0/1? Decision couldn't be analyzed.
|
214 | for (const ZXVert& n : neighbours.get<TagSeq>()) { |
849 |
1/2✓ Branch 1 taken 176 times.
✗ Branch 2 not taken.
|
176 | ZXType n_type = diag.get_zxtype(n); | |
850 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
176 | if (n_type == ZXType::XY || n_type == ZXType::PX || | |
851 | n_type == ZXType::PY) { | |||
852 |
3/6✓ Branch 1 taken 176 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 176 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 176 times.
✗ Branch 8 not taken.
|
176 | preserve.insert({n, (unsigned)preserve.size()}); | |
853 |
1/2✓ Branch 1 taken 176 times.
✗ Branch 2 not taken.
|
176 | to_solve.push_back(n); | |
854 | } | |||
855 | } | |||
856 | std::map<ZXVert, ZXVertSeqSet> candidates = | |||
857 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | Flow::gauss_solve_correctors(diag, correctors, preserve, to_solve, ys); | |
858 | ||||
859 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
|
38 | if (candidates.empty()) | |
860 | ✗ | throw ZXError( | ||
861 | "Error during extraction from ZX diagram: diagram does not have " | |||
862 | ✗ | "gflow"); | ||
863 | ||||
864 | 38 | unsigned min = UINT_MAX; | ||
865 | ZXVert best; | |||
866 |
2/2✓ Branch 5 taken 109 times.
✓ Branch 6 taken 38 times.
|
147 | for (const std::pair<const ZXVert, ZXVertSeqSet>& p : candidates) { | |
867 |
2/2✓ Branch 1 taken 51 times.
✓ Branch 2 taken 58 times.
|
109 | if (p.second.size() < min) { | |
868 | 51 | min = p.second.size(); | ||
869 | 51 | best = p.first; | ||
870 | } | |||
871 | } | |||
872 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
|
38 | ZXVertSeqSet g_best = candidates.at(best); | |
873 | ||||
874 |
1/2✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
38 | ZXVert f_to_isolate = g_best.get<TagSeq>().front(); | |
875 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | unsigned f_q = qubit_map.at(f_to_isolate); | |
876 |
5/8✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 41 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 79 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 41 times.
✓ Branch 12 taken 38 times.
|
79 | for (const ZXVert& f : g_best) { | |
877 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
|
41 | if (f != f_to_isolate) { | |
878 |
3/6✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
|
3 | circ.add_op<unsigned>(OpType::CX, {f_q, qubit_map.at(f)}); | |
879 | } | |||
880 | } | |||
881 | ZXVert out; | |||
882 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | Wire w_out; | |
883 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
|
53 | for (const Wire& w : diag.adj_wires(f_to_isolate)) { | |
884 |
1/2✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
|
53 | ZXVert n = diag.other_end(w, f_to_isolate); | |
885 |
3/4✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 15 times.
|
53 | if (diag.get_zxtype(n) == ZXType::Output) { | |
886 | 38 | out = n; | ||
887 | 38 | w_out = w; | ||
888 | 38 | break; | ||
889 | } | |||
890 | 38 | } | ||
891 |
1/2✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
|
76 | diag.add_wire( | |
892 | best, out, | |||
893 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
|
38 | (diag.get_wire_type(w_out) == ZXWireType::Basic) ? ZXWireType::H | |
894 | : ZXWireType::Basic); | |||
895 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | diag.remove_vertex(f_to_isolate); | |
896 |
2/4✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
|
38 | qubit_map.erase(qubit_map.find(f_to_isolate)); | |
897 |
1/2✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
38 | qubit_map.insert({best, f_q}); | |
898 |
1/2✓ Branch 3 taken 87 times.
✗ Branch 4 not taken.
|
87 | for (ZXVertVec::iterator it = frontier.begin(); it != frontier.end(); | |
899 | 49 | ++it) { | ||
900 |
2/2✓ Branch 1 taken 38 times.
✓ Branch 2 taken 49 times.
|
87 | if (*it == f_to_isolate) { | |
901 | 38 | *it = best; | ||
902 | 38 | break; | ||
903 | } | |||
904 | } | |||
905 | ||||
906 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | clean_frontier(diag, frontier, circ, qubit_map); | |
907 | 38 | } | ||
908 | ||||
909 | 2 | qubit_map_t qm; | ||
910 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
|
10 | for (unsigned i = 0; i < ins.size(); ++i) { | |
911 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ZXVert in = ins.at(i); | |
912 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ZXVert out = diag.neighbours(in).at(0); | |
913 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
|
8 | if (diag.get_zxtype(out) != ZXType::Output) | |
914 | ✗ | throw ZXError( | ||
915 | "Error during extraction from ZX diagram: input not adjacent to " | |||
916 | ✗ | "output after extracting"); | ||
917 |
4/8✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
|
8 | qm.insert({Qubit(qubit_map.at(out)), Qubit(i)}); | |
918 | } | |||
919 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | circ.permute_boundary_output(qm); | |
920 | ||||
921 | // Reverse gates in circuit (all gates added are self-transpose) | |||
922 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | return circ.transpose(); | |
923 | 2 | } | ||
924 | ||||
925 | } // namespace tket | |||
926 |