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 |