| 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 |