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 | #pragma once | |||
16 | ||||
17 | #include <boost/uuid/uuid.hpp> | |||
18 | #include <boost/uuid/uuid_generators.hpp> | |||
19 | #include <boost/uuid/uuid_io.hpp> | |||
20 | #include <memory> | |||
21 | ||||
22 | #include "OpType/OpTypeInfo.hpp" | |||
23 | #include "Ops/Op.hpp" | |||
24 | #include "Utils/BiMapHeaders.hpp" | |||
25 | #include "Utils/EigenConfig.hpp" | |||
26 | #include "Utils/Json.hpp" | |||
27 | #include "Utils/MatrixAnalysis.hpp" | |||
28 | #include "Utils/UnitID.hpp" | |||
29 | ||||
30 | namespace tket { | |||
31 | ||||
32 | class Circuit; | |||
33 | ||||
34 | /** | |||
35 | * Abstract class for an operation from which a circuit can be extracted | |||
36 | */ | |||
37 | class Box : public Op { | |||
38 | public: | |||
39 | 2492 | explicit Box(const OpType &type, const op_signature_t &signature = {}) | ||
40 |
2/4✓ Branch 2 taken 2492 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2492 times.
✗ Branch 7 not taken.
|
2492 | : Op(type), signature_(signature), circ_(), id_(idgen()) { | |
41 |
2/6✓ Branch 1 taken 2492 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2492 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1/2✓ Decision 'true' taken 2492 times.
✗ Decision 'false' not taken.
|
2492 | if (!is_box_type(type)) throw BadOpType(type); |
42 | 2492 | } | ||
43 | ||||
44 | 414 | Box(const Box &other) | ||
45 | ✗ | : Op(other.get_type()), | ||
46 | 414 | signature_(other.signature_), | ||
47 | 414 | circ_(other.circ_), | ||
48 |
2/4✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 414 times.
✗ Branch 6 not taken.
|
828 | id_(other.id_) {} | |
49 | ||||
50 | /** Number of Quantum inputs */ | |||
51 | unsigned n_qubits() const override; | |||
52 | ||||
53 | /** Number of Boolean inputs */ | |||
54 | unsigned n_boolean() const; | |||
55 | ||||
56 | /** Number of Classical inputs */ | |||
57 | unsigned n_classical() const; | |||
58 | ||||
59 | op_signature_t get_signature() const override; | |||
60 | ||||
61 | nlohmann::json serialize() const override; | |||
62 | ||||
63 | static Op_ptr deserialize(const nlohmann::json &j); | |||
64 | ||||
65 | /** Circuit represented by box */ | |||
66 | ✗ | std::shared_ptr<Circuit> to_circuit() const { | ||
67 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (circ_ == nullptr) generate_circuit(); | |
68 | ✗ | return circ_; | ||
69 | }; | |||
70 | ||||
71 | /** Unique identifier (preserved on copy) */ | |||
72 | ✗ | boost::uuids::uuid get_id() const { return id_; } | ||
73 | ||||
74 | template <typename BoxT> | |||
75 | friend Op_ptr set_box_id(BoxT &b, boost::uuids::uuid newid); | |||
76 | ||||
77 | protected: | |||
78 | 2492 | static boost::uuids::uuid idgen() { | ||
79 | static boost::uuids::random_generator gen = {}; | |||
80 | ||||
81 | 2492 | return gen(); | ||
82 | } | |||
83 | op_signature_t signature_; | |||
84 | mutable std::shared_ptr<Circuit> circ_; | |||
85 | boost::uuids::uuid id_; | |||
86 | ||||
87 | virtual void generate_circuit() const = 0; | |||
88 | }; | |||
89 | ||||
90 | // json for base Box attributes | |||
91 | nlohmann::json core_box_json(const Box &box); | |||
92 | ||||
93 | /** | |||
94 | * @brief Set explicit ID on a box | |||
95 | * | |||
96 | * This is used for deserialization. | |||
97 | * | |||
98 | * @param b box | |||
99 | * @param[in] newid new ID | |||
100 | * | |||
101 | * @tparam BoxT concrete box type | |||
102 | * | |||
103 | * @return box with desired ID | |||
104 | */ | |||
105 | template <typename BoxT> | |||
106 | 23 | Op_ptr set_box_id(BoxT &b, boost::uuids::uuid newid) { | ||
107 | 23 | b.id_ = newid; | ||
108 | 23 | return std::make_shared<BoxT>(b); | ||
109 | } | |||
110 | ||||
111 | /** | |||
112 | * Operation defined as a circuit. | |||
113 | */ | |||
114 | class CircBox : public Box { | |||
115 | public: | |||
116 | /** | |||
117 | * Construct from a given circuit. The circuit must be simple. | |||
118 | */ | |||
119 | explicit CircBox(const Circuit &circ); | |||
120 | ||||
121 | /** | |||
122 | * Construct from the empty circuit | |||
123 | */ | |||
124 | CircBox(); | |||
125 | ||||
126 | /** | |||
127 | * Copy constructor | |||
128 | */ | |||
129 | CircBox(const CircBox &other); | |||
130 | ||||
131 | ✗ | ~CircBox() override {} | ||
132 | ||||
133 | bool is_clifford() const override; | |||
134 | ||||
135 | Op_ptr symbol_substitution( | |||
136 | const SymEngine::map_basic_basic &sub_map) const override; | |||
137 | ||||
138 | SymSet free_symbols() const override; | |||
139 | ||||
140 | /** | |||
141 | * Equality check between two CircBox instances | |||
142 | */ | |||
143 | 3 | bool is_equal(const Op &op_other) const override { | ||
144 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const CircBox &other = dynamic_cast<const CircBox &>(op_other); | |
145 | 3 | return id_ == other.get_id(); | ||
146 | } | |||
147 | ||||
148 | Op_ptr dagger() const override; | |||
149 | ||||
150 | Op_ptr transpose() const override; | |||
151 | ||||
152 | static Op_ptr from_json(const nlohmann::json &j); | |||
153 | ||||
154 | static nlohmann::json to_json(const Op_ptr &op); | |||
155 | ||||
156 | protected: | |||
157 | ✗ | void generate_circuit() const override {} // Already set by constructor | ||
158 | }; | |||
159 | ||||
160 | /** | |||
161 | * One-qubit operation defined as a unitary matrix | |||
162 | */ | |||
163 | class Unitary1qBox : public Box { | |||
164 | public: | |||
165 | /** | |||
166 | * Construct from a given 2x2 unitary matrix | |||
167 | * | |||
168 | * @param m unitary matrix | |||
169 | */ | |||
170 | explicit Unitary1qBox(const Eigen::Matrix2cd &m); | |||
171 | ||||
172 | /** | |||
173 | * Construct from the identity matrix | |||
174 | */ | |||
175 | Unitary1qBox(); | |||
176 | ||||
177 | /** | |||
178 | * Copy constructor | |||
179 | */ | |||
180 | Unitary1qBox(const Unitary1qBox &other); | |||
181 | ||||
182 | ✗ | ~Unitary1qBox() override {} | ||
183 | ||||
184 | ✗ | Op_ptr symbol_substitution( | ||
185 | const SymEngine::map_basic_basic &) const override { | |||
186 | ✗ | return Op_ptr(); | ||
187 | } | |||
188 | ||||
189 | ✗ | SymSet free_symbols() const override { return {}; } | ||
190 | ||||
191 | /** | |||
192 | * Equality check between two Unitary1qBox instances | |||
193 | */ | |||
194 | 3 | bool is_equal(const Op &op_other) const override { | ||
195 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const Unitary1qBox &other = dynamic_cast<const Unitary1qBox &>(op_other); | |
196 | 3 | return id_ == other.get_id(); | ||
197 | } | |||
198 | ||||
199 | /** Get the unitary matrix correspnding to this operation */ | |||
200 | ✗ | Eigen::Matrix2cd get_matrix() const { return m_; } | ||
201 | ||||
202 | ✗ | Eigen::MatrixXcd get_unitary() const override { return m_; } | ||
203 | ||||
204 | Op_ptr dagger() const override; | |||
205 | ||||
206 | Op_ptr transpose() const override; | |||
207 | ||||
208 | bool is_clifford() const override; | |||
209 | ||||
210 | static Op_ptr from_json(const nlohmann::json &j); | |||
211 | ||||
212 | static nlohmann::json to_json(const Op_ptr &op); | |||
213 | ||||
214 | protected: | |||
215 | void generate_circuit() const override; | |||
216 | ||||
217 | private: | |||
218 | const Eigen::Matrix2cd m_; | |||
219 | }; | |||
220 | ||||
221 | /** | |||
222 | * Two-qubit operation defined as a unitary matrix (ILO-BE) | |||
223 | */ | |||
224 | class Unitary2qBox : public Box { | |||
225 | public: | |||
226 | /** | |||
227 | * Construct from a given 4x4 unitary matrix | |||
228 | * | |||
229 | * @param m unitary matrix | |||
230 | * @param basis basis order convention for matrix | |||
231 | */ | |||
232 | explicit Unitary2qBox( | |||
233 | const Eigen::Matrix4cd &m, BasisOrder basis = BasisOrder::ilo); | |||
234 | ||||
235 | /** | |||
236 | * Construct from the identity matrix | |||
237 | */ | |||
238 | Unitary2qBox(); | |||
239 | ||||
240 | /** | |||
241 | * Copy constructor | |||
242 | */ | |||
243 | Unitary2qBox(const Unitary2qBox &other); | |||
244 | ||||
245 | ✗ | ~Unitary2qBox() override {} | ||
246 | ||||
247 | ✗ | Op_ptr symbol_substitution( | ||
248 | const SymEngine::map_basic_basic &) const override { | |||
249 | ✗ | return Op_ptr(); | ||
250 | } | |||
251 | ||||
252 | ✗ | SymSet free_symbols() const override { return {}; } | ||
253 | ||||
254 | /** | |||
255 | * Equality check between two Unitary2qBox instances | |||
256 | */ | |||
257 | 6 | bool is_equal(const Op &op_other) const override { | ||
258 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | const Unitary2qBox &other = dynamic_cast<const Unitary2qBox &>(op_other); | |
259 | 6 | return id_ == other.get_id(); | ||
260 | } | |||
261 | ||||
262 | /** Get the unitary matrix correspnding to this operation */ | |||
263 | ✗ | Eigen::Matrix4cd get_matrix() const { return m_; } | ||
264 | ||||
265 | 2 | Eigen::MatrixXcd get_unitary() const override { return m_; } | ||
266 | ||||
267 | Op_ptr dagger() const override; | |||
268 | ||||
269 | Op_ptr transpose() const override; | |||
270 | ||||
271 | static Op_ptr from_json(const nlohmann::json &j); | |||
272 | ||||
273 | static nlohmann::json to_json(const Op_ptr &op); | |||
274 | ||||
275 | protected: | |||
276 | void generate_circuit() const override; | |||
277 | ||||
278 | private: | |||
279 | const Eigen::Matrix4cd m_; | |||
280 | }; | |||
281 | ||||
282 | /** | |||
283 | * Three-qubit operation defined as a unitary matrix (ILO-BE) | |||
284 | */ | |||
285 | class Unitary3qBox : public Box { | |||
286 | public: | |||
287 | /** | |||
288 | * Construct from a given 8x8 unitary matrix | |||
289 | * | |||
290 | * @param m unitary matrix | |||
291 | * @param basis basis order convention for matrix | |||
292 | */ | |||
293 | explicit Unitary3qBox(const Matrix8cd &m, BasisOrder basis = BasisOrder::ilo); | |||
294 | ||||
295 | /** | |||
296 | * Construct from the identity matrix | |||
297 | */ | |||
298 | Unitary3qBox(); | |||
299 | ||||
300 | /** | |||
301 | * Copy constructor | |||
302 | */ | |||
303 | Unitary3qBox(const Unitary3qBox &other); | |||
304 | ||||
305 | ✗ | ~Unitary3qBox() override {} | ||
306 | ||||
307 | ✗ | Op_ptr symbol_substitution( | ||
308 | const SymEngine::map_basic_basic &) const override { | |||
309 | ✗ | return Op_ptr(); | ||
310 | } | |||
311 | ||||
312 | ✗ | SymSet free_symbols() const override { return {}; } | ||
313 | ||||
314 | /** | |||
315 | * Equality check between two Unitary3qBox instances | |||
316 | */ | |||
317 | 3 | bool is_equal(const Op &op_other) const override { | ||
318 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const Unitary3qBox &other = dynamic_cast<const Unitary3qBox &>(op_other); | |
319 | 3 | return id_ == other.get_id(); | ||
320 | } | |||
321 | ||||
322 | /** Get the unitary matrix correspnding to this operation */ | |||
323 | ✗ | Matrix8cd get_matrix() const { return m_; } | ||
324 | ||||
325 | ✗ | Eigen::MatrixXcd get_unitary() const override { return m_; } | ||
326 | ||||
327 | Op_ptr dagger() const override; | |||
328 | ||||
329 | Op_ptr transpose() const override; | |||
330 | ||||
331 | static Op_ptr from_json(const nlohmann::json &j); | |||
332 | ||||
333 | static nlohmann::json to_json(const Op_ptr &op); | |||
334 | ||||
335 | protected: | |||
336 | void generate_circuit() const override; | |||
337 | ||||
338 | private: | |||
339 | const Matrix8cd m_; | |||
340 | }; | |||
341 | ||||
342 | /** | |||
343 | * Two-qubit operation defined in terms of a hermitian matrix and a phase. | |||
344 | * | |||
345 | * The unitary corresponding to the matrix A and phase t is exp(i*t*A). | |||
346 | * Matrix A is stored in ILO-BE form. | |||
347 | */ | |||
348 | class ExpBox : public Box { | |||
349 | public: | |||
350 | /** | |||
351 | * Construct from a given 4x4 hermitian matrix and optional phase. | |||
352 | * | |||
353 | * @param A hermitian matrix | |||
354 | * @param t phase to apply | |||
355 | * @param basis basis order convention for matrix | |||
356 | */ | |||
357 | ExpBox( | |||
358 | const Eigen::Matrix4cd &A, double t = 1., | |||
359 | BasisOrder basis = BasisOrder::ilo); | |||
360 | ||||
361 | /** | |||
362 | * Construct from the zero matrix (resulting in the identity) | |||
363 | */ | |||
364 | ExpBox(); | |||
365 | ||||
366 | /** | |||
367 | * Copy constructor | |||
368 | */ | |||
369 | ExpBox(const ExpBox &other); | |||
370 | ||||
371 | ✗ | ~ExpBox() override {} | ||
372 | ||||
373 | ✗ | Op_ptr symbol_substitution( | ||
374 | const SymEngine::map_basic_basic &) const override { | |||
375 | ✗ | return Op_ptr(); | ||
376 | } | |||
377 | ||||
378 | ✗ | SymSet free_symbols() const override { return {}; } | ||
379 | ||||
380 | /** | |||
381 | * Equality check between two ExpBox instances | |||
382 | */ | |||
383 | 3 | bool is_equal(const Op &op_other) const override { | ||
384 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const ExpBox &other = dynamic_cast<const ExpBox &>(op_other); | |
385 | 3 | return id_ == other.get_id(); | ||
386 | } | |||
387 | ||||
388 | /** Get the hermitian matrix and phase parameter */ | |||
389 | ✗ | std::pair<Eigen::Matrix4cd, double> get_matrix_and_phase() const { | ||
390 | ✗ | return std::make_pair(A_, t_); | ||
391 | } | |||
392 | ||||
393 | Op_ptr dagger() const override; | |||
394 | ||||
395 | Op_ptr transpose() const override; | |||
396 | ||||
397 | static Op_ptr from_json(const nlohmann::json &j); | |||
398 | ||||
399 | static nlohmann::json to_json(const Op_ptr &op); | |||
400 | ||||
401 | protected: | |||
402 | void generate_circuit() const override; | |||
403 | ||||
404 | private: | |||
405 | const Eigen::Matrix4cd A_; | |||
406 | double t_; | |||
407 | }; | |||
408 | ||||
409 | /** | |||
410 | * Operation defined as the exponential of a tensor of Pauli operators | |||
411 | */ | |||
412 | class PauliExpBox : public Box { | |||
413 | public: | |||
414 | /** | |||
415 | * The operation implements the unitary operator | |||
416 | * \f$ e^{-\frac12 i \pi t \sigma_0 \otimes \sigma_1 \otimes \cdots} \f$ | |||
417 | * where \f$ \sigma_i \in \{I,X,Y,Z\} \f$ are the Pauli operators. | |||
418 | */ | |||
419 | PauliExpBox(const std::vector<Pauli> &paulis, const Expr &t); | |||
420 | ||||
421 | /** | |||
422 | * Construct from the empty vector | |||
423 | */ | |||
424 | PauliExpBox(); | |||
425 | ||||
426 | /** | |||
427 | * Copy constructor | |||
428 | */ | |||
429 | PauliExpBox(const PauliExpBox &other); | |||
430 | ||||
431 | ✗ | ~PauliExpBox() override {} | ||
432 | ||||
433 | bool is_clifford() const override; | |||
434 | ||||
435 | SymSet free_symbols() const override; | |||
436 | ||||
437 | /** | |||
438 | * Equality check between two PauliExpBox instances | |||
439 | */ | |||
440 | 3 | bool is_equal(const Op &op_other) const override { | ||
441 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const PauliExpBox &other = dynamic_cast<const PauliExpBox &>(op_other); | |
442 | 3 | return id_ == other.get_id(); | ||
443 | } | |||
444 | ||||
445 | /** Get the Pauli string */ | |||
446 | ✗ | std::vector<Pauli> get_paulis() const { return paulis_; } | ||
447 | ||||
448 | /** Get the phase parameter */ | |||
449 | ✗ | Expr get_phase() const { return t_; } | ||
450 | ||||
451 | Op_ptr dagger() const override; | |||
452 | ||||
453 | Op_ptr transpose() const override; | |||
454 | ||||
455 | Op_ptr symbol_substitution( | |||
456 | const SymEngine::map_basic_basic &sub_map) const override; | |||
457 | ||||
458 | static Op_ptr from_json(const nlohmann::json &j); | |||
459 | ||||
460 | static nlohmann::json to_json(const Op_ptr &op); | |||
461 | ||||
462 | protected: | |||
463 | void generate_circuit() const override; | |||
464 | ||||
465 | private: | |||
466 | std::vector<Pauli> paulis_; | |||
467 | Expr t_; | |||
468 | }; | |||
469 | ||||
470 | class CompositeGateDef; | |||
471 | typedef std::shared_ptr<CompositeGateDef> composite_def_ptr_t; | |||
472 | ||||
473 | // CompositeGateDef | |||
474 | JSON_DECL(composite_def_ptr_t) | |||
475 | ||||
476 | class CompositeGateDef : public std::enable_shared_from_this<CompositeGateDef> { | |||
477 | public: | |||
478 | CompositeGateDef( | |||
479 | const std::string &name, const Circuit &def, | |||
480 | const std::vector<Sym> &args); | |||
481 | ||||
482 | static composite_def_ptr_t define_gate( | |||
483 | const std::string &name, const Circuit &def, | |||
484 | const std::vector<Sym> &args); | |||
485 | ||||
486 | Circuit instance(const std::vector<Expr> ¶ms) const; | |||
487 | ||||
488 | 13 | std::string get_name() const { return name_; } | ||
489 | 2 | std::vector<Sym> get_args() const { return args_; } | ||
490 | 8 | std::shared_ptr<Circuit> get_def() const { return def_; } | ||
491 | 16 | unsigned n_args() const { return args_.size(); } | ||
492 | op_signature_t signature() const; | |||
493 | ||||
494 | bool operator==(const CompositeGateDef &other) const; | |||
495 | ||||
496 | private: | |||
497 | std::string name_; | |||
498 | std::shared_ptr<Circuit> def_; | |||
499 | std::vector<Sym> args_; | |||
500 | ||||
501 | CompositeGateDef() {} | |||
502 | }; | |||
503 | ||||
504 | class CustomGate : public Box { | |||
505 | public: | |||
506 | CustomGate(const composite_def_ptr_t &gate, const std::vector<Expr> ¶ms); | |||
507 | CustomGate(const CustomGate &other); | |||
508 | ||||
509 | SymSet free_symbols() const override; | |||
510 | ||||
511 | ✗ | composite_def_ptr_t get_gate() const { return gate_; } | ||
512 | ✗ | std::vector<Expr> get_params() const override { return params_; } | ||
513 | std::string get_name(bool latex = false) const override; | |||
514 | ||||
515 | Op_ptr symbol_substitution( | |||
516 | const SymEngine::map_basic_basic &sub_map) const override; | |||
517 | ||||
518 | /** | |||
519 | * Equality check between two CustomGate instances. | |||
520 | * This does more than simply checking id_. | |||
521 | */ | |||
522 | bool is_equal(const Op &op_other) const override; | |||
523 | ||||
524 | static Op_ptr from_json(const nlohmann::json &j); | |||
525 | ||||
526 | static nlohmann::json to_json(const Op_ptr &op); | |||
527 | ||||
528 | bool is_clifford() const override; | |||
529 | ||||
530 | protected: | |||
531 | void generate_circuit() const override; | |||
532 | CustomGate() : Box(OpType::CustomGate), gate_(), params_() {} | |||
533 | ||||
534 | private: | |||
535 | composite_def_ptr_t gate_; | |||
536 | const std::vector<Expr> params_; | |||
537 | }; | |||
538 | ||||
539 | /** | |||
540 | * Wraps another quantum op, adding control qubits | |||
541 | */ | |||
542 | class QControlBox : public Box { | |||
543 | public: | |||
544 | /** | |||
545 | * Construct from a given op and number of controls | |||
546 | * | |||
547 | * @param op op to control | |||
548 | * @param n_controls number of qubit controls to add | |||
549 | */ | |||
550 | explicit QControlBox(const Op_ptr &op, unsigned n_controls = 1); | |||
551 | ||||
552 | /** | |||
553 | * Copy constructor | |||
554 | */ | |||
555 | QControlBox(const QControlBox &other); | |||
556 | ||||
557 | ✗ | ~QControlBox() override {} | ||
558 | ||||
559 | Op_ptr symbol_substitution( | |||
560 | const SymEngine::map_basic_basic &sub_map) const override; | |||
561 | ||||
562 | SymSet free_symbols() const override; | |||
563 | ||||
564 | /** | |||
565 | * Equality check between two QControlBox instances | |||
566 | */ | |||
567 | 3 | bool is_equal(const Op &op_other) const override { | ||
568 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | const QControlBox &other = dynamic_cast<const QControlBox &>(op_other); | |
569 | 3 | return id_ == other.get_id(); | ||
570 | } | |||
571 | ||||
572 | std::string get_command_str(const unit_vector_t &args) const override; | |||
573 | ||||
574 | Op_ptr dagger() const override; | |||
575 | ||||
576 | Op_ptr transpose() const override; | |||
577 | ||||
578 | ✗ | Op_ptr get_op() const { return op_; } | ||
579 | ✗ | unsigned get_n_controls() const { return n_controls_; } | ||
580 | ||||
581 | static Op_ptr from_json(const nlohmann::json &j); | |||
582 | ||||
583 | static nlohmann::json to_json(const Op_ptr &op); | |||
584 | ||||
585 | protected: | |||
586 | void generate_circuit() const override; | |||
587 | QControlBox() | |||
588 | : Box(OpType::QControlBox), op_(), n_controls_(0), n_inner_qubits_(0) {} | |||
589 | ||||
590 | private: | |||
591 | const Op_ptr op_; | |||
592 | const unsigned n_controls_; | |||
593 | unsigned n_inner_qubits_; | |||
594 | }; | |||
595 | ||||
596 | class ProjectorAssertionBox : public Box { | |||
597 | public: | |||
598 | /** | |||
599 | * Construct from a given 2x2, 4x4 or 8x8 projector matrix | |||
600 | * | |||
601 | * @param m projector matrix | |||
602 | * @param basis basis order convention for matrix | |||
603 | */ | |||
604 | explicit ProjectorAssertionBox( | |||
605 | const Eigen::MatrixXcd &m, BasisOrder basis = BasisOrder::ilo); | |||
606 | ||||
607 | /** | |||
608 | * Copy constructor | |||
609 | */ | |||
610 | ProjectorAssertionBox(const ProjectorAssertionBox &other); | |||
611 | ||||
612 | ✗ | ~ProjectorAssertionBox() override {} | ||
613 | ||||
614 | ✗ | Op_ptr symbol_substitution( | ||
615 | const SymEngine::map_basic_basic &) const override { | |||
616 | ✗ | return Op_ptr(); | ||
617 | } | |||
618 | ||||
619 | ✗ | SymSet free_symbols() const override { return {}; } | ||
620 | ||||
621 | /** | |||
622 | * Equality check between two ProjectorAssertionBox instances | |||
623 | */ | |||
624 | ✗ | bool is_equal(const Op &op_other) const override { | ||
625 | const ProjectorAssertionBox &other = | |||
626 | ✗ | dynamic_cast<const ProjectorAssertionBox &>(op_other); | ||
627 | ✗ | return id_ == other.get_id(); | ||
628 | } | |||
629 | ||||
630 | /** Get the unitary matrix correspnding to this operation */ | |||
631 | 8 | Eigen::MatrixXcd get_matrix() const { return m_; } | ||
632 | 8 | std::vector<bool> get_expected_readouts() const { return expected_readouts_; } | ||
633 | ||||
634 | Op_ptr dagger() const override; | |||
635 | ||||
636 | Op_ptr transpose() const override; | |||
637 | ||||
638 | op_signature_t get_signature() const override; | |||
639 | ||||
640 | static Op_ptr from_json(const nlohmann::json &j); | |||
641 | ||||
642 | static nlohmann::json to_json(const Op_ptr &op); | |||
643 | ||||
644 | protected: | |||
645 | void generate_circuit() const override; | |||
646 | ||||
647 | private: | |||
648 | const Eigen::MatrixXcd m_; | |||
649 | // expected readouts the debug bits | |||
650 | // false -> 0 | |||
651 | // true -> 1 | |||
652 | mutable std::vector<bool> expected_readouts_; | |||
653 | }; | |||
654 | ||||
655 | class StabiliserAssertionBox : public Box { | |||
656 | public: | |||
657 | /** | |||
658 | * Construct from a set of stabiliser Pauli strings | |||
659 | * | |||
660 | * @param paulis a set of stabiliser Pauli strings | |||
661 | */ | |||
662 | explicit StabiliserAssertionBox(const PauliStabiliserList &paulis); | |||
663 | ||||
664 | /** | |||
665 | * Copy constructor | |||
666 | */ | |||
667 | StabiliserAssertionBox(const StabiliserAssertionBox &other); | |||
668 | ||||
669 | ✗ | ~StabiliserAssertionBox() override {} | ||
670 | ✗ | Op_ptr symbol_substitution( | ||
671 | const SymEngine::map_basic_basic &) const override { | |||
672 | ✗ | return Op_ptr(); | ||
673 | } | |||
674 | ||||
675 | ✗ | SymSet free_symbols() const override { return {}; } | ||
676 | ||||
677 | /** | |||
678 | * Equality check between two StabiliserAssertionBox instances | |||
679 | */ | |||
680 | ✗ | bool is_equal(const Op &op_other) const override { | ||
681 | const StabiliserAssertionBox &other = | |||
682 | ✗ | dynamic_cast<const StabiliserAssertionBox &>(op_other); | ||
683 | ✗ | return id_ == other.get_id(); | ||
684 | } | |||
685 | ||||
686 | /** Get the pauli stabilisers */ | |||
687 | ✗ | PauliStabiliserList get_stabilisers() const { return paulis_; } | ||
688 | 5 | std::vector<bool> get_expected_readouts() const { return expected_readouts_; } | ||
689 | ||||
690 | Op_ptr dagger() const override; | |||
691 | ||||
692 | Op_ptr transpose() const override; | |||
693 | ||||
694 | static Op_ptr from_json(const nlohmann::json &j); | |||
695 | ||||
696 | static nlohmann::json to_json(const Op_ptr &op); | |||
697 | ||||
698 | op_signature_t get_signature() const override; | |||
699 | ||||
700 | protected: | |||
701 | void generate_circuit() const override; | |||
702 | ||||
703 | private: | |||
704 | const PauliStabiliserList paulis_; | |||
705 | // expected readouts the debug bits | |||
706 | // false -> 0 | |||
707 | // true -> 1 | |||
708 | mutable std::vector<bool> expected_readouts_; | |||
709 | }; | |||
710 | ||||
711 | class ToffoliBox : public Box { | |||
712 | public: | |||
713 | /** | |||
714 | * A cycle is a vector of basis states such that the first | |||
715 | * is mapped to the second, the second to the third, etc, | |||
716 | * with the final mapped to the first. The ordering is unique but the | |||
717 | * vector can be rotated without effecting the meaning. | |||
718 | */ | |||
719 | typedef std::vector<std::vector<bool>> cycle_permutation_t; | |||
720 | /** | |||
721 | * Construct from a map between input and output basis states. | |||
722 | * Every basis state changed by the permutation should | |||
723 | * be in the provided map.A invalid_argument error is thrown | |||
724 | * if this is not true. | |||
725 | * Any basis state not in a permutation cycle will be assumed to | |||
726 | * take the identity. | |||
727 | * If each basis state is not the same size will throw an | |||
728 | * invalid_argument error. | |||
729 | * | |||
730 | * @param _n_qubits number of qubits permuted | |||
731 | * @param _permutation map between basis states | |||
732 | */ | |||
733 | ToffoliBox( | |||
734 | unsigned _n_qubits, | |||
735 | std::map<std::vector<bool>, std::vector<bool>> _permutation); | |||
736 | ||||
737 | /** | |||
738 | * Construct from a cycle of basis states. | |||
739 | * Any basis state not in a permutation cycle will be assumed to | |||
740 | * take the identity. | |||
741 | * The first element in the cycle is mapped to the second, second | |||
742 | * to third and so on. The final element is mapped to the first. | |||
743 | * If each basis state is not the same size will throw an | |||
744 | * invalid_argument error. | |||
745 | * | |||
746 | * @param _n_qubits number of qubits permuted | |||
747 | * @param _cycles basis states being peruted | |||
748 | */ | |||
749 | ToffoliBox(unsigned _n_qubits, const std::set<cycle_permutation_t> &_cycles); | |||
750 | ||||
751 | /** | |||
752 | * Copy constructor | |||
753 | */ | |||
754 | ToffoliBox(const ToffoliBox &other); | |||
755 | ||||
756 | ✗ | Op_ptr symbol_substitution( | ||
757 | const SymEngine::map_basic_basic &) const override { | |||
758 | ✗ | return Op_ptr(); | ||
759 | } | |||
760 | ||||
761 | /** Get the number of qubits */ | |||
762 | ✗ | unsigned get_n_qubits() const { return n_qubits_; } | ||
763 | ||||
764 | /** Get cycles of basis states for ToffoliBox */ | |||
765 | ✗ | std::set<std::vector<std::vector<bool>>> get_cycles() const { | ||
766 | ✗ | return cycles_; | ||
767 | } | |||
768 | ||||
769 | ✗ | SymSet free_symbols() const override { return {}; } | ||
770 | ||||
771 | op_signature_t get_signature() const override; | |||
772 | ||||
773 | static Op_ptr from_json(const nlohmann::json &j); | |||
774 | ||||
775 | static nlohmann::json to_json(const Op_ptr &op); | |||
776 | ||||
777 | protected: | |||
778 | void generate_circuit() const override; | |||
779 | ||||
780 | private: | |||
781 | struct transposition_t { | |||
782 | std::vector<bool> first; | |||
783 | std::vector<bool> middle; | |||
784 | std::vector<bool> last; | |||
785 | }; | |||
786 | ||||
787 | typedef std::vector<transposition_t> cycle_transposition_t; | |||
788 | ||||
789 | typedef std::vector<std::pair<std::vector<bool>, unsigned>> gray_code_t; | |||
790 | ||||
791 | std::vector<transposition_t> cycle_to_transposition( | |||
792 | cycle_permutation_t cycle) const; | |||
793 | ||||
794 | std::vector<cycle_transposition_t> get_transpositions() const; | |||
795 | ||||
796 | Circuit get_bitstring_circuit( | |||
797 | const std::vector<bool> &bitstring, const unsigned &target) const; | |||
798 | ||||
799 | gray_code_t transposition_to_gray_code( | |||
800 | const ToffoliBox::transposition_t &transposition) const; | |||
801 | ||||
802 | cycle_transposition_t merge_cycles( | |||
803 | std::vector<ToffoliBox::cycle_transposition_t> &cycle_transpositions) | |||
804 | const; | |||
805 | ||||
806 | unsigned n_qubits_; | |||
807 | std::set<cycle_permutation_t> cycles_; | |||
808 | }; | |||
809 | ||||
810 | } // namespace tket | |||
811 |