tket
Loading...
Searching...
No Matches
PauliOptimisation.cpp
Go to the documentation of this file.
1// Copyright Quantinuum
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
16
26
27namespace tket {
28
29namespace Transforms {
30
32 return Transform([=](Circuit &circ) {
33 Expr t = circ.get_phase();
34 BGL_FORALL_VERTICES(v, circ.dag, DAG) {
35 Op_ptr op = circ.get_Op_ptr_from_Vertex(v);
36 OpType optype = op->get_type();
37 if (is_boundary_type(optype) && !is_boundary_q_type(optype)) continue;
38 if (optype == OpType::Conditional)
40 "Cannot currently do `pauli_gadgets` optimisation on a "
41 "circuit with conditional gates");
42 if (op->get_desc().is_box())
44 "Cannot currently do `pauli_gadgets` optimisation on a "
45 "circuit with boxes");
46 if (optype == OpType::Measure || optype == OpType::Collapse) {
48 if (q_suc.size() != 1 ||
51 "Cannot currently do `pauli_gadgets` optimisation "
52 "on a circuit with a measure in the middle of the "
53 "circuit");
54 }
55 }
58 setup.apply(circ);
59 // We effectively commute non-Clifford rotations to the front of the circuit
60 // This gives a sequence of just Pauli gadgets (gadget_circ), followed by
61 // all of the Clifford operations (clifford_circ)
62 std::vector<SpSymPauliTensor> pauli_gadgets;
63 // rx_pauli[i] specifies which Pauli gadget would be built by applying an Rx
64 // rotation on qubit i and then pushing it through the Cliffords to the
65 // front of the circuit. Likewise for rz_pauli with Rz rotations. Clifford
66 // operations will update these and non-Clifford rotations will introduce
67 // Pauli gadgets accordingly
68 Circuit gadget_circ;
69 Circuit clifford_circ;
70 std::map<Qubit, SpPauliStabiliser> rx_pauli;
71 std::map<Qubit, SpPauliStabiliser> rz_pauli;
72 for (const Qubit &qb : circ.all_qubits()) {
73 gadget_circ.add_qubit(qb);
74 clifford_circ.add_qubit(qb);
75 rx_pauli.insert({qb, SpPauliStabiliser(qb, Pauli::X)});
76 rz_pauli.insert({qb, SpPauliStabiliser(qb, Pauli::Z)});
77 }
78 for (const Bit &cb : circ.all_bits()) {
79 gadget_circ.add_bit(cb);
80 clifford_circ.add_bit(cb);
81 }
82 // Identify Pauli Gadgets and build Clifford circuit
83 for (const Command &c : circ) {
84 const Op_ptr op_ptr = c.get_op_ptr();
85 unit_vector_t args = c.get_args();
86 OpType type = op_ptr->get_type();
87 switch (type) {
88 // Update rx_pauli and rz_pauli
89 case OpType::S: {
90 Qubit q(args[0]);
91 rx_pauli[q] = SpPauliStabiliser({}, 1) * rz_pauli[q] * rx_pauli[q];
92 break;
93 }
94 case OpType::V: {
95 Qubit q(args[0]);
96 rz_pauli[q] = SpPauliStabiliser({}, 1) * rx_pauli[q] * rz_pauli[q];
97 break;
98 }
99 case OpType::Z: {
100 Qubit q(args[0]);
101 rx_pauli[q] = SpPauliStabiliser({}, 2) * rx_pauli[q];
102 break;
103 }
104 case OpType::X: {
105 Qubit q(args[0]);
106 rz_pauli[q] = SpPauliStabiliser({}, 2) * rz_pauli[q];
107 break;
108 }
109 case OpType::Sdg: {
110 Qubit q(args[0]);
111 rx_pauli[q] = SpPauliStabiliser({}, 3) * rz_pauli[q] * rx_pauli[q];
112 break;
113 }
114 case OpType::Vdg: {
115 Qubit q(args[0]);
116 rz_pauli[q] = SpPauliStabiliser({}, 3) * rx_pauli[q] * rz_pauli[q];
117 break;
118 }
119 case OpType::CX: {
120 Qubit q_ctrl(args[0]);
121 Qubit q_trgt(args[1]);
122 rx_pauli[q_ctrl] = rx_pauli[q_ctrl] * rx_pauli[q_trgt];
123 rz_pauli[q_trgt] = rz_pauli[q_ctrl] * rz_pauli[q_trgt];
124 break;
125 }
126 // Introduce a Pauli gadget
127 case OpType::Rz: {
128 Qubit q(args[0]);
129 Expr angle = (op_ptr)->get_params()[0];
131 (SpSymPauliTensor)rz_pauli[q] * SpSymPauliTensor({}, angle);
132 pauli_gadgets.push_back(g);
133 break;
134 }
135 case OpType::Rx: {
136 Qubit q(args[0]);
137 Expr angle = (op_ptr)->get_params()[0];
139 (SpSymPauliTensor)rx_pauli[q] * SpSymPauliTensor({}, angle);
140 pauli_gadgets.push_back(g);
141 break;
142 }
143 case OpType::noop:
144 case OpType::Phase:
145 case OpType::Measure:
146 case OpType::Collapse:
147 case OpType::Reset:
148 break;
149 default: {
150 std::string error_gate =
151 "Cannot perform pairwise Pauli gadget optimisation using: " +
152 op_ptr->get_name();
153 throw BadOpType(error_gate, type);
154 }
155 }
156 // Add Clifford gates to the back of the circuit to recreate the final
157 // combination at the outputs
158 switch (type) {
159 case OpType::Rz:
160 case OpType::Rx: {
161 break;
162 }
163 default: {
164 clifford_circ.add_op(op_ptr, args);
165 }
166 }
167 }
168 // Synthesise pairs of Pauli Gadgets
169 unsigned g = 0;
170 while (g + 1 < pauli_gadgets.size()) {
171 gadget_circ.append(
172 pauli_gadget_pair(pauli_gadgets[g], pauli_gadgets[g + 1], cx_config));
173 g += 2;
174 }
175 // As we synthesised Pauli gadgets 2 at a time, if there were an odd
176 // number, we will have one left over, so add that one on its own
177 if (g < pauli_gadgets.size()) {
178 gadget_circ.append(pauli_gadget(pauli_gadgets[g], cx_config));
179 }
180 // Stitch gadget circuit and Clifford circuit together
181 circ = gadget_circ >> clifford_circ;
182 circ.add_phase(t);
184 clifford_simp().apply(circ);
185 return true;
186 });
187}
188
190 PauliSynthStrat strat, CXConfigType cx_config) {
191 return Transform([=](Circuit &circ) {
192 Expr t = circ.get_phase();
193 std::optional<std::string> name = circ.get_name();
196 switch (strat) {
199 break;
200 }
203 break;
204 }
206 circ = pauli_graph_to_pauli_exp_box_circuit_sets(pg, cx_config);
207 break;
208 }
210 throw Unsupported(
211 "PauliSynthStrat::Greedy is currently not supported. Try using "
212 "GreedyPauliSimp or a different PauliSynthStrat.");
213 }
214 default:
215 TKET_ASSERT(!"Unknown Pauli Synthesis Strategy");
216 }
217 circ.add_phase(t);
218 if (name) {
219 circ.set_name(*name);
220 }
221 // always turn circuit into PauliGraph and back, so always return true
222 return true;
223 });
224}
225
227 return Transform([=](Circuit &circ) {
228 Transform synther = synthesise_pauli_graph(strat, cx_config);
229 // make list so we don't run into unboxing vertex issues
230 std::list<Vertex> circbox_verts;
231 BGL_FORALL_VERTICES(v, circ.dag, DAG) {
233 circbox_verts.push_back(v);
234 }
235 for (Vertex v : circbox_verts) {
236 const Op_ptr op = circ.get_Op_ptr_from_Vertex(v);
237 std::shared_ptr<const CircBox> box_ptr =
238 std::dynamic_pointer_cast<const CircBox>(op);
239 Circuit inner_circ = *(box_ptr->to_circuit());
240 synther.apply(inner_circ);
241 decomp_boxes().apply(inner_circ);
242 Subcircuit sub = circ.singleton_subcircuit(v);
243 circ.substitute(inner_circ, sub);
244 }
245 return !circbox_verts
246 .empty(); // always true if we have left Circuit formalism
247 });
248}
249
250} // namespace Transforms
251
252} // namespace tket
Operation type not valid in the current context.
Location holding a bit.
Definition UnitID.hpp:192
A circuit.
Definition Circuit.hpp:212
void set_name(const std::string _name)
Set the name of the circuit.
Definition Circuit.hpp:1597
const Op_ptr get_Op_ptr_from_Vertex(const Vertex &vert) const
qubit_vector_t all_qubits() const
Subcircuit singleton_subcircuit(const Vertex &v) const
Construct a subcircuit consisting of a single vertex.
VertexVec get_successors_of_type(const Vertex &vert, EdgeType type) const
void add_bit(const Bit &id, bool reject_dups=true)
void append(const Circuit &c2)
bit_vector_t all_bits() const
void substitute(const Circuit &to_insert, const Subcircuit &to_replace, VertexDeletion vertex_deletion=VertexDeletion::Yes, OpGroupTransfer opgroup_transfer=OpGroupTransfer::Disallow)
Replace a subcircuit with a new circuit.
std::optional< std::string > get_name() const
Get the name of the circuit.
Definition Circuit.hpp:1590
Vertex add_op(const Op_ptr &op, const std::vector< ID > &args, std::optional< std::string > opgroup=std::nullopt)
Append an operation to the circuit.
Definition Circuit.hpp:1701
bool decompose_boxes_recursively(const std::unordered_set< OpType > &excluded_types={}, const std::unordered_set< std::string > &excluded_opgroups={}, const std::optional< std::unordered_set< OpType > > &included_types=std::nullopt, const std::optional< std::unordered_set< std::string > > &included_opgroups=std::nullopt)
Recursively replace each Box operation by applying Box::to_circuit.
void add_phase(Expr a)
Adds a global phase to the circuit.
Definition Circuit.cpp:148
Expr get_phase() const
Get the global phase offset as a multiple of pi (in the range [0,2)).
Definition Circuit.cpp:140
void add_qubit(const Qubit &id, bool reject_dups=true)
void replace_all_implicit_wire_swaps()
replaces all implicit wire swaps with SWAP gates
OpType get_OpType_from_Vertex(const Vertex &vert) const
Dependency graph of a circuit wrt Pauli Gadgets.
PauliTensor<PauliContainer, CoeffType>
Location holding a qubit.
Definition UnitID.hpp:154
A transformation of a circuit that preserves its semantics.
Definition Transform.hpp:27
bool apply(Circuit &circ) const
Apply the transform to a circuit.
Definition Transform.hpp:69
Transform decompose_ZX()
Transform decompose_multi_qubits_CX()
Decomposes all multi-qubit unitary gates into CX and single-qubit gates.
Transform clifford_simp(bool allow_swaps, OpType target_2qb_gate)
Simplify a circuit using Clifford rules.
Transform decomp_boxes(const std::unordered_set< OpType > &excluded_types, const std::unordered_set< std::string > &excluded_opgroups, const std::optional< std::unordered_set< OpType > > &included_types, const std::optional< std::unordered_set< std::string > > &included_opgroups)
Recursively replaces all boxes by their decomposition using Box::to_circuit Expects: any gateset.
Transform special_UCC_synthesis(PauliSynthStrat strat, CXConfigType cx_config)
Transform synthesise_pauli_graph(PauliSynthStrat strat, CXConfigType cx_config)
Transform pairwise_pauli_gadgets(CXConfigType cx_config)
Transform decompose_ZX_to_cliffords()
Defines tket::DeviceCharacterisation, used in NoiseAwarePlacement and in commute_SQ_gates_through_SWA...
Definition Path.cpp:22
Circuit pauli_gadget(SpSymPauliTensor paulis, CXConfigType cx_config)
Construct a 'Pauli gadget' corresponding to a tensor of Pauli operators.
boost::graph_traits< DAG >::vertex_descriptor Vertex
Definition DAGDefs.hpp:70
OpType
Named operation types.
Definition OpType.hpp:29
@ Measure
Measure a qubit, producing a classical output.
@ Collapse
Measure a qubit producing no output.
@ CircBox
See CircBox.
@ Reset
Reset a qubit to the zero state.
@ noop
Identity.
@ CX
Controlled OpType::X.
@ Conditional
See Conditional.
Circuit pauli_graph_to_pauli_exp_box_circuit_sets(const PauliGraph &pg, CXConfigType cx_config)
Synthesises a circuit equivalent to the PauliGraph by building sets of mutually commuting pauli gadge...
CXConfigType
Whenever a decomposition choice of Pauli gadgets is presented, users may use either Snake (a....
PauliTensor< QubitPauliMap, quarter_turns_t > SpPauliStabiliser
@ Quantum
A wire carrying quantum information, corresponding to some allocated Qubit.
PauliGraph circuit_to_pauli_graph(const Circuit &circ)
Circuit pauli_gadget_pair(SpSymPauliTensor paulis0, SpSymPauliTensor paulis1, CXConfigType cx_config)
Construct a circuit realising a pair of Pauli gadgets with the fewest two-qubit gates.
SymEngine::Expression Expr
Representation of a phase as a multiple of .
std::shared_ptr< const Op > Op_ptr
Definition OpPtr.hpp:24
bool is_boundary_type(OpType optype)
Test for input, creation, output or discard "ops".
PauliTensor< QubitPauliMap, Expr > SpSymPauliTensor
std::vector< UnitID > unit_vector_t
Definition UnitID.hpp:311
Circuit pauli_graph_to_pauli_exp_box_circuit_pairwise(const PauliGraph &pg, CXConfigType cx_config)
Synthesises a circuit equivalent to the PauliGraph by inserting pairs of pauli gadgets as PauliExpPai...
bool is_boundary_q_type(OpType optype)
Test for input, creation, output or discard quantum "ops".
bool is_final_q_type(OpType optype)
Test for output or discard quantum "ops".
std::vector< Vertex > VertexVec
Definition DAGDefs.hpp:73
boost::adjacency_list< boost::listS, boost::listS, boost::bidirectionalS, boost::property< boost::vertex_index_t, std::size_t, VertexProperties >, EdgeProperties > DAG
Graph representing a circuit, with operations as nodes.
Definition DAGDefs.hpp:68
Circuit pauli_graph_to_pauli_exp_box_circuit_individually(const PauliGraph &pg, CXConfigType cx_config)
Synthesises a circuit equivalent to the PauliGraph by adding each pauli gadget to the circuit as a Pa...
Structure to describe a convex region of the interaction graph.
Definition Circuit.hpp:128