tket
Loading...
Searching...
No Matches
PhaseOptimisation.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
18
19namespace tket {
20
21namespace Transforms {
22
23static void recursive_smash_CX_PhaseGadgets(
24 Circuit &circ, Vertex &vert, VertexList &bin, bool &success);
25
27 return Transform([](Circuit &circ) {
28 bool success = false;
29 VertexList bin;
30 BGL_FORALL_VERTICES(v, circ.dag, DAG) {
31 recursive_smash_CX_PhaseGadgets(circ, v, bin, success);
32 }
33 circ.remove_vertices(
35 return success;
36 });
37}
38
39static void recursive_smash_CX_PhaseGadgets(
40 Circuit &circ, Vertex &vert, VertexList &bin, bool &success) {
42 for (unsigned e = 0; e < circ.n_in_edges(vert); e++) {
43 Edge in_e = circ.get_nth_in_edge(vert, e);
44 Edge out_e = circ.get_nth_out_edge(vert, e);
45 Vertex prev_vert = circ.source(in_e);
46 if (circ.get_OpType_from_Vertex(prev_vert) == OpType::CX &&
47 circ.get_source_port(in_e) == 1) {
48 Vertex next_vert = circ.target(out_e);
49 if (circ.get_OpType_from_Vertex(next_vert) == OpType::CX &&
50 circ.get_target_port(out_e) == 1) {
51 Edge linker = circ.get_nth_in_edge(next_vert, 0);
52 if (linker == circ.get_nth_out_edge(prev_vert, 0)) {
53 success = true;
54 circ.remove_edge(linker);
55 port_t new_port = circ.n_in_edges(vert);
56 circ.add_edge({prev_vert, 0}, {vert, new_port}, EdgeType::Quantum);
57 circ.add_edge({vert, new_port}, {next_vert, 0}, EdgeType::Quantum);
58 VertexList to_detach = {prev_vert, next_vert};
59 bin.push_back(prev_vert);
60 bin.push_back(next_vert);
61 circ.remove_vertices(
64 e--; // continue to add any more from the current port
65 }
66 }
67 }
68 }
69 // Fix up the qubit count for the phase gadget we inserted.
70 std::vector<Expr> v_params =
71 circ.get_Op_ptr_from_Vertex(vert)->get_params();
72 circ.dag[vert].op =
73 get_op_ptr(OpType::PhaseGadget, v_params, circ.n_in_edges(vert));
74 }
75}
76
77static bool align_phases_all(Circuit &circ) {
78 bool success = false;
79 VertexList bin;
80 VertexVec vertices = circ.vertices_in_order();
81 auto index = boost::get(boost::vertex_index, circ.dag);
82 for (const Vertex &v : vertices) {
83 if (circ.get_OpType_from_Vertex(v) == OpType::PhaseGadget) {
84 std::map<Vertex, std::map<port_t, port_t>>
85 parent_to_port_map; // maps ports on initial phase to ports on each
86 // parent
87 EdgeVec i_edges = circ.get_in_edges(v);
88 unsigned n_qubits = i_edges.size();
89 for (EdgeVec::iterator e = i_edges.begin(); e != i_edges.end(); ++e) {
90 Edge ed = *e;
91 Vertex source = boost::source(ed, circ.dag);
92 OpType type = circ.get_OpType_from_Vertex(source);
93 while (!(type == OpType::PhaseGadget || is_initial_q_type(type))) {
94 ed = circ.get_last_edge(source, ed);
95 source = boost::source(ed, circ.dag);
96 type = circ.get_OpType_from_Vertex(source);
97 }
98 if (is_initial_q_type(type) || circ.get_source_port(ed) > n_qubits) {
99 continue;
100 }
101 std::map<Vertex, std::map<port_t, port_t>>::iterator par =
102 parent_to_port_map.find(source);
103 if (par == parent_to_port_map.end()) {
104 std::map<port_t, port_t> port_map;
105 port_map.insert({circ.get_target_port(*e), circ.get_source_port(ed)});
106 parent_to_port_map.insert({source, port_map});
107 } else {
108 par->second.insert(
109 {circ.get_target_port(*e), circ.get_source_port(ed)});
110 }
111 }
112 // build replacement as disconnected graph
113 Circuit phase_replacement;
114 std::map<port_t, Vertex> port_to_input;
115 std::map<port_t, Vertex> port_to_output;
116 std::map<port_t, bool> port_remaining;
117 for (port_t p = 0; p < n_qubits; p++) {
118 Vertex in = phase_replacement.add_vertex(OpType::Input);
119 Vertex out = phase_replacement.add_vertex(OpType::Output);
120 phase_replacement.boundary.insert({Qubit(p), in, out});
121 port_to_input.insert({p, in});
122 port_to_output.insert({p, out});
123 port_remaining.insert({p, true});
124 }
125 Vertex gadget = phase_replacement.add_vertex(
126 phase_replacement.get_Op_ptr_from_Vertex(v));
127 // collect incoming edges by parent and add where preference is possible
128 typedef std::function<bool(
129 std::pair<Vertex, std::map<port_t, port_t>>,
130 std::pair<Vertex, std::map<port_t, port_t>>)>
131 Comp;
132 std::set<std::pair<Vertex, std::map<port_t, port_t>>, Comp> sorted_p2p(
133 parent_to_port_map.begin(), parent_to_port_map.end(),
134 [&](std::pair<Vertex, std::map<port_t, port_t>> const &a,
135 std::pair<Vertex, std::map<port_t, port_t>> const &b) {
136 if (a.second.size() == b.second.size()) {
137 return index[a.first] < index[b.first];
138 }
139 return a.second.size() > b.second.size();
140 });
141 for (std::pair<Vertex, std::map<port_t, port_t>> par : sorted_p2p) {
142 for (std::map<port_t, port_t>::iterator port_pair = par.second.begin();
143 port_pair != par.second.end(); ++port_pair) {
144 if (port_remaining[port_pair->second]) {
145 phase_replacement.add_edge(
146 {port_to_input[port_pair->first], 0},
147 {gadget, port_pair->second}, EdgeType::Quantum);
148 phase_replacement.add_edge(
149 {gadget, port_pair->second},
150 {port_to_output[port_pair->first], 0}, EdgeType::Quantum);
151 port_remaining[port_pair->second] = false;
152 port_to_input.erase(port_pair->first);
153 }
154 }
155 }
156 // add edges for remaining ports
157 port_t spare_port = 0;
158 for (std::map<port_t, Vertex>::iterator in = port_to_input.begin();
159 in != port_to_input.end(); ++in) {
160 while (!port_remaining[spare_port]) spare_port++;
161 phase_replacement.add_edge(
162 {in->second, 0}, {gadget, spare_port}, EdgeType::Quantum);
163 phase_replacement.add_edge(
164 {gadget, spare_port}, {port_to_output[in->first], 0},
166 spare_port++;
167 }
168 // substitute into circuit
169 Subcircuit sub = circ.singleton_subcircuit(v);
170 bin.push_back(v);
171 circ.substitute(phase_replacement, sub, Circuit::VertexDeletion::No);
172 success = true;
173 }
174 }
175 circ.remove_vertices(
177 return success;
178}
179
180Transform align_PhaseGadgets() { return Transform(align_phases_all); }
181
182} // namespace Transforms
183
184} // namespace tket
A circuit.
Definition Circuit.hpp:212
Edge get_nth_in_edge(const Vertex &vert_to, const port_t &n) const
Get the edge targeting the nth input port at vert_to.
const Op_ptr get_Op_ptr_from_Vertex(const Vertex &vert) const
port_t get_target_port(const Edge &edge) const
void remove_vertices(const VertexSet &surplus, GraphRewiring graph_rewiring, VertexDeletion vertex_deletion)
Vertex source(const Edge &e) const
Definition Circuit.hpp:569
Edge get_nth_out_edge(const Vertex &vert_from, const port_t &n) const
Get the edge originated from the nth output port at vert_from.
void remove_edge(const Edge &edge)
Removes a single edge from the dag.
port_t get_source_port(const Edge &edge) const
Edge add_edge(const VertPort &source, const VertPort &target, const EdgeType &type)
OpType get_OpType_from_Vertex(const Vertex &vert) const
Vertex target(const Edge &e) const
Definition Circuit.hpp:567
unsigned n_in_edges(const Vertex &vert) const
Total number of inward edges.
A transformation of a circuit that preserves its semantics.
Definition Transform.hpp:27
Transform smash_CX_PhaseGadgets()
Transform align_PhaseGadgets()
Defines tket::DeviceCharacterisation, used in NoiseAwarePlacement and in commute_SQ_gates_through_SWA...
Definition Path.cpp:22
boost::graph_traits< DAG >::vertex_descriptor Vertex
Definition DAGDefs.hpp:70
OpType
Named operation types.
Definition OpType.hpp:29
@ Output
Quantum output node of the circuit.
@ Input
Quantum input node of the circuit.
@ CX
Controlled OpType::X.
std::list< Vertex > VertexList
Definition DAGDefs.hpp:74
Op_ptr get_op_ptr(OpType chosen_type, const Expr &param, unsigned n_qubits)
Get an operation with a given type, single parameter and qubit count.
bool is_initial_q_type(OpType optype)
Test for input or creation quantum "ops".
@ Quantum
A wire carrying quantum information, corresponding to some allocated Qubit.
boost::graph_traits< DAG >::edge_descriptor Edge
Definition DAGDefs.hpp:88
std::vector< Edge > EdgeVec
Definition DAGDefs.hpp:93
unsigned port_t
A specific entry or exit port of a vertex.
Definition Op.hpp:48
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