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 | /** | |||
18 | * @file | |||
19 | * @brief Operations | |||
20 | */ | |||
21 | ||||
22 | #include <memory> | |||
23 | #include <optional> | |||
24 | #include <ostream> | |||
25 | #include <stdexcept> | |||
26 | #include <string> | |||
27 | #include <utility> | |||
28 | #include <vector> | |||
29 | ||||
30 | #include "OpPtr.hpp" | |||
31 | #include "OpType/OpDesc.hpp" | |||
32 | #include "OpType/OpTypeFunctions.hpp" | |||
33 | #include "OpType/OpTypeInfo.hpp" | |||
34 | #include "Utils/Constants.hpp" | |||
35 | #include "Utils/Expression.hpp" | |||
36 | #include "Utils/Json.hpp" | |||
37 | #include "Utils/PauliStrings.hpp" | |||
38 | #include "Utils/UnitID.hpp" | |||
39 | ||||
40 | namespace tket { | |||
41 | ||||
42 | /** Wrong number of parameters for an operation */ | |||
43 | class InvalidParameterCount : public std::logic_error { | |||
44 | public: | |||
45 | 1 | InvalidParameterCount() | ||
46 | 1 | : std::logic_error("Gate has an invalid number of parameters") {} | ||
47 | }; | |||
48 | ||||
49 | /** | |||
50 | * Abstract class representing an operation type | |||
51 | */ | |||
52 | class Op : public std::enable_shared_from_this<Op> { | |||
53 | public: | |||
54 | /** | |||
55 | * Inverse (of a unitary operation) | |||
56 | * | |||
57 | * @throw BadOpType if operation is not unitary | |||
58 | */ | |||
59 | ✗ | virtual Op_ptr dagger() const { throw BadOpType(get_type()); } | ||
60 | ||||
61 | /** | |||
62 | * Transpose of a unitary operation | |||
63 | */ | |||
64 | ✗ | virtual Op_ptr transpose() const { throw BadOpType(get_type()); }; | ||
65 | ||||
66 | /** | |||
67 | * Operation with values for symbols substituted | |||
68 | * | |||
69 | * @param sub_map map from symbols to values | |||
70 | * | |||
71 | * @return New operation with symbols substituted, or a null pointer if | |||
72 | * the operation type does not support symbols. | |||
73 | */ | |||
74 | virtual Op_ptr symbol_substitution( | |||
75 | const SymEngine::map_basic_basic &sub_map) const = 0; | |||
76 | ||||
77 | /** Sequence of phase parameters, if applicable */ | |||
78 | ✗ | virtual std::vector<Expr> get_params() const { throw BadOpType(get_type()); } | ||
79 | ||||
80 | /** Sequence of phase parameters reduced to canonical range, if applicable */ | |||
81 | ✗ | virtual std::vector<Expr> get_params_reduced() const { | ||
82 | ✗ | throw BadOpType(get_type()); | ||
83 | } | |||
84 | ||||
85 | /* Number of qubits */ | |||
86 | ✗ | virtual unsigned n_qubits() const { throw BadOpType(get_type()); } | ||
87 | ||||
88 | /** String representation */ | |||
89 | virtual std::string get_name(bool latex = false) const; | |||
90 | ||||
91 | /** Command representation */ | |||
92 | virtual std::string get_command_str(const unit_vector_t &args) const; | |||
93 | ||||
94 | /** Get operation descriptor */ | |||
95 | ✗ | OpDesc get_desc() const { return desc_; } | ||
96 | ||||
97 | /** Get operation type */ | |||
98 | ✗ | OpType get_type() const { return type_; } | ||
99 | ||||
100 | /** Set of all free symbols occurring in operation parameters. */ | |||
101 | virtual SymSet free_symbols() const = 0; | |||
102 | ||||
103 | /** | |||
104 | * Which Pauli, if any, commutes with the operation at a given qubit | |||
105 | * | |||
106 | * @param i qubit number at which Pauli should commute | |||
107 | * @return A Pauli that commutes with the given operation | |||
108 | * @retval std::nullopt no Pauli commutes (or operation not a gate) | |||
109 | * @retval Pauli::I any Pauli commutes | |||
110 | */ | |||
111 | ✗ | virtual std::optional<Pauli> commuting_basis(unsigned i) const { | ||
112 | (void)i; | |||
113 | ✗ | return std::nullopt; | ||
114 | } | |||
115 | ||||
116 | /** | |||
117 | * Whether the operation commutes with the given Pauli at the given qubit | |||
118 | * | |||
119 | * @param colour Pauli operation type | |||
120 | * @param i operation qubit index | |||
121 | */ | |||
122 | ✗ | virtual bool commutes_with_basis( | ||
123 | const std::optional<Pauli> &colour, unsigned i) const { | |||
124 | (void)colour; | |||
125 | (void)i; | |||
126 | ✗ | return false; | ||
127 | } | |||
128 | ||||
129 | /** | |||
130 | * return if the op is external | |||
131 | */ | |||
132 | ✗ | virtual bool is_extern() const { return false; } | ||
133 | ||||
134 | /** Vector specifying type of data for each port on op */ | |||
135 | virtual op_signature_t get_signature() const = 0; | |||
136 | ||||
137 | /** | |||
138 | * Test whether operation is identity up to a phase and return phase if so. | |||
139 | * | |||
140 | * @return phase, as multiple of pi, if operation is identity up to phase | |||
141 | * @throw BadOpType if operation is not a \ref Gate | |||
142 | */ | |||
143 | ✗ | virtual std::optional<double> is_identity() const { | ||
144 | ✗ | throw BadOpType(get_type()); | ||
145 | } | |||
146 | ||||
147 | /** | |||
148 | * Test whether operation is in the Clifford group. | |||
149 | * | |||
150 | * A return value of true guarantees that the operation is Clifford. (Note | |||
151 | * that the converse is not the case: some Clifford operations may not be | |||
152 | * detected as such.) | |||
153 | * | |||
154 | * @retval true operation is in the Clifford group | |||
155 | */ | |||
156 | ✗ | virtual bool is_clifford() const { return false; } | ||
157 | ||||
158 | /** | |||
159 | * If meaningful and implemented, return the numerical unitary matrix | |||
160 | * (in ILO-BE convention) which this Op represents. | |||
161 | * | |||
162 | * @pre No symbolic parameters. | |||
163 | * @return unitary matrix (ILO-BE) which this Op represents | |||
164 | * @throw BadOpType upon error. | |||
165 | */ | |||
166 | ✗ | virtual Eigen::MatrixXcd get_unitary() const { throw BadOpType(get_type()); } | ||
167 | ||||
168 | ✗ | virtual nlohmann::json serialize() const { | ||
169 |
0/1? Decision couldn't be analyzed.
|
✗ | throw JsonError("JSON serialization not yet implemented for " + get_name()); | |
170 | } | |||
171 | ||||
172 | ✗ | virtual ~Op() {} | ||
173 | ||||
174 | ✗ | bool operator==(const Op &other) const { | ||
175 | ✗ | return type_ == other.type_ && is_equal(other); | ||
176 | } | |||
177 | ||||
178 | /** | |||
179 | * Checks equality between two instances of the same class. | |||
180 | * The Op object passed as parameter must always be of the same type as this. | |||
181 | * | |||
182 | * For base class Op, it is sufficient that they have same type | |||
183 | */ | |||
184 | 1 | virtual bool is_equal(const Op &) const { return true; } | ||
185 | ||||
186 | protected: | |||
187 |
1/2✓ Branch 2 taken 2007993 times.
✗ Branch 3 not taken.
|
2007993 | explicit Op(const OpType &type) : desc_(type), type_(type) {} | |
188 | const OpDesc desc_; /**< Operation descriptor */ | |||
189 | const OpType type_; /**< Operation type */ | |||
190 | }; | |||
191 | ||||
192 | // friend to stream op (print) | |||
193 | std::ostream &operator<<(std::ostream &os, Op const &operation); | |||
194 | ||||
195 | } // namespace tket | |||
196 |