GCC Code Coverage Report


Directory: ./
File: Circuit/macro_manipulation.cpp
Date: 2022-10-15 05:10:18
Exec Total Coverage
Lines: 442 478 92.5%
Functions: 25 25 100.0%
Branches: 590 1062 55.6%
Decisions: 7 18 38.9%

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 /////////////////////////////////////////////////////
16 // ALL METHODS TO PERFORM COMPLEX CIRCUIT MANIPULATION//
17 /////////////////////////////////////////////////////
18
19 #include <memory>
20 #include <tklog/TketLog.hpp>
21
22 #include "Circuit.hpp"
23 #include "Gate/Gate.hpp"
24 #include "Ops/ClassicalOps.hpp"
25 #include "Utils/UnitID.hpp"
26 namespace tket {
27
28 442892 vertex_map_t Circuit::copy_graph(
29 const Circuit& c2, BoundaryMerge boundary_merge,
30 OpGroupTransfer opgroup_transfer) {
31
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 222753 times.
✓ Branch 2 taken 220139 times.
✗ Branch 3 not taken.
442892 switch (opgroup_transfer) {
32
0/1
✗ Decision 'true' not taken.
case OpGroupTransfer::Preserve:
33 // Fail if any collisions.
34
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (const auto& opgroupsig : c2.opgroupsigs) {
35
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (opgroupsigs.find(opgroupsig.first) != opgroupsigs.end()) {
36 throw CircuitInvalidity("Name collision in inserted circuit");
37 }
38 }
39 // Add inserted opgroups to circuit.
40 opgroupsigs.insert(c2.opgroupsigs.begin(), c2.opgroupsigs.end());
41 break;
42
0/1
✗ Decision 'true' not taken.
222753 case OpGroupTransfer::Disallow:
43 // Fail if any opgroups.
44
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 222753 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 222753 times.
222753 if (!c2.opgroupsigs.empty()) {
45 throw CircuitInvalidity("Named op groups in inserted circuit");
46 }
47 222753 break;
48
0/1
✗ Decision 'true' not taken.
220139 case OpGroupTransfer::Merge:
49 // Fail if any mismatched signatures
50
2/2
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 220139 times.
2/2
✓ Decision 'true' taken 19 times.
✓ Decision 'false' taken 220139 times.
220158 for (const auto& opgroupsig : c2.opgroupsigs) {
51
3/4
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 11 times.
✓ Decision 'false' taken 8 times.
19 if (opgroupsigs.find(opgroupsig.first) != opgroupsigs.end()) {
52
3/6
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 11 times.
11 if (opgroupsigs[opgroupsig.first] != opgroupsig.second) {
53 throw CircuitInvalidity(
54 "Name signature mismatch in inserted circuit");
55 }
56 }
57 }
58 // Add inserted opgroups to circuit.
59 220139 opgroupsigs.insert(c2.opgroupsigs.begin(), c2.opgroupsigs.end());
60 220139 break;
61
0/1
✗ Decision 'true' not taken.
default:
62 TKET_ASSERT(opgroup_transfer == OpGroupTransfer::Remove);
63 // Ignore inserted opgroups
64 break;
65 }
66
67 442892 vertex_map_t isomap;
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 442892 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 442892 times.
442892 if (&c2 == this) {
69 throw Unsupported(
70 "Circuit Cannot currently copy itself using this method. Use * "
71 "instead\n");
72 }
73
7/8
✓ Branch 1 taken 442892 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2469870 times.
✓ Branch 5 taken 442861 times.
✓ Branch 7 taken 2469870 times.
✓ Branch 8 taken 442861 times.
✓ Branch 10 taken 442861 times.
✓ Branch 11 taken 442892 times.
3355623 BGL_FORALL_VERTICES(v, c2.dag, DAG) {
74
1/2
✓ Branch 1 taken 2469870 times.
✗ Branch 2 not taken.
2469870 Vertex v0 = boost::add_vertex(this->dag);
75
2/4
✓ Branch 1 taken 2469870 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2469870 times.
✗ Branch 5 not taken.
2469870 this->dag[v0].op = c2.get_Op_ptr_from_Vertex(v);
76
3/4
✓ Branch 0 taken 2469870 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1436974 times.
✓ Branch 3 taken 1032896 times.
2469870 if (opgroup_transfer == OpGroupTransfer::Preserve ||
77 opgroup_transfer == OpGroupTransfer::Merge) {
78
3/6
✓ Branch 1 taken 1436974 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1436974 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1436974 times.
✗ Branch 8 not taken.
1436974 this->dag[v0].opgroup = c2.get_opgroup_from_Vertex(v);
79 }
80
1/2
✓ Branch 2 taken 2469870 times.
✗ Branch 3 not taken.
2469870 isomap.insert({v, v0});
81 }
82
7/8
✓ Branch 1 taken 442892 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2469870 times.
✓ Branch 6 taken 442861 times.
✓ Branch 8 taken 2469870 times.
✓ Branch 9 taken 442861 times.
✓ Branch 11 taken 442861 times.
✓ Branch 12 taken 442892 times.
3355623 BGL_FORALL_VERTICES(v, c2.dag, DAG) {
83
1/2
✓ Branch 1 taken 2469870 times.
✗ Branch 2 not taken.
2469870 EdgeVec edges = c2.get_in_edges(v);
84
1/2
✓ Branch 1 taken 2469870 times.
✗ Branch 2 not taken.
2469870 Vertex target_v = isomap.find(v)->second;
85
2/2
✓ Branch 3 taken 2107713 times.
✓ Branch 4 taken 2469870 times.
4577583 for (EdgeVec::iterator e1 = edges.begin(); e1 != edges.end(); ++e1) {
86
1/2
✓ Branch 2 taken 2107713 times.
✗ Branch 3 not taken.
2107713 Vertex old_source_v = c2.source(*e1);
87
1/2
✓ Branch 1 taken 2107713 times.
✗ Branch 2 not taken.
2107713 Vertex source_v = isomap.find(old_source_v)->second;
88
1/2
✓ Branch 1 taken 2107713 times.
✗ Branch 2 not taken.
2107713 add_edge(
89
2/4
✓ Branch 1 taken 2107713 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2107713 times.
✗ Branch 7 not taken.
4215426 {source_v, get_source_port(*e1)}, {target_v, get_target_port(*e1)},
90
1/2
✓ Branch 2 taken 2107713 times.
✗ Branch 3 not taken.
2107713 c2.dag[*e1].type);
91 }
92 2469870 }
93
94
2/2
✓ Branch 0 taken 180185 times.
✓ Branch 1 taken 262707 times.
442892 if (boundary_merge == BoundaryMerge::Yes) {
95
5/8
✓ Branch 4 taken 270170 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 270170 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 450355 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 270170 times.
✓ Branch 13 taken 180185 times.
450355 for (const BoundaryElement& el : c2.boundary.get<TagID>()) {
96
1/2
✓ Branch 1 taken 270170 times.
✗ Branch 2 not taken.
270170 std::string reg_name = el.id_.reg_name();
97
1/2
✓ Branch 1 taken 270170 times.
✗ Branch 2 not taken.
270170 register_info_t reg_type = el.reg_info();
98
2/4
✓ Branch 1 taken 270170 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 270170 times.
✗ Branch 5 not taken.
270170 opt_reg_info_t reg_found = get_reg_info(reg_name);
99
2/2
✓ Branch 1 taken 89409 times.
✓ Branch 2 taken 180761 times.
270170 if (reg_found) {
100
2/4
✓ Branch 1 taken 89409 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 89409 times.
89409 if (reg_found.value() != reg_type) {
101 throw Unsupported(
102 "Cannot merge circuits with different types for "
103 "register with name: " +
104 reg_name);
105 }
106
1/2
✓ Branch 2 taken 89409 times.
✗ Branch 3 not taken.
89409 boundary_t::iterator unit_found = boundary.get<TagID>().find(el.id_);
107
2/4
✓ Branch 3 taken 89409 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 89409 times.
89409 if (unit_found != boundary.get<TagID>().end()) {
108 throw Unsupported(
109 "Cannot merge circuits as both contain unit: " + el.id_.repr());
110 }
111 }
112
1/2
✓ Branch 1 taken 270170 times.
✗ Branch 2 not taken.
270170 Vertex new_in = isomap[el.in_];
113
1/2
✓ Branch 1 taken 270170 times.
✗ Branch 2 not taken.
270170 Vertex new_out = isomap[el.out_];
114
1/2
✓ Branch 2 taken 270170 times.
✗ Branch 3 not taken.
270170 boundary.insert({el.id_, new_in, new_out});
115 270170 }
116 }
117 442892 return isomap;
118 }
119
120 // given two circuits, adds second circuit to first circuit object in parallel
121 1 Circuit operator*(const Circuit& c1, const Circuit& c2) {
122 // preliminary method to add circuit objects together
123 1 Circuit new_circ;
124
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 new_circ.copy_graph(c1);
125
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 new_circ.copy_graph(c2);
126
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 new_circ.add_phase(c1.get_phase() + c2.get_phase());
127 1 return new_circ;
128 }
129
130
2/2
✓ Branch 2 taken 13973 times.
✓ Branch 3 taken 1 times.
13974 void Circuit::append(const Circuit& c2) { append_with_map(c2, {}); }
131
132 // qm is from the units on the second (appended) circuit to the units on the
133 // first (this) circuit
134 39898 void Circuit::append_with_map(const Circuit& c2, const unit_map_t& qm) {
135
1/2
✓ Branch 1 taken 39898 times.
✗ Branch 2 not taken.
39898 Circuit copy = c2;
136
2/2
✓ Branch 1 taken 39896 times.
✓ Branch 2 taken 2 times.
39898 copy.rename_units(qm);
137
138 // Check what we need to do at the joins:
139 // Output --- Input ==> -------------
140 // Output --- Create ==> --- Reset ---
141 // Discard --- Input ==> [not allowed]
142 // Discard --- Create ==> --- Reset ---
143
1/2
✓ Branch 1 taken 39896 times.
✗ Branch 2 not taken.
39896 qubit_vector_t qbs = copy.all_qubits();
144
1/2
✓ Branch 3 taken 39896 times.
✗ Branch 4 not taken.
39896 std::set<Qubit> qbs_set(qbs.begin(), qbs.end());
145 39896 std::set<Qubit> reset_qbs;
146
3/4
✓ Branch 1 taken 39896 times.
✗ Branch 2 not taken.
✓ Branch 9 taken 168635 times.
✓ Branch 10 taken 39895 times.
208530 for (auto qb : all_qubits()) {
147
3/4
✓ Branch 2 taken 168635 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 85087 times.
✓ Branch 6 taken 83548 times.
168635 if (qbs_set.find(qb) != qbs_set.end()) {
148
3/4
✓ Branch 1 taken 85087 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 85084 times.
85087 if (copy.is_created(qb)) {
149
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 reset_qbs.insert(qb);
150
3/4
✓ Branch 1 taken 85084 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 85083 times.
85084 } else if (is_discarded(qb)) {
151
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInvalidity("Cannot append input qubit to discarded qubit");
152 }
153 }
154 208531 }
155
156 // Copy c2 into c1 but do not merge boundaries
157
1/2
✓ Branch 1 taken 39895 times.
✗ Branch 2 not taken.
39895 vertex_map_t vm = copy_graph(copy, BoundaryMerge::No);
158
1/2
✓ Branch 2 taken 39895 times.
✗ Branch 3 not taken.
39895 const Op_ptr noop = get_op_ptr(OpType::noop);
159
160 // Connect each matching qubit and bit, merging remainder
161
5/8
✓ Branch 4 taken 85123 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 85123 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 125018 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 85123 times.
✓ Branch 13 taken 39895 times.
125018 for (const BoundaryElement& el : copy.boundary.get<TagID>()) {
162
1/2
✓ Branch 1 taken 85123 times.
✗ Branch 2 not taken.
85123 std::string reg_name = el.reg_name();
163
1/2
✓ Branch 1 taken 85123 times.
✗ Branch 2 not taken.
85123 register_info_t reg_type = el.reg_info();
164
2/4
✓ Branch 1 taken 85123 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 85123 times.
✗ Branch 5 not taken.
85123 opt_reg_info_t reg_found = get_reg_info(reg_name);
165
2/2
✓ Branch 1 taken 85118 times.
✓ Branch 2 taken 5 times.
85123 if (reg_found) {
166
2/4
✓ Branch 1 taken 85118 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 85118 times.
85118 if (reg_found.value() != reg_type) {
167 throw Unsupported(
168 "Cannot append circuits with different types for "
169 "register with name: " +
170 reg_name);
171 }
172
1/2
✓ Branch 2 taken 85118 times.
✗ Branch 3 not taken.
85118 boundary_t::iterator unit_found = boundary.get<TagID>().find(el.id_);
173
3/4
✓ Branch 3 taken 85118 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 85089 times.
✓ Branch 6 taken 29 times.
85118 if (unit_found != boundary.get<TagID>().end()) {
174
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 Vertex out = unit_found->out_;
175
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 Vertex in = vm[el.in_];
176 // Update map
177
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 BoundaryElement new_elem = *unit_found;
178
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 new_elem.out_ = vm[el.out_];
179
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 boundary.replace(unit_found, new_elem);
180 // Tie together
181
2/2
✓ Branch 0 taken 85084 times.
✓ Branch 1 taken 5 times.
85089 if (reg_type.first == UnitType::Qubit)
182
1/2
✓ Branch 3 taken 85084 times.
✗ Branch 4 not taken.
85084 add_edge({out, 0}, {in, 0}, EdgeType::Quantum);
183 else
184
1/2
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 add_edge({out, 0}, {in, 0}, EdgeType::Classical);
185
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 dag[out].op = noop;
186
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 dag[in].op = noop;
187
1/2
✓ Branch 1 taken 85089 times.
✗ Branch 2 not taken.
85089 remove_vertex(out, GraphRewiring::Yes, VertexDeletion::Yes);
188
4/4
✓ Branch 1 taken 85084 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 85082 times.
✓ Branch 4 taken 2 times.
170173 if (el.type() != UnitType::Qubit ||
189
6/10
✓ Branch 2 taken 85084 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 85084 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 85084 times.
✓ Branch 9 taken 5 times.
✓ Branch 11 taken 85087 times.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
170173 reset_qbs.find(Qubit(el.id_)) == reset_qbs.end()) {
190
1/2
✓ Branch 1 taken 85087 times.
✗ Branch 2 not taken.
85087 remove_vertex(in, GraphRewiring::Yes, VertexDeletion::Yes);
191 } else {
192
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 dag[in].op = std::make_shared<const Gate>(OpType::Reset);
193 }
194 85089 } else {
195
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 Vertex new_in = vm[el.in_];
196
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 Vertex new_out = vm[el.out_];
197
1/2
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
29 boundary.insert({el.id_, new_in, new_out});
198 }
199 } else {
200
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 Vertex new_in = vm[el.in_];
201
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 Vertex new_out = vm[el.out_];
202
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 boundary.insert({el.id_, new_in, new_out});
203 }
204 85123 }
205
2/4
✓ Branch 1 taken 39895 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39895 times.
✗ Branch 5 not taken.
39895 add_phase(c2.get_phase());
206 39901 }
207
208 198 void Circuit::append_qubits(
209 const Circuit& c2, const std::vector<unsigned>& qubits,
210 const std::vector<unsigned>& bits) {
211 198 unit_map_t qm;
212
2/2
✓ Branch 1 taken 808 times.
✓ Branch 2 taken 198 times.
1006 for (unsigned i = 0; i < qubits.size(); i++) {
213
3/6
✓ Branch 1 taken 808 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 808 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 808 times.
✗ Branch 10 not taken.
808 qm.insert({Qubit(i), Qubit(qubits[i])});
214 }
215
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 198 times.
203 for (unsigned i = 0; i < bits.size(); i++) {
216
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
5 qm.insert({Bit(i), Bit(bits[i])});
217 }
218
2/2
✓ Branch 1 taken 196 times.
✓ Branch 2 taken 2 times.
198 append_with_map(c2, qm);
219 198 }
220
221 // given two circuits, adds second circuit to first sequentially by tying qubits
222 // together and returns a copy of this (to prevent destruction of initial
223 // circuits)
224 415 Circuit operator>>(const Circuit& ci1, const Circuit& ci2) {
225 415 Circuit new_circ = ci1;
226
1/2
✓ Branch 1 taken 415 times.
✗ Branch 2 not taken.
415 new_circ.append(ci2);
227 415 return new_circ;
228 }
229
230 // Important substitute method. Requires knowledge of the boundary to insert
231 // into, and the vertices inside which are to be removed when substitution is
232 // performed. Gives the option to isolate the removed vertices but not delete
233 // them.
234 222812 void Circuit::substitute(
235 const Circuit& to_insert, const Subcircuit& to_replace,
236 VertexDeletion vertex_deletion, OpGroupTransfer opgroup_transfer) {
237
2/6
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 222812 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
222812 if (!to_insert.is_simple()) throw SimpleOnly();
238
4/8
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222812 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 222812 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 222812 times.
445624 if (to_insert.n_qubits() != to_replace.q_in_hole.size() ||
239
1/2
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
222812 to_insert.n_bits() != to_replace.c_in_hole.size())
240 throw CircuitInvalidity("Subcircuit boundary mismatch to hole");
241
242
1/2
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
222812 vertex_map_t vm = copy_graph(to_insert, BoundaryMerge::No, opgroup_transfer);
243 222812 VertexList bin;
244 222812 EdgeSet ebin; // Needs to be a set since subcircuit to replace could be
245 // trivial, essentially rewiring on a cut
246 222812 std::map<Edge, Vertex> c_out_map;
247
248
1/2
✓ Branch 2 taken 222812 times.
✗ Branch 3 not taken.
222812 const Op_ptr noop = get_op_ptr(OpType::noop);
249
2/2
✓ Branch 1 taken 254931 times.
✓ Branch 2 taken 222812 times.
477743 for (unsigned i = 0; i < to_replace.q_in_hole.size(); i++) {
250 254931 Edge edge = to_replace.q_in_hole[i];
251
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 Vertex pred_v = source(edge);
252
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 port_t port1 = get_source_port(edge);
253
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 ebin.insert(edge);
254
3/6
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 254931 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 254931 times.
✗ Branch 8 not taken.
254931 Vertex inp = vm[to_insert.get_in(Qubit(i))];
255
1/2
✓ Branch 3 taken 254931 times.
✗ Branch 4 not taken.
254931 add_edge({pred_v, port1}, {inp, 0}, EdgeType::Quantum);
256
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 dag[inp].op = noop;
257
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 bin.push_back(inp);
258 }
259
2/2
✓ Branch 1 taken 254931 times.
✓ Branch 2 taken 222812 times.
477743 for (unsigned i = 0; i < to_replace.q_out_hole.size(); i++) {
260 254931 Edge edge = to_replace.q_out_hole[i];
261
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 Vertex succ_v = target(edge);
262
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 port_t port2 = get_target_port(edge);
263
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 ebin.insert(edge);
264
3/6
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 254931 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 254931 times.
✗ Branch 8 not taken.
254931 Vertex outp = vm[to_insert.get_out(Qubit(i))];
265
1/2
✓ Branch 3 taken 254931 times.
✗ Branch 4 not taken.
254931 add_edge({outp, 0}, {succ_v, port2}, EdgeType::Quantum);
266
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 dag[outp].op = noop;
267
1/2
✓ Branch 1 taken 254931 times.
✗ Branch 2 not taken.
254931 bin.push_back(outp);
268 }
269
2/2
✓ Branch 1 taken 454 times.
✓ Branch 2 taken 222812 times.
223266 for (unsigned i = 0; i < to_replace.c_in_hole.size(); i++) {
270 454 Edge edge = to_replace.c_in_hole[i];
271
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 Vertex pred_v = source(edge);
272
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 port_t port1 = get_source_port(edge);
273
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 ebin.insert(edge);
274
3/6
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 454 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 454 times.
✗ Branch 8 not taken.
454 Vertex inp = vm[to_insert.get_in(Bit(i))];
275
1/2
✓ Branch 3 taken 454 times.
✗ Branch 4 not taken.
454 add_edge({pred_v, port1}, {inp, 0}, EdgeType::Classical);
276
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 dag[inp].op = noop;
277
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 bin.push_back(inp);
278 }
279
2/2
✓ Branch 1 taken 454 times.
✓ Branch 2 taken 222812 times.
223266 for (unsigned i = 0; i < to_replace.c_out_hole.size(); i++) {
280 454 Edge edge = to_replace.c_out_hole[i];
281
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 Vertex succ_v = target(edge);
282
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 port_t port2 = get_target_port(edge);
283
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 ebin.insert(edge);
284
3/6
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 454 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 454 times.
✗ Branch 8 not taken.
454 Vertex outp = vm[to_insert.get_out(Bit(i))];
285
1/2
✓ Branch 3 taken 454 times.
✗ Branch 4 not taken.
454 add_edge({outp, 0}, {succ_v, port2}, EdgeType::Classical);
286
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 dag[outp].op = noop;
287
1/2
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
454 bin.push_back(outp);
288
1/2
✓ Branch 2 taken 454 times.
✗ Branch 3 not taken.
454 c_out_map.insert({edge, outp});
289 }
290
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 222812 times.
222814 for (const Edge& e : to_replace.b_future) {
291
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 Edge c_out = get_nth_out_edge(source(e), get_source_port(e));
292
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Vertex outp = c_out_map[c_out];
293
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
2 add_edge({outp, 0}, {target(e), get_target_port(e)}, EdgeType::Boolean);
294
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ebin.insert(e);
295 }
296
2/2
✓ Branch 5 taken 508526 times.
✓ Branch 6 taken 222812 times.
731338 for (const Edge& e : ebin) {
297
1/2
✓ Branch 1 taken 508526 times.
✗ Branch 2 not taken.
508526 remove_edge(e);
298 }
299 // automatically rewire these canned vertices
300
1/2
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
222812 remove_vertices(bin, GraphRewiring::Yes, VertexDeletion::Yes);
301
1/2
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
222812 remove_vertices(to_replace.verts, GraphRewiring::No, vertex_deletion);
302
2/4
✓ Branch 1 taken 222812 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222812 times.
✗ Branch 5 not taken.
222812 add_phase(to_insert.get_phase());
303 222812 }
304
305 115146 void Circuit::substitute(
306 const Circuit& to_insert, const Vertex& to_replace,
307 VertexDeletion vertex_deletion, OpGroupTransfer opgroup_transfer) {
308 Subcircuit sub = {
309
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
115146 get_in_edges_of_type(to_replace, EdgeType::Quantum),
310
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
230292 get_out_edges_of_type(to_replace, EdgeType::Quantum),
311
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
230292 get_in_edges_of_type(to_replace, EdgeType::Classical),
312
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
230292 get_out_edges_of_type(to_replace, EdgeType::Classical),
313
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
230292 get_out_edges_of_type(to_replace, EdgeType::Boolean),
314
2/4
✓ Branch 2 taken 115146 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 115146 times.
✗ Branch 6 not taken.
230292 {to_replace}};
315
1/2
✓ Branch 1 taken 115146 times.
✗ Branch 2 not taken.
115146 substitute(to_insert, sub, vertex_deletion, opgroup_transfer);
316 115146 }
317
318 220 void Circuit::substitute_conditional(
319 Circuit to_insert, const Vertex& to_replace, VertexDeletion vertex_deletion,
320 OpGroupTransfer opgroup_transfer) {
321
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
220 Op_ptr op = get_Op_ptr_from_Vertex(to_replace);
322
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 220 times.
220 if (op->get_type() != OpType::Conditional)
323 throw CircuitInvalidity(
324 "substitute_conditional called with an unconditional gate");
325 Subcircuit sub = {
326
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
220 get_in_edges_of_type(to_replace, EdgeType::Quantum),
327
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
440 get_out_edges_of_type(to_replace, EdgeType::Quantum),
328
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
440 get_in_edges_of_type(to_replace, EdgeType::Classical),
329
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
440 get_out_edges_of_type(to_replace, EdgeType::Classical),
330
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
440 get_out_edges_of_type(to_replace, EdgeType::Boolean),
331
2/4
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 220 times.
✗ Branch 6 not taken.
440 {to_replace}};
332 220 const Conditional& cond = static_cast<const Conditional&>(*op);
333
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
220 unsigned width = cond.get_width();
334 // Conditions are first few args, so increase index of all others
335 220 bit_map_t rename_map;
336
3/4
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 220 times.
222 for (unsigned i = 0; i < to_insert.n_bits(); ++i) {
337
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 rename_map[Bit(i)] = Bit(i + width);
338 }
339
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
220 to_insert.rename_units(rename_map);
340 // Extend subcircuit hole with space for condition bits
341
1/2
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
220 bit_vector_t cond_bits(width);
342 220 EdgeVec cond_sources;
343
2/2
✓ Branch 0 taken 411 times.
✓ Branch 1 taken 220 times.
631 for (unsigned i = 0; i < width; ++i) {
344
1/2
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
411 cond_bits[i] = Bit(i);
345
1/2
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
411 Edge read_in = get_nth_in_edge(to_replace, i);
346 Edge source_write =
347
3/6
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 411 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 411 times.
✗ Branch 8 not taken.
411 get_nth_out_edge(source(read_in), get_source_port(read_in));
348
1/2
✓ Branch 1 taken 411 times.
✗ Branch 2 not taken.
411 cond_sources.push_back(source_write);
349 }
350
1/2
✓ Branch 4 taken 220 times.
✗ Branch 5 not taken.
440 sub.c_in_hole.insert(
351 220 sub.c_in_hole.begin(), cond_sources.begin(), cond_sources.end());
352
1/2
✓ Branch 4 taken 220 times.
✗ Branch 5 not taken.
440 sub.c_out_hole.insert(
353 220 sub.c_out_hole.begin(), cond_sources.begin(), cond_sources.end());
354
3/6
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 220 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 220 times.
✗ Branch 8 not taken.
220 to_insert = to_insert.conditional_circuit(cond_bits, cond.get_value());
355
1/2
✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
220 substitute(to_insert, sub, vertex_deletion, opgroup_transfer);
356 220 }
357
358 // given the edges to be broken and new
359 // circuit, implants circuit into old circuit
360 192 void Circuit::cut_insert(
361 const Circuit& incirc, const EdgeVec& q_preds, const EdgeVec& c_preds,
362 const EdgeVec& b_future) {
363
1/2
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
192 Subcircuit sub = {q_preds, q_preds, c_preds, c_preds, b_future};
364
1/2
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
192 substitute(incirc, sub, VertexDeletion::No);
365 192 }
366
367 119 void Circuit::replace_SWAPs() {
368 119 VertexList bin;
369
7/8
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4403 times.
✓ Branch 6 taken 119 times.
✓ Branch 8 taken 4403 times.
✓ Branch 9 taken 119 times.
✓ Branch 11 taken 119 times.
✓ Branch 12 taken 119 times.
4641 BGL_FORALL_VERTICES(v, dag, DAG) {
370
3/4
✓ Branch 1 taken 4403 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 101 times.
✓ Branch 7 taken 4302 times.
4403 if (get_Op_ptr_from_Vertex(v)->get_type() == OpType::SWAP) {
371 101 Vertex swap = v;
372
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 EdgeVec outs = get_all_out_edges(v);
373 101 Edge out1 = outs[0];
374
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 dag[out1].ports.first = 1;
375 101 Edge out2 = outs[1];
376
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 dag[out2].ports.first = 0;
377
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 remove_vertex(swap, GraphRewiring::Yes, VertexDeletion::No);
378
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 bin.push_back(swap);
379 101 }
380 }
381
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
119 remove_vertices(bin, GraphRewiring::No, VertexDeletion::Yes);
382 119 }
383
384 27 void Circuit::replace_implicit_wire_swap(
385 const Qubit first, const Qubit second) {
386
4/8
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 54 times.
✓ Branch 13 taken 27 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
81 add_op<UnitID>(OpType::CX, {first, second});
387
4/8
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 54 times.
✓ Branch 13 taken 27 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
81 add_op<UnitID>(OpType::CX, {second, first});
388
4/8
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 54 times.
✓ Branch 13 taken 27 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
81 Vertex cxvertex = add_op<UnitID>(OpType::CX, {first, second});
389
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 EdgeVec outs = get_all_out_edges(cxvertex);
390 27 Edge out1 = outs[0];
391
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 dag[out1].ports.first = 1;
392 27 Edge out2 = outs[1];
393
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 dag[out2].ports.first = 0;
394 27 }
395
396 // helper functions for the dagger and transpose
397 41618 void Circuit::_handle_boundaries(Circuit& circ, vertex_map_t& vmap) const {
398 // Handle boundaries
399
4/6
✓ Branch 4 taken 48109 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 89727 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 48109 times.
✓ Branch 10 taken 41618 times.
89727 for (const BoundaryElement& el : this->boundary.get<TagID>()) {
400 Vertex new_in;
401 Vertex new_out;
402
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48109 times.
48109 if (el.id_.type() == UnitType::Bit) {
403 tket_log()->warn(
404 "The circuit contains classical data for which the dagger/transpose "
405 "might not be defined.");
406 new_in = circ.add_vertex(OpType::ClInput);
407 new_out = circ.add_vertex(OpType::ClOutput);
408 } else {
409
1/2
✓ Branch 2 taken 48109 times.
✗ Branch 3 not taken.
48109 new_in = circ.add_vertex(OpType::Input);
410
1/2
✓ Branch 2 taken 48109 times.
✗ Branch 3 not taken.
48109 new_out = circ.add_vertex(OpType::Output);
411 }
412 48109 Vertex old_in = el.in_;
413 48109 Vertex old_out = el.out_;
414
1/2
✓ Branch 1 taken 48109 times.
✗ Branch 2 not taken.
48109 vmap[old_in] = new_out;
415
1/2
✓ Branch 1 taken 48109 times.
✗ Branch 2 not taken.
48109 vmap[old_out] = new_in;
416
2/4
✓ Branch 2 taken 48109 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 48109 times.
✗ Branch 7 not taken.
48109 circ.boundary.insert({el.id_, new_in, new_out});
417 }
418 41618 }
419
420 41618 void Circuit::_handle_interior(
421 Circuit& circ, vertex_map_t& vmap, V_iterator& vi, V_iterator& vend,
422 ReverseType reverse_op) const {
423 // Handle interior
424
2/2
✓ Branch 5 taken 183736 times.
✓ Branch 6 taken 41618 times.
225354 for (std::tie(vi, vend) = boost::vertices(this->dag); vi != vend; vi++) {
425
1/2
✓ Branch 2 taken 183736 times.
✗ Branch 3 not taken.
183736 const Op_ptr op = get_Op_ptr_from_Vertex(*vi);
426
1/2
✓ Branch 2 taken 183736 times.
✗ Branch 3 not taken.
183736 OpDesc desc = op->get_desc();
427
4/6
✓ Branch 1 taken 183736 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 183736 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 96218 times.
✓ Branch 7 taken 87518 times.
183736 if (is_boundary_q_type(desc.type())) {
428 96218 continue;
429
8/14
✓ Branch 1 taken 87518 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 87511 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 87518 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 87518 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 87518 times.
✗ Branch 16 not taken.
87518 } else if ((desc.is_gate() || desc.is_box()) && !desc.is_oneway()) {
430 87518 Op_ptr op_type_ptr;
431
2/3
✓ Branch 0 taken 87317 times.
✓ Branch 1 taken 201 times.
✗ Branch 2 not taken.
87518 switch (reverse_op) {
432 87317 case ReverseType::dagger: {
433
1/2
✓ Branch 2 taken 87317 times.
✗ Branch 3 not taken.
87317 op_type_ptr = op->dagger();
434 87317 break;
435 }
436 201 case ReverseType::transpose: {
437
1/2
✓ Branch 2 taken 201 times.
✗ Branch 3 not taken.
201 op_type_ptr = op->transpose();
438 201 break;
439 }
440 default: {
441 throw std::logic_error(
442 "Error in the definition of the dagger or transpose.");
443 }
444 }
445
1/2
✓ Branch 3 taken 87518 times.
✗ Branch 4 not taken.
87518 Vertex v = circ.add_vertex(op_type_ptr);
446
1/2
✓ Branch 2 taken 87518 times.
✗ Branch 3 not taken.
87518 vmap[*vi] = v;
447 87518 } else {
448 throw CircuitInvalidity(
449 "Cannot dagger or transpose op: " + op->get_name());
450 }
451
4/4
✓ Branch 1 taken 87518 times.
✓ Branch 2 taken 96218 times.
✓ Branch 4 taken 87518 times.
✓ Branch 5 taken 96218 times.
279954 }
452 41618 }
453
454 41618 void Circuit::_handle_edges(
455 Circuit& circ, vertex_map_t& vmap, E_iterator& ei, E_iterator& eend) const {
456
2/2
✓ Branch 4 taken 142509 times.
✓ Branch 5 taken 41618 times.
184127 for (std::tie(ei, eend) = boost::edges(this->dag); ei != eend; ei++) {
457
2/4
✓ Branch 1 taken 142509 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 142509 times.
✗ Branch 5 not taken.
142509 Vertex s = source(*ei);
458
2/4
✓ Branch 1 taken 142509 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 142509 times.
✗ Branch 5 not taken.
142509 port_t sp = get_source_port(*ei);
459
2/4
✓ Branch 1 taken 142509 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 142509 times.
✗ Branch 5 not taken.
142509 Vertex t = target(*ei);
460
2/4
✓ Branch 1 taken 142509 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 142509 times.
✗ Branch 5 not taken.
142509 port_t tp = get_target_port(*ei);
461
5/10
✓ Branch 1 taken 142509 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 142509 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 142509 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 142509 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 142509 times.
✗ Branch 16 not taken.
142509 circ.add_edge({vmap[t], tp}, {vmap[s], sp}, get_edgetype(*ei));
462 }
463 41618 }
464
465 // returns Hermitian conjugate of circuit, ie its inverse
466 41610 Circuit Circuit::dagger() const {
467
1/2
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
41610 Circuit c;
468 41610 vertex_map_t vmap;
469
1/2
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
41610 _handle_boundaries(c, vmap);
470
471 41610 V_iterator vi, vend;
472 41610 ReverseType dagger = ReverseType::dagger;
473
1/2
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
41610 _handle_interior(c, vmap, vi, vend, dagger);
474
475
2/4
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 41610 times.
✗ Branch 5 not taken.
41610 E_iterator ei, eend;
476
1/2
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
41610 _handle_edges(c, vmap, ei, eend);
477
478
3/6
✓ Branch 1 taken 41610 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 41610 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 41610 times.
✗ Branch 8 not taken.
41610 c.add_phase(-get_phase());
479 83220 return c;
480 41610 }
481
482 // returns transpose of circuit
483 8 Circuit Circuit::transpose() const {
484
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Circuit c;
485 8 vertex_map_t vmap;
486
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _handle_boundaries(c, vmap);
487
488 8 V_iterator vi, vend;
489 8 ReverseType transpose = ReverseType::transpose;
490
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _handle_interior(c, vmap, vi, vend, transpose);
491
492
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 E_iterator ei, eend;
493
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 _handle_edges(c, vmap, ei, eend);
494
495
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 c.add_phase(get_phase());
496 16 return c;
497 8 }
498
499 98 bool Circuit::substitute_all(const Circuit& to_insert, const Op_ptr op) {
500
2/6
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
98 if (!to_insert.is_simple()) throw SimpleOnly();
501
4/6
✓ Branch 2 taken 98 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 98 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 97 times.
98 if (op->n_qubits() != to_insert.n_qubits())
502
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 throw CircuitInvalidity(
503 "Cannot substitute all on mismatching arity between Vertex "
504 2 "and inserted Circuit");
505 97 VertexVec to_replace;
506 97 VertexVec conditional_to_replace;
507
7/8
✓ Branch 1 taken 97 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8202 times.
✓ Branch 6 taken 97 times.
✓ Branch 8 taken 8202 times.
✓ Branch 9 taken 97 times.
✓ Branch 11 taken 97 times.
✓ Branch 12 taken 97 times.
8396 BGL_FORALL_VERTICES(v, dag, DAG) {
508
1/2
✓ Branch 1 taken 8202 times.
✗ Branch 2 not taken.
8202 Op_ptr v_op = get_Op_ptr_from_Vertex(v);
509
3/4
✓ Branch 3 taken 8202 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 109 times.
✓ Branch 6 taken 8093 times.
8202 if (*v_op == *op)
510
1/2
✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
109 to_replace.push_back(v);
511
2/2
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 8026 times.
8093 else if (v_op->get_type() == OpType::Conditional) {
512 67 const Conditional& cond = static_cast<const Conditional&>(*v_op);
513
5/8
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 67 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 35 times.
✓ Branch 10 taken 32 times.
✓ Branch 12 taken 35 times.
✗ Branch 13 not taken.
67 if (*cond.get_op() == *op) conditional_to_replace.push_back(v);
514 }
515 8202 }
516
2/2
✓ Branch 5 taken 109 times.
✓ Branch 6 taken 97 times.
206 for (const Vertex& v : to_replace) {
517
1/2
✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
109 substitute(to_insert, v, VertexDeletion::Yes);
518 }
519
2/2
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 97 times.
132 for (const Vertex& v : conditional_to_replace) {
520
2/4
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
35 substitute_conditional(to_insert, v, VertexDeletion::Yes);
521 }
522
4/4
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 22 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 69 times.
194 return !(to_replace.empty() && conditional_to_replace.empty());
523 97 }
524
525 3 bool Circuit::substitute_named(
526 const Circuit& to_insert, const std::string opname) {
527
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
3 if (!to_insert.is_simple()) throw SimpleOnly();
528
529 // Check that no op group names are in common
530
2/2
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
4 for (const auto& opgroupsig : to_insert.opgroupsigs) {
531
3/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
2 if (opgroupsigs.find(opgroupsig.first) != opgroupsigs.end()) {
532
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInvalidity("Name collision in replacement circuit");
533 }
534 }
535
536 // Do nothing if opname not present
537
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
2 if (opgroupsigs.find(opname) == opgroupsigs.end()) {
538 return false;
539 }
540
541 // Check signatures match
542
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 op_signature_t sig = opgroupsigs[opname];
543
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 unsigned sig_n_q = std::count(sig.begin(), sig.end(), EdgeType::Quantum);
544
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 unsigned sig_n_c = std::count(sig.begin(), sig.end(), EdgeType::Classical);
545
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 unsigned sig_n_b = std::count(sig.begin(), sig.end(), EdgeType::Boolean);
546
8/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
2 if (to_insert.n_qubits() != sig_n_q || to_insert.n_bits() != sig_n_c ||
547 sig_n_b != 0) {
548
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInvalidity("Signature mismatch");
549 }
550
551 1 VertexVec to_replace;
552
7/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 1 times.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
16 BGL_FORALL_VERTICES(v, dag, DAG) {
553
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 std::optional<std::string> v_opgroup = get_opgroup_from_Vertex(v);
554
7/8
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 11 times.
14 if (v_opgroup && v_opgroup.value() == opname) {
555
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 to_replace.push_back(v);
556 }
557 14 }
558
559
2/2
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
4 for (const Vertex& v : to_replace) {
560
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 substitute(to_insert, v, VertexDeletion::Yes, OpGroupTransfer::Merge);
561 }
562
563 1 return !to_replace.empty();
564 2 }
565
566 4 bool Circuit::substitute_named(Op_ptr to_insert, const std::string opname) {
567 // Do nothing if opname not present
568
3/4
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 3 times.
4 if (opgroupsigs.find(opname) == opgroupsigs.end()) {
569 1 return false;
570 }
571
572 // Check signatures match
573
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 op_signature_t sig = opgroupsigs[opname];
574
4/6
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 2 times.
3 if (to_insert->get_signature() != sig) {
575
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInvalidity("Signature mismatch");
576 }
577
578 2 VertexVec to_replace;
579
7/8
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 31 times.
✓ Branch 6 taken 2 times.
✓ Branch 8 taken 31 times.
✓ Branch 9 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
35 BGL_FORALL_VERTICES(v, dag, DAG) {
580
2/4
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
31 std::optional<std::string> v_opgroup = get_opgroup_from_Vertex(v);
581
7/8
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 19 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 6 times.
✓ Branch 10 taken 25 times.
31 if (v_opgroup && v_opgroup.value() == opname) {
582
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 to_replace.push_back(v);
583 }
584 31 }
585
586
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 unsigned sig_n_q = std::count(sig.begin(), sig.end(), EdgeType::Quantum);
587
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 unsigned sig_n_c = std::count(sig.begin(), sig.end(), EdgeType::Classical);
588
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 Circuit c(sig_n_q, sig_n_c);
589
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 unit_vector_t args(sig_n_q + sig_n_c);
590
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
4 for (unsigned i = 0; i < sig_n_q; i++) args[i] = Qubit(i);
591
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 for (unsigned i = 0; i < sig_n_c; i++) args[sig_n_q + i] = Bit(i);
592
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 c.add_op(to_insert, args, opname);
593
2/2
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2 times.
8 for (const Vertex& v : to_replace) {
594
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 substitute(c, v, VertexDeletion::Yes, OpGroupTransfer::Merge);
595 }
596
597 2 return !to_replace.empty();
598 3 }
599
600 223 Circuit Circuit::conditional_circuit(
601 const bit_vector_t& bits, unsigned value) const {
602
3/4
✓ Branch 1 taken 223 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 222 times.
223 if (has_implicit_wireswaps()) {
603
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInvalidity("Cannot add conditions to an implicit wireswap");
604 }
605
3/6
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 222 times.
✗ Branch 8 not taken.
444 Circuit cond_circ(all_qubits(), all_bits());
606
2/2
✓ Branch 5 taken 415 times.
✓ Branch 6 taken 221 times.
636 for (const Bit& b : bits) {
607
3/4
✓ Branch 1 taken 415 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 412 times.
415 if (contains_unit(b)) {
608
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Vertex in = get_in(b);
609
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 Vertex out = get_out(b);
610
3/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
3 if (get_successors_of_type(in, EdgeType::Classical).front() != out) {
611
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw CircuitInvalidity(
612 "Cannot add condition. Circuit has non-trivial "
613
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 "actions on bit " +
614
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 b.repr());
615 }
616 } else {
617
1/2
✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
412 cond_circ.add_bit(b);
618 }
619 }
620 221 unsigned width = bits.size();
621
6/10
✓ Branch 1 taken 221 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 221 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 517 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 517 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 517 times.
✓ Branch 14 taken 221 times.
738 for (const Command& com : *this) {
622 517 const Op_ptr op = com.get_op_ptr();
623
1/2
✓ Branch 1 taken 517 times.
✗ Branch 2 not taken.
517 Op_ptr cond_op = std::make_shared<Conditional>(op, width, value);
624
1/2
✓ Branch 1 taken 517 times.
✗ Branch 2 not taken.
517 unit_vector_t args = com.get_args();
625
1/2
✓ Branch 5 taken 517 times.
✗ Branch 6 not taken.
517 args.insert(args.begin(), bits.begin(), bits.end());
626
1/2
✓ Branch 2 taken 517 times.
✗ Branch 3 not taken.
517 cond_circ.add_op(cond_op, args);
627 738 }
628
2/4
✓ Branch 1 taken 221 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 221 times.
✗ Branch 5 not taken.
221 cond_circ.add_phase(get_phase());
629 442 return cond_circ;
630 1 }
631
632 4394 bool Circuit::substitute_box_vertex(
633 Vertex& vert, VertexDeletion vertex_deletion) {
634
1/2
✓ Branch 1 taken 4394 times.
✗ Branch 2 not taken.
4394 Op_ptr op = get_Op_ptr_from_Vertex(vert);
635 4394 bool conditional = op->get_type() == OpType::Conditional;
636
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4385 times.
4394 if (conditional) {
637 9 const Conditional& cond = static_cast<const Conditional&>(*op);
638
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 op = cond.get_op();
639 }
640
4/6
✓ Branch 2 taken 4394 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4394 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4347 times.
✓ Branch 9 taken 47 times.
4394 if (!op->get_desc().is_box()) return false;
641
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
47 if (op->get_type() == OpType::ClassicalExpBox) return false;
642 47 const Box& b = static_cast<const Box&>(*op);
643
2/4
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 47 times.
✗ Branch 6 not taken.
47 Circuit replacement = *b.to_circuit();
644
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 44 times.
47 if (conditional) {
645
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 substitute_conditional(
646 replacement, vert, vertex_deletion, OpGroupTransfer::Merge);
647 } else {
648
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 substitute(replacement, vert, vertex_deletion, OpGroupTransfer::Merge);
649 }
650 47 return true;
651 4394 }
652
653 57 bool Circuit::decompose_boxes() {
654 57 bool success = false;
655 57 VertexList bin;
656
7/8
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4389 times.
✓ Branch 6 taken 57 times.
✓ Branch 8 taken 4389 times.
✓ Branch 9 taken 57 times.
✓ Branch 11 taken 57 times.
✓ Branch 12 taken 57 times.
4503 BGL_FORALL_VERTICES(v, dag, DAG) {
657
3/4
✓ Branch 1 taken 4389 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 4347 times.
4389 if (substitute_box_vertex(v, VertexDeletion::No)) {
658
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 bin.push_back(v);
659 42 success = true;
660 }
661 }
662
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 remove_vertices(bin, GraphRewiring::No, VertexDeletion::Yes);
663 57 return success;
664 57 }
665
666 33 void Circuit::decompose_boxes_recursively() {
667
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 33 times.
45 while (decompose_boxes()) {
668 }
669 33 }
670
671 4 std::map<Bit, bool> Circuit::classical_eval(
672 const std::map<Bit, bool>& values) const {
673 4 std::map<Bit, bool> v(values);
674
5/8
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 8 times.
✓ Branch 12 taken 4 times.
12 for (CommandIterator it = begin(); it != end(); ++it) {
675 8 Op_ptr op = it->get_op_ptr();
676 8 OpType optype = op->get_type();
677
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if (!is_classical_type(optype)) {
678 throw CircuitInvalidity("Non-classical operation");
679 }
680 std::shared_ptr<const ClassicalEvalOp> cop =
681 8 std::dynamic_pointer_cast<const ClassicalEvalOp>(op);
682
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 unit_vector_t args = it->get_args();
683 8 unsigned n_args = args.size();
684
2/3
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 switch (optype) {
685 4 case OpType::ClassicalTransform: {
686
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::vector<bool> input(n_args);
687
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (unsigned i = 0; i < n_args; i++) {
688
3/6
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
8 input[i] = v[Bit(args[i])];
689 }
690
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::vector<bool> output = cop->eval(input);
691 TKET_ASSERT(output.size() == n_args);
692
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (unsigned i = 0; i < n_args; i++) {
693
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 10 not taken.
8 v[Bit(args[i])] = output[i];
694 }
695 4 break;
696 4 }
697 4 case OpType::SetBits: {
698
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 std::vector<bool> output = cop->eval({});
699 TKET_ASSERT(output.size() == n_args);
700
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (unsigned i = 0; i < n_args; i++) {
701
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
4 v[Bit(args[i])] = output[i];
702 }
703 4 break;
704 4 }
705 default:
706 throw CircuitInvalidity("Unexpected operation in circuit");
707 }
708 12 }
709 4 return v;
710 }
711
712 } // namespace tket
713