GCC Code Coverage Report


Directory: ./
File: ZX/ZXDExpansions.cpp
Date: 2022-10-15 05:10:18
Exec Total Coverage
Lines: 110 135 81.5%
Functions: 3 3 100.0%
Branches: 119 230 51.7%
Decisions: 33 41 80.5%

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 <tkassert/Assert.hpp>
16
17 #include "Utils/GraphHeaders.hpp"
18 #include "ZX/ZXDiagram.hpp"
19
20 namespace tket {
21
22 namespace zx {
23
24 enum class CPMDouble { Original, Conjugated };
25
26 struct CPMVert {
27 ZXVert vert;
28 CPMDouble conj;
29
30 310 bool operator<(const CPMVert& other) const {
31
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 184 times.
2/2
✓ Decision 'true' taken 126 times.
✓ Decision 'false' taken 184 times.
310 if (this->vert == other.vert)
32 126 return this->conj < other.conj;
33 else
34 184 return this->vert < other.vert;
35 }
36 };
37
38 2 ZXDiagram ZXDiagram::to_doubled_diagram() const {
39
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ZXDiagram doubled;
40 // map from vertex
41 2 std::map<CPMVert, ZXVert> iso;
42
43
7/8
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 2 times.
✓ Branch 9 taken 14 times.
✓ Branch 10 taken 2 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 2 times.
18 BGL_FORALL_VERTICES(v, *this->graph, ZXGraph) {
44
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 ZXGen_ptr op = this->get_vertex_ZXGen_ptr(v);
45
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 std::optional<QuantumType> qtype = op->get_qtype();
46
3/4
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 13 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 13 times.
14 if (op->get_type() == ZXType::ZXBox) {
47 1 const ZXBox& box = static_cast<const ZXBox&>(*op);
48
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 ZXGen_ptr new_op = std::make_shared<const ZXBox>(
49
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
3 box.get_diagram()->to_doubled_diagram());
50
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 ZXVert added = doubled.add_vertex(new_op);
51
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 iso.insert({{v, CPMDouble::Original}, added});
52 1 } else {
53 TKET_ASSERT(qtype.has_value());
54
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 3 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 3 times.
13 if (*qtype == QuantumType::Quantum) {
55 10 ZXGen_ptr orig_op, conj_op;
56
5/10
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
10 switch (op->get_type()) {
57 6 case ZXType::Input:
58 case ZXType::Output:
59 case ZXType::Open: {
60 6 orig_op = std::make_shared<const BoundaryGen>(
61
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 op->get_type(), QuantumType::Classical);
62 6 conj_op = orig_op;
63 6 break;
64 }
65 2 case ZXType::ZSpider:
66 case ZXType::XSpider:
67 case ZXType::XY:
68 case ZXType::YZ: {
69 2 const PhasedGen& bg = static_cast<const PhasedGen&>(*op);
70 2 orig_op = std::make_shared<const PhasedGen>(
71
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
4 op->get_type(), bg.get_param(), QuantumType::Classical);
72 2 conj_op = std::make_shared<const PhasedGen>(
73
4/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
4 op->get_type(), -bg.get_param(), QuantumType::Classical);
74 2 break;
75 }
76
0/1
✗ Decision 'true' not taken.
case ZXType::XZ: {
77 const PhasedGen& bg = static_cast<const PhasedGen&>(*op);
78 orig_op = std::make_shared<const PhasedGen>(
79 op->get_type(), bg.get_param(), QuantumType::Classical);
80 conj_op = orig_op;
81 break;
82 }
83 case ZXType::PX:
84 case ZXType::PZ: {
85 const CliffordGen& bg = static_cast<const CliffordGen&>(*op);
86 orig_op = std::make_shared<const CliffordGen>(
87 op->get_type(), bg.get_param(), QuantumType::Classical);
88 conj_op = orig_op;
89 break;
90 }
91
0/1
✗ Decision 'true' not taken.
case ZXType::PY: {
92 const CliffordGen& bg = static_cast<const CliffordGen&>(*op);
93 orig_op = std::make_shared<const CliffordGen>(
94 op->get_type(), bg.get_param(), QuantumType::Classical);
95 conj_op = std::make_shared<const CliffordGen>(
96 op->get_type(), !bg.get_param(), QuantumType::Classical);
97 break;
98 }
99
1/1
✓ Decision 'true' taken 1 times.
1 case ZXType::Hbox: {
100 1 const PhasedGen& bg = static_cast<const PhasedGen&>(*op);
101 1 orig_op = std::make_shared<const PhasedGen>(
102
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
2 op->get_type(), bg.get_param(), QuantumType::Classical);
103 1 conj_op = std::make_shared<const PhasedGen>(
104
3/6
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
2 op->get_type(), SymEngine::conjugate(bg.get_param()),
105
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 QuantumType::Classical);
106 1 break;
107 }
108
1/1
✓ Decision 'true' taken 1 times.
1 case ZXType::Triangle: {
109 1 orig_op = std::make_shared<const DirectedGen>(
110
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 ZXType::Triangle, QuantumType::Classical);
111 1 conj_op = orig_op;
112 1 break;
113 }
114
0/1
✗ Decision 'true' not taken.
default:
115 throw ZXError("Unrecognised ZXType in to_doubled_diagram()");
116 }
117
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 ZXVert orig = doubled.add_vertex(orig_op);
118
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 ZXVert conj = doubled.add_vertex(conj_op);
119
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 iso.insert({{v, CPMDouble::Original}, orig});
120
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 iso.insert({{v, CPMDouble::Conjugated}, conj});
121 10 } else {
122
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 ZXVert added = doubled.add_vertex(op);
123
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 iso.insert({{v, CPMDouble::Original}, added});
124 }
125 }
126 14 }
127
128
12/18
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 8 times.
✓ Branch 14 taken 1 times.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 8 times.
✓ Branch 19 taken 1 times.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 24 taken 2 times.
11 BGL_FORALL_EDGES(w, *this->graph, ZXGraph) {
129
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 WireProperties wp = this->get_wire_info(w);
130
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXVert s = source(w);
131
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXVert t = target(w);
132 8 std::optional<unsigned> new_s_port, new_t_port;
133
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXGen_ptr sgen = get_vertex_ZXGen_ptr(s);
134
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXGen_ptr tgen = get_vertex_ZXGen_ptr(t);
135 // Quantum ports on a ZXBox get mapped to two Classical ports
136
3/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 7 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 7 times.
8 if (sgen->get_type() == ZXType::ZXBox) {
137 1 const ZXBox& box = static_cast<const ZXBox&>(*sgen);
138
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<QuantumType> sig = box.get_signature();
139 1 unsigned p = 0;
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 for (unsigned i = 0; i < *wp.source_port; ++i) {
141
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (sig.at(i) == QuantumType::Quantum)
142 p += 2;
143 else
144 p += 1;
145 }
146 1 new_s_port = p;
147 1 }
148 // Other generators just get duplicated
149 else {
150 7 new_s_port = wp.source_port;
151 }
152 // Do the same for the target
153
3/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 7 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 7 times.
8 if (tgen->get_type() == ZXType::ZXBox) {
154 1 const ZXBox& box = static_cast<const ZXBox&>(*tgen);
155
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<QuantumType> sig = box.get_signature();
156 1 unsigned p = 0;
157
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 for (unsigned i = 0; i < *wp.target_port; ++i) {
158
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (sig.at(i) == QuantumType::Quantum)
159 1 p += 2;
160 else
161 p += 1;
162 }
163 1 new_t_port = p;
164 1 } else {
165 7 new_t_port = wp.target_port;
166 }
167 WireProperties new_wp{
168
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 wp.type, QuantumType::Classical, new_s_port, new_t_port};
169
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXVert new_s = iso.at({s, CPMDouble::Original});
170
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ZXVert new_t = iso.at({t, CPMDouble::Original});
171
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 doubled.add_wire(new_s, new_t, new_wp);
172 // Handle the second wire for expanding Quantum wires
173
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 2 times.
8 if (wp.qtype == QuantumType::Quantum) {
174 // For ZXBox, the conjugated port is the next one
175
3/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 1 times.
6 if (sgen->get_type() == ZXType::ZXBox) *new_wp.source_port += 1;
176 // For other generators, the conjugate is a new vertex
177
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 5 times.
✗ Decision 'false' not taken.
5 else if (sgen->get_qtype() == QuantumType::Quantum)
178
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 new_s = iso.at({s, CPMDouble::Conjugated});
179 // Do the same for the target
180
3/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 5 times.
6 if (tgen->get_type() == ZXType::ZXBox)
181 1 *new_wp.target_port += 1;
182
3/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 1 times.
5 else if (tgen->get_qtype() == QuantumType::Quantum)
183
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 new_t = iso.at({t, CPMDouble::Conjugated});
184
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 doubled.add_wire(new_s, new_t, new_wp);
185 }
186 8 }
187
188
2/2
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 2 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 2 times.
10 for (const ZXVert& b : boundary) {
189
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 doubled.boundary.push_back(iso.at({b, CPMDouble::Original}));
190
3/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 2 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 2 times.
8 if (get_qtype(b) == QuantumType::Quantum)
191
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 doubled.boundary.push_back(iso.at({b, CPMDouble::Conjugated}));
192 }
193
194 4 return doubled;
195 2 }
196
197 1 ZXDiagram ZXDiagram::to_quantum_embedding() const {
198 1 ZXDiagram embedding(*this);
199
2/2
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 1 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 1 times.
7 for (ZXVert& b : embedding.boundary) {
200
3/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 4 times.
6 if (embedding.get_qtype(b) == QuantumType::Classical) {
201 ZXVert new_b =
202
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 embedding.add_vertex(embedding.get_zxtype(b), QuantumType::Quantum);
203 4 ZXGen_ptr id = std::make_shared<const PhasedGen>(
204
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ZXType::ZSpider, 0., QuantumType::Classical);
205
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 embedding.set_vertex_ZXGen_ptr(b, id);
206
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 embedding.add_wire(new_b, b, ZXWireType::Basic, QuantumType::Quantum);
207 2 b = new_b;
208 2 }
209 }
210
211 1 return embedding;
212 }
213
214 } // namespace zx
215
216 } // namespace tket
217