GCC Code Coverage Report


Directory: ./
File: Circuit/Boxes.cpp
Date: 2022-10-15 05:10:18
Warnings: 5 unchecked decisions!
Exec Total Coverage
Lines: 498 600 83.0%
Functions: 91 117 77.8%
Branches: 535 1182 45.3%
Decisions: 47 78 60.3%

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 "Boxes.hpp"
16
17 #include <memory>
18 #include <numeric>
19 #include <tkassert/Assert.hpp>
20
21 #include "CircUtils.hpp"
22 #include "Circuit/AssertionSynthesis.hpp"
23 #include "Command.hpp"
24 #include "Gate/Rotation.hpp"
25 #include "OpType/OpTypeInfo.hpp"
26 #include "Ops/OpJsonFactory.hpp"
27 #include "Ops/OpPtr.hpp"
28 #include "ThreeQubitConversion.hpp"
29 #include "Utils/EigenConfig.hpp"
30 #include "Utils/Expression.hpp"
31 #include "Utils/Json.hpp"
32 #include "Utils/PauliStrings.hpp"
33
34 namespace tket {
35
36 1 unsigned Box::n_qubits() const {
37
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 op_signature_t sig = get_signature();
38
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 return std::count(sig.begin(), sig.end(), EdgeType::Quantum);
39 1 }
40
41 unsigned Box::n_boolean() const {
42 op_signature_t sig = get_signature();
43 return std::count(sig.begin(), sig.end(), EdgeType::Boolean);
44 }
45
46 unsigned Box::n_classical() const {
47 op_signature_t sig = get_signature();
48 return std::count(sig.begin(), sig.end(), EdgeType::Classical);
49 }
50
51 900 op_signature_t Box::get_signature() const {
52
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
900 std::optional<op_signature_t> sig = desc_.signature();
53
2/2
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 700 times.
2/2
✓ Decision 'true' taken 200 times.
✓ Decision 'false' taken 700 times.
900 if (sig)
54
1/2
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
200 return *sig;
55 else
56
1/2
✓ Branch 1 taken 700 times.
✗ Branch 2 not taken.
700 return signature_;
57 900 }
58
59 13 nlohmann::json Box::serialize() const {
60 13 nlohmann::json j;
61
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
13 j["type"] = get_type();
62
3/6
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
13 j["box"] = OpJsonFactory::to_json(shared_from_this());
63 13 return j;
64 }
65
66 13 Op_ptr Box::deserialize(const nlohmann::json &j) {
67 13 return OpJsonFactory::from_json(j.at("box"));
68 }
69
70
1/2
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
45 CircBox::CircBox(const Circuit &circ) : Box(OpType::CircBox) {
71
4/6
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 44 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2/2
✓ Decision 'true' taken 44 times.
✓ Decision 'false' taken 1 times.
45 if (!circ.is_simple()) throw SimpleOnly();
72
2/4
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
44 signature_ = op_signature_t(circ.n_qubits(), EdgeType::Quantum);
73
2/4
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
44 op_signature_t bits(circ.n_bits(), EdgeType::Classical);
74
1/2
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
44 signature_.insert(signature_.end(), bits.begin(), bits.end());
75
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 circ_ = std::make_shared<Circuit>(circ);
76 45 }
77
78 48 CircBox::CircBox(const CircBox &other) : Box(other) {}
79
80 CircBox::CircBox() : Box(OpType::CircBox) {
81 circ_ = std::make_shared<Circuit>();
82 }
83
84 1 bool CircBox::is_clifford() const {
85
7/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 45 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
47 BGL_FORALL_VERTICES(v, circ_->dag, DAG) {
86
3/6
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 45 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 45 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 44 times.
45 if (!circ_->get_Op_ptr_from_Vertex(v)->is_clifford()) return false;
87 }
88 1 return true;
89 }
90
91 Op_ptr CircBox::symbol_substitution(
92 const SymEngine::map_basic_basic &sub_map) const {
93 Circuit new_circ(*to_circuit());
94 new_circ.symbol_substitution(sub_map);
95 return std::make_shared<CircBox>(new_circ);
96 }
97
98
1/2
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
28 SymSet CircBox::free_symbols() const { return to_circuit()->free_symbols(); }
99
100 1 Op_ptr CircBox::dagger() const {
101
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 return std::make_shared<CircBox>(circ_->dagger());
102 }
103
104 Op_ptr CircBox::transpose() const {
105 return std::make_shared<CircBox>(circ_->transpose());
106 }
107
108 13 Unitary1qBox::Unitary1qBox(const Eigen::Matrix2cd &m)
109
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
13 : Box(OpType::Unitary1qBox), m_(m) {
110
3/6
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 13 times.
13 if (!is_unitary(m)) {
111
0/1
? Decision couldn't be analyzed.
throw CircuitInvalidity("Matrix for Unitary1qBox must be unitary");
112 }
113 13 }
114
115 7 Unitary1qBox::Unitary1qBox(const Unitary1qBox &other)
116
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 : Box(other), m_(other.m_) {}
117
118 Unitary1qBox::Unitary1qBox() : Unitary1qBox(Eigen::Matrix2cd::Identity()) {}
119
120 1 Op_ptr Unitary1qBox::dagger() const {
121
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 return std::make_shared<Unitary1qBox>(m_.conjugate().transpose());
122 }
123
124 1 Op_ptr Unitary1qBox::transpose() const {
125
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return std::make_shared<Unitary1qBox>(m_.transpose());
126 }
127
128 1 bool Unitary1qBox::is_clifford() const {
129
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 std::vector<Command> cmds = to_circuit()->get_commands();
130 TKET_ASSERT(cmds.size() == 1);
131
1/2
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 return cmds[0].get_op_ptr()->is_clifford();
132 1 }
133
134 4 void Unitary1qBox::generate_circuit() const {
135
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 std::vector<double> tk1_params = tk1_angles_from_unitary(m_);
136
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 Circuit temp_circ(1);
137
8/16
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✓ Branch 23 taken 12 times.
✓ Branch 24 taken 4 times.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
28 temp_circ.add_op<unsigned>(
138 12 OpType::TK1, {tk1_params[0], tk1_params[1], tk1_params[2]}, {0});
139
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 circ_ = std::make_shared<Circuit>(temp_circ);
140
2/4
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
4 circ_->add_phase(tk1_params[3]);
141 4 }
142
143 34 Unitary2qBox::Unitary2qBox(const Eigen::Matrix4cd &m, BasisOrder basis)
144 : Box(OpType::Unitary2qBox),
145
3/8
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 34 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 34 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
34 m_(basis == BasisOrder::ilo ? m : reverse_indexing(m)) {
146
3/6
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 34 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 34 times.
34 if (!is_unitary(m)) {
147
0/1
? Decision couldn't be analyzed.
throw CircuitInvalidity("Matrix for Unitary2qBox must be unitary");
148 }
149 34 }
150
151 27 Unitary2qBox::Unitary2qBox(const Unitary2qBox &other)
152
1/2
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 : Box(other), m_(other.m_) {}
153
154 Unitary2qBox::Unitary2qBox() : Unitary2qBox(Eigen::Matrix4cd::Identity()) {}
155
156 2 Op_ptr Unitary2qBox::dagger() const {
157
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 return std::make_shared<Unitary2qBox>(m_.conjugate().transpose());
158 }
159
160 2 Op_ptr Unitary2qBox::transpose() const {
161
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 return std::make_shared<Unitary2qBox>(m_.transpose());
162 }
163
164 9 void Unitary2qBox::generate_circuit() const {
165
1/2
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 circ_ = std::make_shared<Circuit>(two_qubit_canonical(m_));
166 9 }
167
168 20 Unitary3qBox::Unitary3qBox(const Matrix8cd &m, BasisOrder basis)
169 : Box(OpType::Unitary3qBox),
170
3/8
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
20 m_(basis == BasisOrder::ilo ? m : reverse_indexing(m)) {}
171
172 16 Unitary3qBox::Unitary3qBox(const Unitary3qBox &other)
173
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 : Box(other), m_(other.m_) {}
174
175 Unitary3qBox::Unitary3qBox() : Unitary3qBox(Matrix8cd::Identity()) {}
176
177 Op_ptr Unitary3qBox::dagger() const {
178 return std::make_shared<Unitary3qBox>(m_.adjoint());
179 }
180
181 Op_ptr Unitary3qBox::transpose() const {
182 return std::make_shared<Unitary3qBox>(m_.transpose());
183 }
184
185 5 void Unitary3qBox::generate_circuit() const {
186
2/4
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
5 circ_ = std::make_shared<Circuit>(three_qubit_tk_synthesis(m_));
187 5 }
188
189 28 ExpBox::ExpBox(const Eigen::Matrix4cd &A, double t, BasisOrder basis)
190 : Box(OpType::ExpBox),
191
1/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
28 A_(basis == BasisOrder::ilo ? A : reverse_indexing(A)),
192
2/4
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
28 t_(t) {
193
3/6
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 28 times.
28 if (!A.isApprox(A.adjoint())) {
194
0/1
? Decision couldn't be analyzed.
throw CircuitInvalidity("Matrix for ExpBox must be Hermitian");
195 }
196 28 }
197
198
1/2
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 ExpBox::ExpBox(const ExpBox &other) : Box(other), A_(other.A_), t_(other.t_) {}
199
200 ExpBox::ExpBox() : ExpBox(Eigen::Matrix4cd::Zero(), 1.) {}
201
202
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 Op_ptr ExpBox::dagger() const { return std::make_shared<ExpBox>(A_, -t_); }
203
204 1 Op_ptr ExpBox::transpose() const {
205
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return std::make_shared<ExpBox>(A_.transpose(), t_);
206 }
207
208 void ExpBox::generate_circuit() const {
209 circ_ = std::make_shared<Circuit>(two_qubit_canonical((i_ * t_ * A_).exp()));
210 }
211
212 1882 PauliExpBox::PauliExpBox(const std::vector<Pauli> &paulis, const Expr &t)
213 : Box(OpType::PauliExpBox,
214
1/2
✓ Branch 2 taken 1882 times.
✗ Branch 3 not taken.
3764 op_signature_t(paulis.size(), EdgeType::Quantum)),
215 1882 paulis_(paulis),
216
3/6
✓ Branch 2 taken 1882 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1882 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1882 times.
✗ Branch 9 not taken.
5646 t_(t) {}
217
218 135 PauliExpBox::PauliExpBox(const PauliExpBox &other)
219
2/4
✓ Branch 2 taken 135 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 135 times.
✗ Branch 6 not taken.
135 : Box(other), paulis_(other.paulis_), t_(other.t_) {}
220
221 PauliExpBox::PauliExpBox() : PauliExpBox({}, 0.) {}
222
223 1 bool PauliExpBox::is_clifford() const {
224
6/18
✓ 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 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
1 return equiv_0(4 * t_) || paulis_.empty();
225 }
226
227 6 SymSet PauliExpBox::free_symbols() const { return expr_free_symbols(t_); }
228
229 1 Op_ptr PauliExpBox::dagger() const {
230
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return std::make_shared<PauliExpBox>(paulis_, -t_);
231 }
232
233 2 Op_ptr PauliExpBox::transpose() const {
234
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::vector<Pauli> paulis = get_paulis();
235
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 int y_pauli_counter = std::count(paulis.begin(), paulis.end(), Pauli::Y);
236
237 // Negate the parameter if odd
238
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 if (y_pauli_counter % 2 == 0) {
239
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return std::make_shared<PauliExpBox>(paulis_, t_);
240 } else {
241
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 return std::make_shared<PauliExpBox>(paulis_, -t_);
242 };
243 2 }
244
245 25 Op_ptr PauliExpBox::symbol_substitution(
246 const SymEngine::map_basic_basic &sub_map) const {
247
1/2
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
25 return std::make_shared<PauliExpBox>(this->paulis_, this->t_.subs(sub_map));
248 }
249
250 void PauliExpBox::generate_circuit() const {
251 Circuit circ = pauli_gadget(paulis_, t_);
252 circ_ = std::make_shared<Circuit>(circ);
253 }
254
255 12 composite_def_ptr_t CompositeGateDef::define_gate(
256 const std::string &name, const Circuit &def, const std::vector<Sym> &args) {
257 12 return std::make_shared<CompositeGateDef>(name, def, args);
258 }
259
260 12 CompositeGateDef::CompositeGateDef(
261 12 const std::string &name, const Circuit &def, const std::vector<Sym> &args)
262
3/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
12 : name_(name), def_(std::make_shared<Circuit>(def)), args_(args) {}
263
264 5 Circuit CompositeGateDef::instance(const std::vector<Expr> &params) const {
265
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 Circuit circ = *def_;
266 5 symbol_map_t symbol_map;
267
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 5 times.
✓ Decision 'false' taken 5 times.
10 for (unsigned i = 0; i < params.size(); i++) {
268
4/8
✓ 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.
5 symbol_map.insert({args_.at(i), params.at(i)});
269 }
270
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 circ.symbol_substitution(symbol_map);
271 10 return circ;
272 5 }
273
274 16 op_signature_t CompositeGateDef::signature() const {
275
2/4
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
16 op_signature_t qubs(def_->n_qubits(), EdgeType::Quantum);
276
2/4
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
16 op_signature_t bs(def_->n_bits(), EdgeType::Classical);
277
1/2
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
16 qubs.insert(qubs.end(), bs.begin(), bs.end());
278 32 return qubs;
279 16 }
280
281 4 bool CompositeGateDef::operator==(const CompositeGateDef &other) const {
282
4/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 3 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 1 times.
4 if (this->get_name() != other.get_name()) return false;
283
1/2
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 std::vector<Expr> this_args = {this->args_.begin(), this->args_.end()};
284
1/2
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 std::vector<Expr> other_args = {other.args_.begin(), other.args_.end()};
285
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
1/2
✓ Decision 'true' taken 3 times.
✗ Decision 'false' not taken.
3 if (this_args != other_args) return false;
286
1/2
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 return this->get_def()->circuit_equality(*other.get_def(), {}, false);
287 3 }
288
289 17 CustomGate::CustomGate(
290 17 const composite_def_ptr_t &gate, const std::vector<Expr> &params)
291
2/4
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
17 : Box(OpType::CustomGate), gate_(gate), params_(params) {
292
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 16 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 16 times.
17 if (!gate) {
293
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 throw std::runtime_error(
294 2 "Null CompositeGateDef pointer passed to CustomGate");
295 }
296
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 signature_ = gate->signature();
297
298
1/4
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
0/1
? Decision couldn't be analyzed.
16 if (params_.size() != gate_->n_args()) throw InvalidParameterCount();
299 19 }
300
301 7 CustomGate::CustomGate(const CustomGate &other)
302
1/2
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
7 : Box(other), gate_(other.gate_), params_(other.params_) {}
303
304 8 bool CustomGate::is_equal(const Op &op_other) const {
305
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 const CustomGate &other = dynamic_cast<const CustomGate &>(op_other);
306
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 5 times.
8 if (this->id_ == other.id_) {
307 3 return true;
308 }
309 TKET_ASSERT(gate_ && other.gate_);
310
4/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
5 return params_ == other.params_ && *gate_ == *other.gate_;
311 }
312
313 Op_ptr CustomGate::symbol_substitution(
314 const SymEngine::map_basic_basic &sub_map) const {
315 std::vector<Expr> new_params;
316
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (const Expr &p : this->params_) {
317 new_params.push_back(p.subs(sub_map));
318 }
319 return std::make_shared<CustomGate>(this->gate_, new_params);
320 }
321
322 5 void CustomGate::generate_circuit() const {
323
1/2
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
5 circ_ = std::make_shared<Circuit>(gate_->instance(params_));
324 5 }
325
326
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 SymSet CustomGate::free_symbols() const { return to_circuit()->free_symbols(); }
327
328 3 std::string CustomGate::get_name(bool) const {
329
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 std::stringstream s;
330
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
3 s << gate_->get_name();
331
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 if (!params_.empty()) {
332
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 s << "(";
333
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 std::string sep = "";
334
2/2
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 2 times.
6 for (const Expr &e : params_) {
335
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 s << sep << e;
336
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 sep = ",";
337 }
338
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 s << ")";
339 2 }
340
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 return s.str();
341 3 }
342
343 1 bool CustomGate::is_clifford() const {
344
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::shared_ptr<Circuit> circ = to_circuit();
345
7/8
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 1 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
9 BGL_FORALL_VERTICES(v, circ->dag, DAG) {
346
3/6
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 6 times.
7 if (!circ->get_Op_ptr_from_Vertex(v)->is_clifford()) return false;
347 }
348 1 return true;
349 1 }
350
351 33 QControlBox::QControlBox(const Op_ptr &op, unsigned n_controls)
352
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 : Box(OpType::QControlBox), op_(op), n_controls_(n_controls) {
353
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 op_signature_t inner_sig = op_->get_signature();
354 33 n_inner_qubits_ = inner_sig.size();
355
1/2
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 33 times.
33 if (std::count(inner_sig.begin(), inner_sig.end(), EdgeType::Quantum) !=
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 n_inner_qubits_) {
357 throw BadOpType(
358 "Quantum control of classical wires not supported", op_->get_type());
359 }
360
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 signature_ = op_signature_t(n_controls + n_inner_qubits_, EdgeType::Quantum);
361 33 }
362
363 4 QControlBox::QControlBox(const QControlBox &other)
364 : Box(other),
365 4 op_(other.op_),
366 4 n_controls_(other.n_controls_),
367 4 n_inner_qubits_(other.n_inner_qubits_) {}
368
369 Op_ptr QControlBox::symbol_substitution(
370 const SymEngine::map_basic_basic &sub_map) const {
371 return std::make_shared<QControlBox>(
372 op_->symbol_substitution(sub_map), n_controls_);
373 }
374
375 SymSet QControlBox::free_symbols() const { return op_->free_symbols(); }
376
377 std::string QControlBox::get_command_str(const unit_vector_t &args) const {
378 std::stringstream out;
379 out << "qif (";
380
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (n_controls_ > 0) {
381 out << args.at(0).repr();
382
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (unsigned i = 1; i < n_controls_; ++i) {
383 out << ", " << args.at(i).repr();
384 }
385 }
386 unit_vector_t inner_args(args.begin() + n_controls_, args.end());
387 out << ") " << op_->get_command_str(inner_args);
388 return out.str();
389 }
390
391 28 void QControlBox::generate_circuit() const {
392
1/2
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 Circuit c(n_inner_qubits_);
393
1/2
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 std::vector<unsigned> qbs(n_inner_qubits_);
394 28 std::iota(qbs.begin(), qbs.end(), 0);
395
1/2
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 c.add_op(op_, qbs);
396
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 c.decompose_boxes_recursively();
397
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 c = with_controls(c, n_controls_);
398
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 circ_ = std::make_shared<Circuit>(c);
399 28 }
400
401 Op_ptr QControlBox::dagger() const {
402 const Op_ptr inner_dagger = op_->dagger();
403 return std::make_shared<QControlBox>(inner_dagger, n_controls_);
404 }
405
406 Op_ptr QControlBox::transpose() const {
407 const Op_ptr inner_transpose = op_->transpose();
408 return std::make_shared<QControlBox>(inner_transpose, n_controls_);
409 }
410
411 2 ProjectorAssertionBox::ProjectorAssertionBox(
412 2 const Eigen::MatrixXcd &m, BasisOrder basis)
413 : Box(OpType::ProjectorAssertionBox),
414
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 m_(basis == BasisOrder::ilo ? m : reverse_indexing(m)),
415
3/6
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
4 expected_readouts_({}) {
416
7/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if ((m.rows() != 2 && m.rows() != 4 && m.rows() != 8) || !is_projector(m)) {
417 throw CircuitInvalidity(
418 "Matrix for ProjectorAssertionBox must be a 2x2, 4x4, or 8x8 "
419 "projector");
420 }
421
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 generate_circuit();
422 2 }
423
424 8 ProjectorAssertionBox::ProjectorAssertionBox(const ProjectorAssertionBox &other)
425
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 : Box(other), m_(other.m_), expected_readouts_(other.expected_readouts_) {}
426
427 Op_ptr ProjectorAssertionBox::dagger() const {
428 return std::make_shared<ProjectorAssertionBox>(m_.adjoint());
429 }
430
431 Op_ptr ProjectorAssertionBox::transpose() const {
432 return std::make_shared<ProjectorAssertionBox>(m_.transpose());
433 }
434
435 32 op_signature_t ProjectorAssertionBox::get_signature() const {
436
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 auto circ_ptr = to_circuit();
437
2/4
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 op_signature_t qubs(circ_ptr->n_qubits(), EdgeType::Quantum);
438
2/4
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
32 op_signature_t bs(circ_ptr->n_bits(), EdgeType::Classical);
439
1/2
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
32 qubs.insert(qubs.end(), bs.begin(), bs.end());
440 64 return qubs;
441 32 }
442
443 2 void ProjectorAssertionBox::generate_circuit() const {
444
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 Circuit c;
445
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 std::tie(c, expected_readouts_) = projector_assertion_synthesis(m_);
446
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 c.decompose_boxes_recursively();
447
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 circ_ = std::make_shared<Circuit>(c);
448 2 }
449
450 5 StabiliserAssertionBox::StabiliserAssertionBox(
451 5 const PauliStabiliserList &paulis)
452 : Box(OpType::StabiliserAssertionBox),
453 7 paulis_(paulis),
454
3/6
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
5 expected_readouts_({}) {
455
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
5 generate_circuit();
456 9 }
457
458 6 StabiliserAssertionBox::StabiliserAssertionBox(
459 6 const StabiliserAssertionBox &other)
460 : Box(other),
461 6 paulis_(other.paulis_),
462
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 expected_readouts_(other.expected_readouts_) {}
463
464 Op_ptr StabiliserAssertionBox::dagger() const {
465 return std::make_shared<StabiliserAssertionBox>(paulis_);
466 }
467
468 Op_ptr StabiliserAssertionBox::transpose() const {
469 PauliStabiliserList new_pauli_list;
470
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (auto &pauli : paulis_) {
471 int y_pauli_counter =
472 std::count(pauli.string.begin(), pauli.string.end(), Pauli::Y);
473
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
if (y_pauli_counter % 2 == 0) {
474 new_pauli_list.push_back(PauliStabiliser(pauli.string, pauli.coeff));
475 } else {
476 new_pauli_list.push_back(PauliStabiliser(pauli.string, !pauli.coeff));
477 };
478 }
479 return std::make_shared<StabiliserAssertionBox>(new_pauli_list);
480 }
481
482 5 void StabiliserAssertionBox::generate_circuit() const {
483
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 Circuit c;
484
3/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
5 std::tie(c, expected_readouts_) = stabiliser_assertion_synthesis(paulis_);
485
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 c.decompose_boxes_recursively();
486
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 circ_ = std::make_shared<Circuit>(c);
487 5 }
488
489 20 op_signature_t StabiliserAssertionBox::get_signature() const {
490
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 auto circ_ptr = to_circuit();
491
2/4
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 op_signature_t qubs(circ_ptr->n_qubits(), EdgeType::Quantum);
492
2/4
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 op_signature_t bs(circ_ptr->n_bits(), EdgeType::Classical);
493
1/2
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
20 qubs.insert(qubs.end(), bs.begin(), bs.end());
494 40 return qubs;
495 20 }
496
497 8 ToffoliBox::ToffoliBox(
498 unsigned _n_qubits,
499 8 std::map<std::vector<bool>, std::vector<bool>> _permutation)
500
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 : Box(OpType::ToffoliBox), n_qubits_(_n_qubits) {
501 // Convert passed permutation to cycles
502
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 8 times.
16 while (!_permutation.empty()) {
503 8 auto it = _permutation.begin();
504
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
24 cycle_permutation_t cycle = {it->first};
505
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
8 if (it->first.size() != this->n_qubits_) {
506 throw std::invalid_argument(
507 "Size of bitstring does not match number of qubits.");
508 }
509
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 it = _permutation.find(it->second);
510
3/4
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 8 times.
0/1
? Decision couldn't be analyzed.
26 while (it->first != cycle[0]) {
511
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 18 times.
18 if (it->first.size() != this->n_qubits_) {
512 throw std::invalid_argument(
513 "Size of bitstring does not match number of qubits.");
514 }
515
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 cycle.push_back(it->first);
516
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 it = _permutation.find(it->second);
517
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 18 times.
18 if (it == _permutation.end()) {
518 throw std::invalid_argument("Permutation is not complete.");
519 }
520 }
521
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
1/2
✓ Decision 'true' taken 8 times.
✗ Decision 'false' not taken.
8 if (cycle.size() > 1) {
522
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 this->cycles_.insert(cycle);
523 }
524
2/2
✓ Branch 5 taken 26 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 8 times.
34 for (const std::vector<bool> &bitstring : cycle) {
525
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 _permutation.erase(bitstring);
526 }
527 8 }
528 8 }
529
530 2 ToffoliBox::ToffoliBox(const ToffoliBox &other)
531
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 : Box(other), n_qubits_(other.n_qubits_), cycles_(other.cycles_) {}
532
533 1 ToffoliBox::ToffoliBox(
534 1 unsigned _n_qubits, const std::set<cycle_permutation_t> &_cycles)
535
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 : Box(OpType::ToffoliBox), n_qubits_(_n_qubits), cycles_(_cycles) {}
536
537 139 unsigned get_hamming_distance(
538 const std::vector<bool> &a, const std::vector<bool> &b) {
539
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 139 times.
139 if (a.size() != b.size()) {
540 throw std::invalid_argument("Bitstrings must have identical size.");
541 }
542 139 unsigned counter = 0;
543
2/2
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 139 times.
2/2
✓ Decision 'true' taken 456 times.
✓ Decision 'false' taken 139 times.
595 for (unsigned i = 0; i < a.size(); i++) {
544
2/2
✓ Branch 2 taken 250 times.
✓ Branch 3 taken 206 times.
2/2
✓ Decision 'true' taken 250 times.
✓ Decision 'false' taken 206 times.
456 if (a[i] != b[i]) {
545 250 ++counter;
546 }
547 }
548 139 return counter;
549 }
550
551 7 ToffoliBox::cycle_transposition_t ToffoliBox::cycle_to_transposition(
552 cycle_permutation_t cycle) const {
553 /**
554 * A cycle can start at any element
555 * A transposition for a cycle can always be constructed by pairing the
556 * starting element with the others in cycle order
557 * This also gives opportunities to produce gray codes with matching elements
558 * that can be cancelled
559 *
560 * For each element in a cycle, produce a sequence of transpositions and
561 * compare total Hamming distance Return the transposition with smallest
562 * Hamming distance
563 *
564 */
565 7 cycle_transposition_t best_transposition;
566 7 unsigned best_hamming_distance = 0;
567
568
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 7 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 7 times.
31 for (unsigned i = 0; i < cycle.size(); i++) {
569 24 unsigned accumulated_hamming_distance = 0;
570 24 cycle_transposition_t transposition;
571
2/2
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 24 times.
2/2
✓ Decision 'true' taken 88 times.
✓ Decision 'false' taken 24 times.
112 for (unsigned j = 1; j < cycle.size(); j++) {
572
4/8
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 88 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 88 times.
✗ Branch 14 not taken.
88 transposition.push_back({cycle[0], cycle[j], cycle[0]});
573
1/2
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
88 accumulated_hamming_distance += get_hamming_distance(cycle[0], cycle[j]);
574 }
575
6/6
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 16 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 21 times.
24 if (best_transposition.empty() ||
576 accumulated_hamming_distance < best_hamming_distance) {
577
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 best_transposition = transposition;
578 8 best_hamming_distance = accumulated_hamming_distance;
579 }
580
1/2
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
24 std::rotate(cycle.begin(), cycle.begin() + 1, cycle.end());
581 24 }
582 7 return best_transposition;
583 }
584
585 7 std::vector<ToffoliBox::cycle_transposition_t> ToffoliBox::get_transpositions()
586 const {
587 7 std::vector<ToffoliBox::cycle_transposition_t> transpositions;
588
2/2
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
14 for (const cycle_permutation_t &cycle : this->cycles_) {
589 // each cycle is costed via the Hamming distance to reduce the number of
590 // operations
591
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
7 transpositions.push_back(this->cycle_to_transposition(cycle));
592 }
593 7 return transpositions;
594 }
595
596 31 Circuit ToffoliBox::get_bitstring_circuit(
597 const std::vector<bool> &bitstring, const unsigned &target) const {
598 // flip qubits that need to be state 0
599
1/2
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
31 Circuit x_circuit(this->n_qubits_);
600 31 std::vector<unsigned> cnx_args;
601
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 31 times.
123 for (unsigned i = 0; i < this->n_qubits_; i++) {
602
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 31 times.
92 if (i != target) {
603
3/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 34 times.
61 if (!bitstring[i]) {
604
2/4
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
27 x_circuit.add_op<unsigned>(OpType::X, {i});
605 }
606
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
61 cnx_args.push_back(i);
607 }
608 }
609
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 cnx_args.push_back(target);
610 TKET_ASSERT(cnx_args.size() == this->n_qubits_);
611
612
1/2
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
31 Circuit return_circuit(this->n_qubits_);
613
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 return_circuit.append(x_circuit);
614
1/2
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
31 return_circuit.add_op<unsigned>(OpType::CnX, cnx_args);
615
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 return_circuit.append(x_circuit);
616 62 return return_circuit;
617 31 }
618
619 17 ToffoliBox::gray_code_t ToffoliBox::transposition_to_gray_code(
620 const ToffoliBox::transposition_t &transposition) const {
621 unsigned first_middle_hamming_distance =
622
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 get_hamming_distance(transposition.first, transposition.middle);
623 unsigned middle_last_hamming_distance =
624
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 get_hamming_distance(transposition.middle, transposition.last);
625 17 ToffoliBox::gray_code_t all_gray_code_entries;
626 // => that some optimisation is done to middle_last, so must go via
627 // transposition.last bitstring to allow proper cancellation
628 // At some point transposition.first == transposition.last
629 // If transposition.last != transposition.first & the hamming distance
630 // between transposition.last and transposition.middle is smaller than
631 // transposition.first and transposition.middle,
632 // then we need to make sure that the gray code between transposition.first
633 // and transposition.middle goes via transposition.last, such that the
634 // eventual gray code between transposition.middle and transposition.last
635 // uncomputes this we can assume that the remaining
636 // transposition.last->transposition.first gray code would be cancelled out if
637 // added
638
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 std::vector<bool> initial = transposition.first;
639
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (middle_last_hamming_distance < first_middle_hamming_distance) {
640 // get bitstrings for first -> last
641
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 5 times.
22 for (unsigned i = 0; i < transposition.first.size(); i++) {
642
4/6
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 11 times.
17 if (transposition.first[i] != transposition.last[i]) {
643
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 initial[i] = !initial[i];
644
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 all_gray_code_entries.push_back({initial, i});
645 }
646 }
647 }
648 // with the right middle bitstring now guaranteed, go from this bitstring to
649 // middle
650
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 std::vector<bool> bitstring = initial;
651
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 17 times.
67 for (unsigned i = 0; i < transposition.first.size(); i++) {
652
4/6
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 50 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 32 times.
50 if (initial[i] != transposition.middle[i]) {
653
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
18 bitstring[i] = !bitstring[i];
654
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 all_gray_code_entries.push_back({bitstring, i});
655 }
656 }
657 // now do the last->middle in reverse to guarantee right
658 // gray code path is taken
659
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 initial = transposition.last;
660 17 ToffoliBox::gray_code_t reverse_gray_code_entries;
661 // as before, implies some optimisation has been completed on
662 // first one
663 // thus make sure that gray code goes via transposition.first
664 // to make applied permutation right
665
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (first_middle_hamming_distance < middle_last_hamming_distance) {
666 // get bitstrings for first -> last
667
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 5 times.
22 for (unsigned i = 0; i < transposition.first.size(); i++) {
668
4/6
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 11 times.
17 if (initial[i] != transposition.first[i]) {
669
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
6 initial[i] = !initial[i];
670
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 reverse_gray_code_entries.push_back({initial, i});
671 }
672 }
673 }
674 // and then go from bitstring to middle
675
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 bitstring = initial;
676
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 17 times.
67 for (unsigned i = 0; i < transposition.middle.size(); i++) {
677
4/6
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 50 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 32 times.
50 if (transposition.middle[i] != initial[i]) {
678
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
18 bitstring[i] = !bitstring[i];
679
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 reverse_gray_code_entries.push_back({bitstring, i});
680 }
681 }
682 // don't want to add transformation for reaching final -> so pop_back
683
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if (!reverse_gray_code_entries.empty()) {
684 17 reverse_gray_code_entries.pop_back();
685 }
686
1/2
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 all_gray_code_entries.insert(
687 17 all_gray_code_entries.end(), reverse_gray_code_entries.rbegin(),
688 17 reverse_gray_code_entries.rend());
689 34 return all_gray_code_entries;
690 17 }
691
692 7 ToffoliBox::cycle_transposition_t ToffoliBox::merge_cycles(
693 std::vector<ToffoliBox::cycle_transposition_t> &cycle_transpositions)
694 const {
695 7 ToffoliBox::cycle_transposition_t return_transposition;
696
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 7 times.
14 for (unsigned k = 0; k < cycle_transpositions.size(); k++) {
697
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 ToffoliBox::cycle_transposition_t cycle = cycle_transpositions[k];
698 7 unsigned i = 0, j = 1;
699
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 7 times.
17 while (j < cycle.size()) {
700
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 ToffoliBox::transposition_t transposition_i = cycle[i];
701
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 ToffoliBox::transposition_t transposition_j = cycle[j];
702
703
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<bool> transposition_j_first = transposition_j.first;
704
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<bool> transposition_i_last = transposition_i.last;
705
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<bool> transposition_i_first = transposition_i.first;
706
707 TKET_ASSERT(transposition_i_last == transposition_j.first);
708
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<bool> i_middle = transposition_i.middle;
709
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 std::vector<bool> j_middle = transposition_j.middle;
710
711 TKET_ASSERT(i_middle.size() == transposition_i.last.size());
712 TKET_ASSERT(j_middle.size() == transposition_i.last.size());
713 // if a transposition has already been reduced, still need to make sure we
714 // uncompute it
715
3/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 6 times.
10 if (transposition_i_first != transposition_i_last) {
716 unsigned middle_last_distance =
717
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 get_hamming_distance(i_middle, transposition_i_last);
718 unsigned middle_first_distance =
719
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 get_hamming_distance(i_middle, transposition_i_first);
720 // this => the reduced transposition is on a good gray code between the
721 // new "first" and target
722
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (middle_first_distance < middle_last_distance &&
723 middle_first_distance > 1) {
724 transposition_i_last = transposition_i_first;
725 std::vector<bool> starting_point = transposition_i_last;
726 for (unsigned k = 0; k < i_middle.size(); k++) {
727 if (i_middle[k] == j_middle[k] &&
728 get_hamming_distance(starting_point, i_middle) > 1) {
729 starting_point[k] = i_middle[k];
730 }
731 }
732
733 cycle_transpositions[k][i].last = starting_point;
734 cycle_transpositions[k][j].first = starting_point;
735 }
736 } else { // else in this case just find any good transposition
737
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<bool> starting_point = transposition_i_last;
738
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 6 times.
27 for (unsigned k = 0; k < i_middle.size(); k++) {
739
6/8
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 8 times.
✓ Branch 10 taken 13 times.
30 if (i_middle[k] == j_middle[k] &&
740
3/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 1 times.
9 get_hamming_distance(starting_point, i_middle) > 1) {
741
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 starting_point[k] = i_middle[k];
742 }
743 }
744
745
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 cycle[i].last = starting_point;
746
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 cycle[j].first = starting_point;
747 6 }
748
749 10 ++i;
750 10 ++j;
751 10 }
752
753
1/2
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 return_transposition.insert(
754 7 return_transposition.end(), cycle.begin(), cycle.end());
755 7 }
756
757 7 return return_transposition;
758 }
759
760 5 op_signature_t ToffoliBox::get_signature() const {
761
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 op_signature_t qubs(this->n_qubits_, EdgeType::Quantum);
762 5 return qubs;
763 }
764
765 7 void ToffoliBox::generate_circuit() const {
766 // This decomposition is as described on page 191, section 4.5.2 "Single
767 // qubit and CNOT gates are universal" of Nielsen & Chuang
768 std::vector<ToffoliBox::cycle_transposition_t> cycle_transpositions =
769
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 this->get_transpositions();
770
771 // optionally, order the transpositions and cycles to allow gate
772 // cancellation
773 7 cycle_transposition_t ordered_transpositions;
774
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 ordered_transpositions = merge_cycles(cycle_transpositions);
775
776
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
7 if (ordered_transpositions.empty()) {
777
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 this->circ_ = std::make_shared<Circuit>(this->n_qubits_);
778 1 return;
779 }
780
781 // Now we have ordered transpositions, produced front->middle and
782 // middle->back gray codes for each transposition and add to circuit
783
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 this->circ_ = std::make_shared<Circuit>(this->n_qubits_);
784
2/2
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 6 times.
23 for (const transposition_t &transposition : ordered_transpositions) {
785 TKET_ASSERT(transposition.first.size() == this->n_qubits_);
786 TKET_ASSERT(transposition.middle.size() == this->n_qubits_);
787 TKET_ASSERT(transposition.last.size() == this->n_qubits_);
788 ToffoliBox::gray_code_t all_gray_code_entries =
789
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 transposition_to_gray_code(transposition);
790 17 for (const std::pair<std::vector<bool>, unsigned> &entry :
791
2/2
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 17 times.
65 all_gray_code_entries) {
792
1/2
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
62 this->circ_->append(
793
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
62 this->get_bitstring_circuit(entry.first, entry.second));
794 }
795 17 }
796
4/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1 times.
8 }
797
798 13 nlohmann::json core_box_json(const Box &box) {
799 13 nlohmann::json j;
800
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
13 j["type"] = box.get_type();
801
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
13 j["id"] = boost::lexical_cast<std::string>(box.get_id());
802 13 return j;
803 }
804
805 1 nlohmann::json CircBox::to_json(const Op_ptr &op) {
806 1 const auto &box = static_cast<const CircBox &>(*op);
807 1 nlohmann::json j = core_box_json(box);
808
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 j["circuit"] = *(box.to_circuit());
809 1 return j;
810 }
811
812 1 Op_ptr CircBox::from_json(const nlohmann::json &j) {
813
3/6
✓ 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.
1 CircBox box = CircBox(j.at("circuit").get<Circuit>());
814 return set_box_id(
815 box,
816
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
817 1 }
818
819 1 nlohmann::json Unitary1qBox::to_json(const Op_ptr &op) {
820 1 const auto &box = static_cast<const Unitary1qBox &>(*op);
821 1 nlohmann::json j = core_box_json(box);
822
3/6
✓ 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.
1 j["matrix"] = box.get_matrix();
823 1 return j;
824 }
825
826 1 Op_ptr Unitary1qBox::from_json(const nlohmann::json &j) {
827
3/6
✓ 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.
1 Unitary1qBox box = Unitary1qBox(j.at("matrix").get<Eigen::Matrix2cd>());
828 return set_box_id(
829 box,
830
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
831 1 }
832
833 1 nlohmann::json Unitary2qBox::to_json(const Op_ptr &op) {
834 1 const auto &box = static_cast<const Unitary2qBox &>(*op);
835 1 nlohmann::json j = core_box_json(box);
836
3/6
✓ 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.
1 j["matrix"] = box.get_matrix();
837 1 return j;
838 }
839
840 1 Op_ptr Unitary2qBox::from_json(const nlohmann::json &j) {
841
3/6
✓ 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.
1 Unitary2qBox box = Unitary2qBox(j.at("matrix").get<Eigen::Matrix4cd>());
842 return set_box_id(
843 box,
844
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
845 1 }
846 1 nlohmann::json Unitary3qBox::to_json(const Op_ptr &op) {
847 1 const auto &box = static_cast<const Unitary3qBox &>(*op);
848 1 nlohmann::json j = core_box_json(box);
849
3/6
✓ 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.
1 j["matrix"] = box.get_matrix();
850 1 return j;
851 }
852
853 1 Op_ptr Unitary3qBox::from_json(const nlohmann::json &j) {
854
3/6
✓ 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.
1 Unitary3qBox box = Unitary3qBox(j.at("matrix").get<Matrix8cd>());
855 return set_box_id(
856 box,
857
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
858 1 }
859
860 1 nlohmann::json ExpBox::to_json(const Op_ptr &op) {
861 1 const auto &box = static_cast<const ExpBox &>(*op);
862
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 nlohmann::json j = core_box_json(box);
863
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const auto &matrix_phase = box.get_matrix_and_phase();
864
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 j["matrix"] = matrix_phase.first;
865
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 j["phase"] = matrix_phase.second;
866 2 return j;
867 }
868
869 1 Op_ptr ExpBox::from_json(const nlohmann::json &j) {
870 ExpBox box = ExpBox(
871
5/10
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
1 j.at("matrix").get<Eigen::Matrix4cd>(), j.at("phase").get<double>());
872 return set_box_id(
873 box,
874
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
875 1 }
876
877 1 nlohmann::json PauliExpBox::to_json(const Op_ptr &op) {
878 1 const auto &box = static_cast<const PauliExpBox &>(*op);
879 1 nlohmann::json j = core_box_json(box);
880
3/6
✓ 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.
1 j["paulis"] = box.get_paulis();
881
3/6
✓ 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.
1 j["phase"] = box.get_phase();
882 1 return j;
883 }
884
885 1 Op_ptr PauliExpBox::from_json(const nlohmann::json &j) {
886 PauliExpBox box = PauliExpBox(
887
5/10
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
2 j.at("paulis").get<std::vector<Pauli>>(), j.at("phase").get<Expr>());
888 return set_box_id(
889 box,
890
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
891 1 }
892
893 1 nlohmann::json ToffoliBox::to_json(const Op_ptr &op) {
894 1 const auto &box = static_cast<const ToffoliBox &>(*op);
895 1 nlohmann::json j = core_box_json(box);
896
3/6
✓ 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.
1 j["cycles"] = box.get_cycles();
897
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 j["n_qubits"] = box.get_n_qubits();
898 1 return j;
899 }
900
901 1 Op_ptr ToffoliBox::from_json(const nlohmann::json &j) {
902 ToffoliBox box = ToffoliBox(
903
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 j.at("n_qubits").get<unsigned>(),
904
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.
2 j.at("cycles").get<std::set<ToffoliBox::cycle_permutation_t>>());
905 return set_box_id(
906 box,
907
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
908 1 }
909
910 2 void to_json(nlohmann::json &j, const composite_def_ptr_t &cdef) {
911
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 j["name"] = cdef->get_name();
912
2/4
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 j["definition"] = *cdef->get_def();
913
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 j["args"] = cdef->get_args();
914 2 }
915
916 2 void from_json(const nlohmann::json &j, composite_def_ptr_t &cdef) {
917
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 cdef = CompositeGateDef::define_gate(
918
4/8
✓ 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.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
4 j.at("name").get<std::string>(), j.at("definition").get<Circuit>(),
919 6 j.at("args").get<std::vector<Sym>>());
920 2 }
921
922 2 nlohmann::json CustomGate::to_json(const Op_ptr &op) {
923 2 const auto &box = static_cast<const CustomGate &>(*op);
924 2 nlohmann::json j = core_box_json(box);
925
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 j["gate"] = box.get_gate();
926
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 j["params"] = box.get_params();
927 2 return j;
928 }
929
930 2 Op_ptr CustomGate::from_json(const nlohmann::json &j) {
931 CustomGate box = CustomGate(
932
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 j.at("gate").get<composite_def_ptr_t>(),
933
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.
4 j.at("params").get<std::vector<Expr>>());
934 return set_box_id(
935 box,
936
4/8
✓ 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.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
6 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
937 2 }
938
939 1 nlohmann::json QControlBox::to_json(const Op_ptr &op) {
940 1 const auto &box = static_cast<const QControlBox &>(*op);
941 1 nlohmann::json j = core_box_json(box);
942
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 j["n_controls"] = box.get_n_controls();
943
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 j["op"] = box.get_op();
944 1 return j;
945 }
946
947 1 Op_ptr QControlBox::from_json(const nlohmann::json &j) {
948 QControlBox box =
949
5/10
✓ 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.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
1 QControlBox(j.at("op").get<Op_ptr>(), j.at("n_controls").get<unsigned>());
950 return set_box_id(
951 box,
952
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
953 1 }
954
955 nlohmann::json ProjectorAssertionBox::to_json(const Op_ptr &op) {
956 const auto &box = static_cast<const ProjectorAssertionBox &>(*op);
957 nlohmann::json j = core_box_json(box);
958 j["matrix"] = box.get_matrix();
959 return j;
960 }
961
962 Op_ptr ProjectorAssertionBox::from_json(const nlohmann::json &j) {
963 ProjectorAssertionBox box =
964 ProjectorAssertionBox(j.at("matrix").get<Eigen::MatrixXcd>());
965 return set_box_id(
966 box,
967 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
968 }
969
970 1 nlohmann::json StabiliserAssertionBox::to_json(const Op_ptr &op) {
971 1 const auto &box = static_cast<const StabiliserAssertionBox &>(*op);
972 1 nlohmann::json j = core_box_json(box);
973
3/6
✓ 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.
1 j["stabilisers"] = box.get_stabilisers();
974 1 return j;
975 }
976
977 1 Op_ptr StabiliserAssertionBox::from_json(const nlohmann::json &j) {
978 StabiliserAssertionBox box =
979
3/6
✓ 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.
1 StabiliserAssertionBox(j.at("stabilisers").get<PauliStabiliserList>());
980 return set_box_id(
981 box,
982
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.
3 boost::lexical_cast<boost::uuids::uuid>(j.at("id").get<std::string>()));
983 1 }
984
985 // use macro to register converters defined in this file with OpJsonFactory
986 REGISTER_OPFACTORY(CircBox, CircBox)
987 REGISTER_OPFACTORY(Unitary1qBox, Unitary1qBox)
988 REGISTER_OPFACTORY(Unitary2qBox, Unitary2qBox)
989 REGISTER_OPFACTORY(Unitary3qBox, Unitary3qBox)
990 REGISTER_OPFACTORY(ExpBox, ExpBox)
991 REGISTER_OPFACTORY(PauliExpBox, PauliExpBox)
992 REGISTER_OPFACTORY(CustomGate, CustomGate)
993 REGISTER_OPFACTORY(QControlBox, QControlBox)
994 REGISTER_OPFACTORY(ProjectorAssertionBox, ProjectorAssertionBox)
995 REGISTER_OPFACTORY(StabiliserAssertionBox, StabiliserAssertionBox)
996 REGISTER_OPFACTORY(ToffoliBox, ToffoliBox)
997 } // namespace tket
998