GCC Code Coverage Report


Directory: ./
File: Circuit/Circuit.cpp
Date: 2022-10-15 05:10:18
Warnings: 4 unchecked decisions!
Exec Total Coverage
Lines: 198 204 97.1%
Functions: 17 18 94.4%
Branches: 298 500 59.6%
Decisions: 60 74 81.1%

Line Branch Decision Exec Source
1 // Copyright 2019-2022 Cambridge Quantum Computing
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Circuit.hpp"
16
17 #include <fstream>
18 #include <numeric>
19 #include <optional>
20 #include <set>
21 #include <string>
22 #include <tklog/TketLog.hpp>
23 #include <utility>
24
25 #include "Utils/Expression.hpp"
26 #include "Utils/GraphHeaders.hpp"
27 #include "Utils/HelperFunctions.hpp"
28
29 namespace tket {
30
31 ////////////////////////////
32 // Public Circuit Methods //
33 ////////////////////////////
34
35 // Out stream of graphviz code describing the circuit from Top-Bottom,
36 // information apart from qubit path and slices can be seen easily.
37 // Very useful for debugging and eyeball comparison of circuits.
38 // out << "\nrankdir=\"LR\"" <--- put this in for Left-Right circuit
39 1 void Circuit::to_graphviz(std::ostream &out) const {
40
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 IndexMap im = index_map();
41
42
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "digraph G {\n";
43
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "{ rank = same\n";
44
3/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
0/1
? Decision couldn't be analyzed.
3 for (const Vertex &v : all_inputs()) {
45
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 out << im[v] << " ";
46 1 }
47
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "}\n";
48
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "{ rank = same\n";
49
3/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 1 times.
0/1
? Decision couldn't be analyzed.
3 for (const Vertex &v : all_outputs()) {
50
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 out << im[v] << " ";
51 1 }
52
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "}\n";
53
54
7/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
7 BGL_FORALL_VERTICES(v, dag, DAG) {
55
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
15 out << im[v] << " [label = \"" << get_Op_ptr_from_Vertex(v)->get_name()
56
7/14
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 5 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 5 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 5 times.
✗ Branch 20 not taken.
10 << ", " << im[v] << "\"];\n";
57 }
58
12/18
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 4 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 4 times.
✓ Branch 18 taken 1 times.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✓ Branch 23 taken 1 times.
6 BGL_FORALL_EDGES(e, dag, DAG) {
59
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 Vertex v_so = source(e);
60
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 Vertex v_ta = target(e);
61
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 unsigned v_s = im[v_so];
62
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 unsigned v_t = im[v_ta];
63
7/14
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
4 out << v_s << " -> " << v_t << " [label = \"" << get_source_port(e) << ", "
64
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
4 << get_target_port(e) << "\"];\n";
65 }
66
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 out << "}";
67 1 }
68
69 void Circuit::to_graphviz_file(const std::string &filename) const {
70 std::ofstream dot_file(filename);
71 to_graphviz(dot_file);
72 }
73
74 1 std::string Circuit::to_graphviz_str() const {
75
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::stringstream dot_string;
76
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 to_graphviz(dot_string);
77
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return dot_string.str();
78 1 }
79
80 1 void Circuit::extract_slice_segment(unsigned slice_one, unsigned slice_two) {
81
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 SliceVec slices = get_slices();
82 1 VertexList bin;
83
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 for (unsigned i = 0; i < slice_one - 1; ++i) {
84
2/2
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 for (Vertex it : slices[i]) {
85
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 bin.push_back(it);
86
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 remove_vertex(it, GraphRewiring::Yes, VertexDeletion::No);
87 }
88 }
89
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 1 times.
3 for (unsigned i = slice_two; i < slices.size(); ++i) {
90
2/2
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
4 for (Vertex it : slices[i]) {
91
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 bin.push_back(it);
92
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 remove_vertex(it, GraphRewiring::Yes, VertexDeletion::No);
93 }
94 }
95
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 remove_vertices(bin, GraphRewiring::No, VertexDeletion::Yes);
96 1 }
97
98 250 std::vector<Command> Circuit::get_commands() const {
99 250 std::vector<Command> coms;
100
4/6
✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1485 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1235 times.
✓ Branch 9 taken 250 times.
0/1
? Decision couldn't be analyzed.
1485 for (CommandIterator it = begin(); it != end(); ++it) {
101
3/6
✓ Branch 1 taken 1235 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1235 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1235 times.
✗ Branch 9 not taken.
1235 coms.push_back(*it);
102 250 }
103 250 return coms;
104 }
105
106 446 void Circuit::index_vertices() /*const*/ {
107
1/2
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
446 VIndex index = boost::get(boost::vertex_index, dag);
108 446 int i = 0;
109
8/10
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19796 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 19796 times.
✓ Branch 9 taken 446 times.
✓ Branch 11 taken 19796 times.
✓ Branch 12 taken 446 times.
✓ Branch 14 taken 446 times.
✓ Branch 15 taken 446 times.
20688 BGL_FORALL_VERTICES(v, dag, DAG) { boost::put(index, v, i++); }
110 446 }
111
112 446 VertexVec Circuit::vertices_in_order() /*const*/ {
113 446 index_vertices();
114 446 VertexVec vertices;
115
2/4
✓ Branch 1 taken 446 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 446 times.
✗ Branch 5 not taken.
446 boost::topological_sort(dag, std::back_inserter(vertices));
116
1/2
✓ Branch 3 taken 446 times.
✗ Branch 4 not taken.
446 std::reverse(vertices.begin(), vertices.end());
117 446 return vertices;
118 }
119
120 41291 IndexMap Circuit::index_map() const {
121 41291 IndexMap im;
122 41291 unsigned i = 0;
123
8/10
✓ Branch 1 taken 41291 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 565596 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 565596 times.
✓ Branch 9 taken 41291 times.
✓ Branch 11 taken 565596 times.
✓ Branch 12 taken 41291 times.
✓ Branch 14 taken 41291 times.
✓ Branch 15 taken 41291 times.
648178 BGL_FORALL_VERTICES(v, dag, DAG) { im[v] = i++; }
124 41291 return im;
125 }
126
127 498106 Expr Circuit::get_phase() const {
128
1/2
✓ Branch 1 taken 498106 times.
✗ Branch 2 not taken.
498106 std::optional<double> x = eval_expr_mod(phase);
129
2/2
✓ Branch 1 taken 498100 times.
✓ Branch 2 taken 6 times.
2/2
✓ Decision 'true' taken 498100 times.
✓ Decision 'false' taken 6 times.
498106 if (x) {
130
2/4
✓ Branch 1 taken 498100 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 498100 times.
✗ Branch 5 not taken.
498100 return x.value();
131 } else
132
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 return phase;
133 }
134
135 391248 void Circuit::add_phase(Expr a) { phase += a; }
136
137 222 void Circuit::symbol_substitution(const symbol_map_t &symbol_map) {
138 222 SymEngine::map_basic_basic sub_map;
139
2/2
✓ Branch 5 taken 330 times.
✓ Branch 6 taken 222 times.
2/2
✓ Decision 'true' taken 330 times.
✓ Decision 'false' taken 222 times.
552 for (const std::pair<const Sym, Expr> &p : symbol_map) {
140
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 ExprPtr s = p.first;
141
1/2
✓ Branch 2 taken 330 times.
✗ Branch 3 not taken.
330 ExprPtr e = p.second;
142 // This is a workaround for a symengine issue: symengine currently has poor
143 // handling of symbolic evaluations for atan2. However, this may not catch
144 // every such issue, so we should revisit it.
145
4/6
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 321 times.
2/2
✓ Decision 'true' taken 9 times.
✓ Decision 'false' taken 321 times.
330 if (approx_0(e)) {
146
3/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
9 sub_map[s] = SymEngine::zero;
147 } else {
148
2/4
✓ Branch 1 taken 321 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 321 times.
✗ Branch 5 not taken.
321 sub_map[s] = e;
149 }
150 330 }
151
2/4
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
222 symbol_substitution(sub_map);
152 222 }
153
154 15 void Circuit::symbol_substitution(
155 const std::map<Sym, double, SymEngine::RCPBasicKeyLess> &symbol_map) {
156 15 symbol_map_t s_map;
157
3/4
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 65 times.
✓ Branch 9 taken 15 times.
0/1
? Decision couldn't be analyzed.
80 for (std::pair<Sym, Expr> p : symbol_map) {
158
2/4
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 5 not taken.
65 s_map[p.first] = Expr(p.second);
159 65 }
160
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 symbol_substitution(s_map);
161 15 }
162
163 222 void Circuit::symbol_substitution(const SymEngine::map_basic_basic sub_map) {
164
7/8
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3300 times.
✓ Branch 6 taken 222 times.
✓ Branch 8 taken 3300 times.
✓ Branch 9 taken 222 times.
✓ Branch 11 taken 222 times.
✓ Branch 12 taken 222 times.
3744 BGL_FORALL_VERTICES(v, dag, DAG) {
165
2/4
✓ Branch 1 taken 3300 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3300 times.
✗ Branch 6 not taken.
3300 Op_ptr new_op = get_Op_ptr_from_Vertex(v)->symbol_substitution(sub_map);
166
2/2
✓ Branch 1 taken 2400 times.
✓ Branch 2 taken 900 times.
2/2
✓ Decision 'true' taken 2400 times.
✓ Decision 'false' taken 900 times.
3300 if (new_op) {
167
2/4
✓ Branch 3 taken 2400 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2400 times.
✗ Branch 7 not taken.
2400 dag[v] = {new_op};
168 }
169 3300 }
170 222 phase = phase.subs(sub_map);
171 222 }
172
173 95 const SymSet Circuit::free_symbols() const {
174 95 SymSet symbols;
175
7/8
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 906 times.
✓ Branch 6 taken 95 times.
✓ Branch 8 taken 906 times.
✓ Branch 9 taken 95 times.
✓ Branch 11 taken 95 times.
✓ Branch 12 taken 95 times.
1096 BGL_FORALL_VERTICES(v, dag, DAG) {
176
2/4
✓ Branch 1 taken 906 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 906 times.
✗ Branch 6 not taken.
906 const SymSet s = get_Op_ptr_from_Vertex(v)->free_symbols();
177
1/2
✓ Branch 3 taken 906 times.
✗ Branch 4 not taken.
906 symbols.insert(s.begin(), s.end());
178 906 }
179
1/2
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
95 SymSet phase_s = expr_free_symbols(phase);
180
1/2
✓ Branch 3 taken 95 times.
✗ Branch 4 not taken.
95 symbols.insert(phase_s.begin(), phase_s.end());
181 190 return symbols;
182 95 }
183
184 38 bool Circuit::is_symbolic() const { return !free_symbols().empty(); }
185
186 // check aspects of circuit for equality, and optionally throw exceptions when
187 // not met
188 158 bool Circuit::circuit_equality(
189 const Circuit &other, const std::set<Check> &except,
190 bool throw_error) const {
191 158 bool check = true;
192 158 check &= check_iterators_equality(*this, other);
193
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 145 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 158 times.
158 if (throw_error && !check) {
194 throw CircuitInequality(std::string("Circuit operations do not match."));
195 }
196
197
2/4
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 158 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 158 times.
✗ Decision 'false' not taken.
158 if (except.count(Check::Phase) == 0) {
198
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 const Expr thisphase = this->get_phase();
199
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 const Expr othephase = other.get_phase();
200
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 check &= equiv_expr(thisphase, othephase);
201
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 157 times.
158 if (throw_error && !check) {
202
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw CircuitInequality(
203
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 std::string("Circuit phases do not match: ") +
204
4/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
4 ExprPtr(thisphase)->__str__() +
205
4/8
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
4 " != " + ExprPtr(othephase)->__str__());
206 }
207 159 }
208
2/4
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 157 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 157 times.
✗ Decision 'false' not taken.
157 if (except.count(Check::Units) == 0) {
209
2/4
✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 157 times.
✗ Branch 6 not taken.
157 check &= (this->all_qubits() == other.all_qubits());
210
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 11 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 156 times.
157 if (throw_error && !check) {
211
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInequality(std::string("Circuit qubits do not match."));
212 }
213
214
2/4
✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 156 times.
✗ Branch 6 not taken.
156 check &= (this->all_bits() == other.all_bits());
215
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 155 times.
156 if (throw_error && !check) {
216
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw CircuitInequality(std::string("Circuit bits do not match."));
217 }
218
2/4
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 155 times.
✗ Branch 6 not taken.
155 check &= (this->created_qubits() == other.created_qubits());
219
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 154 times.
155 if (throw_error && !check) {
220
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw CircuitInequality(
221
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 std::string("Circuit created qubits do not match."));
222 }
223
2/4
✓ Branch 2 taken 154 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 154 times.
✗ Branch 6 not taken.
154 check &= (this->discarded_qubits() == other.discarded_qubits());
224
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 8 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 153 times.
154 if (throw_error && !check) {
225
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw CircuitInequality(
226
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 std::string("Circuit discarded qubits do not match."));
227 }
228 }
229
230
3/4
✓ Branch 1 taken 153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 152 times.
✓ Branch 4 taken 1 times.
2/2
✓ Decision 'true' taken 152 times.
✓ Decision 'false' taken 1 times.
153 if (except.count(Check::ImplicitPermutation) == 0) {
231 152 check &=
232
2/4
✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 152 times.
✗ Branch 5 not taken.
152 (this->implicit_qubit_permutation() ==
233 304 other.implicit_qubit_permutation());
234
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 151 times.
152 if (throw_error && !check) {
235
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw CircuitInequality(
236
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 std::string("Circuit implicit permutations do not match."));
237 }
238 }
239
2/4
✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 152 times.
✗ Branch 4 not taken.
1/2
✓ Decision 'true' taken 152 times.
✗ Decision 'false' not taken.
152 if (except.count(Check::Name) == 0) {
240
1/2
✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
152 check &= (this->get_name() == other.get_name());
241
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 151 times.
152 if (throw_error && !check) {
242
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const std::optional<std::string> thisname = this->get_name();
243
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const std::optional<std::string> othename = other.get_name();
244
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 std::string errormsg = "Circuit names do not match: ";
245
5/14
✓ 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 11 not taken.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
1 errormsg += (thisname ? thisname.value() : "None");
246
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 errormsg += " != ";
247
4/14
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
1 errormsg += (othename ? othename.value() : "None");
248
249
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 throw CircuitInequality(errormsg);
250 3 }
251 }
252 151 return check;
253 }
254
255 // Performs a traversal from the given vertex forwards through the dag, looking
256 // for something on the target qubit We can prune a path if it reaches the depth
257 // of the target forward = true returns true if target is in causal future of
258 // from forward = false checks for causal past (v_to_depth should give reverse
259 // depth)
260 // TODO:: rewrite to work with classical boxes
261 911 bool Circuit::in_causal_order(
262 const Vertex &target, const Vertex &from, bool forward,
263 const std::map<Vertex, unsigned> &v_to_depth,
264 const std::map<Vertex, unit_set_t> &v_to_units, bool strict) const {
265
1/2
✓ Branch 1 taken 911 times.
✗ Branch 2 not taken.
911 unsigned target_depth = v_to_depth.at(target);
266
4/4
✓ Branch 0 taken 801 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 800 times.
2/2
✓ Decision 'true' taken 910 times.
✓ Decision 'false' taken 1 times.
911 if (!strict && from == target) return true;
267
3/4
✓ Branch 1 taken 910 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 872 times.
✓ Branch 4 taken 38 times.
2/2
✓ Decision 'true' taken 362 times.
✓ Decision 'false' taken 548 times.
910 if (v_to_depth.at(from) >= target_depth) return false;
268 typedef std::function<bool(Vertex, Vertex)> Comp;
269 362 Comp c = [&](Vertex a, Vertex b) {
270 362 unsigned deptha = v_to_depth.at(a);
271 362 unsigned depthb = v_to_depth.at(b);
272
2/2
✓ Branch 0 taken 160 times.
✓ Branch 1 taken 202 times.
2/2
✓ Decision 'true' taken 160 times.
✓ Decision 'false' taken 202 times.
362 if (deptha == depthb) {
273
2/4
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
160 unit_set_t unitsa = v_to_units.at(a);
274
2/4
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 160 times.
✗ Branch 5 not taken.
160 unit_set_t unitsb = v_to_units.at(b);
275
1/2
✓ Branch 2 taken 160 times.
✗ Branch 3 not taken.
160 return unitsa < unitsb;
276 160 }
277 202 return deptha < depthb;
278 38 };
279
1/2
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
38 std::set<Vertex, Comp> to_search(c);
280
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 37 times.
✓ Decision 'false' taken 1 times.
38 if (forward) {
281
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 VertexVec succs = get_successors(from);
282
2/2
✓ Branch 5 taken 64 times.
✓ Branch 6 taken 37 times.
2/2
✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 37 times.
101 for (const Vertex &s : succs) {
283
2/4
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 64 times.
✗ Branch 6 not taken.
1/2
✓ Decision 'true' taken 64 times.
✗ Decision 'false' not taken.
64 if (v_to_depth.find(s) != v_to_depth.end()) {
284
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 to_search.insert(s);
285 }
286 }
287 37 } else {
288
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 VertexVec preds = get_predecessors(from);
289
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 to_search.insert(preds.begin(), preds.end());
290 1 }
291
2/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
38 unit_set_t lookup_units = v_to_units.at(target);
292
2/2
✓ Branch 1 taken 255 times.
✓ Branch 2 taken 22 times.
2/2
✓ Decision 'true' taken 255 times.
✓ Decision 'false' taken 22 times.
277 while (!to_search.empty()) {
293 255 Vertex v = *to_search.begin();
294
1/2
✓ Branch 2 taken 255 times.
✗ Branch 3 not taken.
255 to_search.erase(to_search.begin());
295
3/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 228 times.
2/2
✓ Decision 'true' taken 228 times.
✓ Decision 'false' taken 27 times.
255 if (v_to_depth.at(v) > target_depth) continue;
296
2/4
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 228 times.
✗ Branch 5 not taken.
228 unit_set_t v_units = v_to_units.at(v);
297
2/2
✓ Branch 5 taken 253 times.
✓ Branch 6 taken 212 times.
2/2
✓ Decision 'true' taken 253 times.
✓ Decision 'false' taken 212 times.
465 for (const UnitID &u : lookup_units) {
298
3/4
✓ Branch 2 taken 253 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 237 times.
2/2
✓ Decision 'true' taken 16 times.
✓ Decision 'false' taken 237 times.
253 if (v_units.find(u) != v_units.end()) {
299 16 return true;
300 }
301 }
302
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 212 times.
✗ Decision 'false' not taken.
212 if (forward) {
303
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 VertexVec succs = get_successors(v);
304
2/2
✓ Branch 5 taken 219 times.
✓ Branch 6 taken 212 times.
2/2
✓ Decision 'true' taken 219 times.
✓ Decision 'false' taken 212 times.
431 for (const Vertex &s : succs) {
305
3/4
✓ Branch 2 taken 219 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 205 times.
✓ Branch 6 taken 14 times.
2/2
✓ Decision 'true' taken 205 times.
✓ Decision 'false' taken 14 times.
219 if (v_to_depth.find(s) != v_to_depth.end()) {
306
1/2
✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
205 to_search.insert(s);
307 }
308 }
309 212 } else {
310 VertexVec preds = get_predecessors(v);
311 to_search.insert(preds.begin(), preds.end());
312 }
313
2/2
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 16 times.
228 }
314 22 return false;
315 38 }
316
317 } // namespace tket
318