25struct VertexDetachmentInfo {
30static void detach_vertex(
31 Circuit &circuit,
const Vertex &vertex,
32 VertexDetachmentInfo &detachmentInfo) {
33 detachmentInfo.detachedVertices.emplace_back(vertex);
34 auto &vertexPredecessors = detachmentInfo.detachedVertexPredecessors;
35 const auto &newVertexPredecessors = circuit.get_predecessors(vertex);
36 vertexPredecessors.insert(
37 vertexPredecessors.cend(), newVertexPredecessors.cbegin(),
38 newVertexPredecessors.cend());
39 circuit.remove_vertex(
43static void detach_vertex_and_successor(
44 Circuit &circuit,
const Vertex &vertex,
const Vertex &successor,
45 VertexDetachmentInfo &detachmentInfo) {
46 detachmentInfo.detachedVertices.emplace_back(vertex);
47 detachmentInfo.detachedVertices.emplace_back(successor);
48 auto &vertexPredecessors = detachmentInfo.detachedVertexPredecessors;
49 const auto &newVertexPredecessors = circuit.get_predecessors(vertex);
50 vertexPredecessors.insert(
51 vertexPredecessors.cend(), newVertexPredecessors.cbegin(),
52 newVertexPredecessors.cend());
53 circuit.remove_vertices(
58static bool try_detach_identity(
59 Circuit &circuit,
const Vertex &vertex,
60 VertexDetachmentInfo &detachmentInfo) {
61 auto vertex_operator = circuit.get_Op_ptr_from_Vertex(vertex);
62 if (
auto phase = vertex_operator->is_identity()) {
63 circuit.add_phase(phase.value());
64 detach_vertex(circuit, vertex, detachmentInfo);
70static bool vertex_is_a_measurement(
71 const Circuit &circuit,
Vertex const &vertex) {
76vertex_is_succeeded_only_by_z_basis_measurements_with_which_it_commutes(
77 const Circuit &circuit,
const Vertex &vertex) {
81 auto successors = circuit.get_successors(vertex);
82 std::vector<port_t> ports(successors.size());
83 std::iota(ports.begin(), ports.end(), 0);
85 return std::all_of(ports.cbegin(), ports.cend(), [&](
port_t port) {
86 return vertex_is_a_measurement(circuit, successors[port]) &&
87 circuit.commutes_with_basis(vertex, Pauli::Z, port);
91static bool try_detach_zbasis_commuting_vertex(
92 Circuit &circuit,
const Vertex &vertex,
93 VertexDetachmentInfo &detachmentInfo) {
94 if (vertex_is_succeeded_only_by_z_basis_measurements_with_which_it_commutes(
96 detach_vertex(circuit, vertex, detachmentInfo);
102static bool port_ordering_is_compatible(
103 Circuit &circuit,
const Vertex &vertex,
const Vertex &successor) {
104 const Op_ptr vertex_op = circuit.get_Op_ptr_from_Vertex(vertex);
111 for (
const Edge &in : circuit.get_in_edges(successor)) {
112 auto source_port = circuit.get_source_port(in);
113 auto target_port = circuit.get_target_port(in);
114 if (not vertex_op->has_symmetry(source_port, target_port)) {
121static bool preliminary_vertex_successor_checks_pass(
122 Circuit &circuit,
const Vertex &vertex) {
128 auto successors = circuit.get_successors(vertex);
129 if (successors.size() != 1)
return false;
130 auto successor = successors[0];
131 if (circuit.get_predecessors(successor).size() != 1)
return false;
134 if (circuit.get_Op_ptr_from_Vertex(successor)->get_desc().is_oneway()) {
138 return port_ordering_is_compatible(circuit, vertex, successor);
141static bool try_detach_both_because_successor_is_adjoint(
142 Circuit &circuit,
Vertex const &vertex,
Vertex const &successor,
143 VertexDetachmentInfo &detachmentInfo) {
144 const Op_ptr successor_op = circuit.get_Op_ptr_from_Vertex(successor);
145 const Op_ptr vertex_op = circuit.get_Op_ptr_from_Vertex(vertex);
146 if (*vertex_op == *successor_op->dagger()) {
147 detach_vertex_and_successor(circuit, vertex, successor, detachmentInfo);
153static bool try_join_rotations_and_detach_successor(
154 Circuit &circuit,
Vertex const &vertex,
Vertex const &successor,
155 VertexDetachmentInfo &detachmentInfo) {
156 const Op_ptr successor_op = circuit.get_Op_ptr_from_Vertex(successor);
157 const OpDesc successor_op_descriptor = successor_op->get_desc();
158 const Op_ptr vertex_op = circuit.get_Op_ptr_from_Vertex(vertex);
159 const OpDesc vertex_op_descriptor = vertex_op->get_desc();
162 if (not(vertex_op_descriptor.is_rotation() &&
163 vertex_op_descriptor.type() == successor_op_descriptor.type())) {
168 auto expr1 = vertex_op->get_params()[0];
169 auto expr2 = successor_op->get_params()[0];
171 vertex_op_descriptor.type(), {expr1 + expr2},
172 circuit.get_in_edges(successor).size());
173 circuit.dag[
vertex].op = op_new;
177 detach_vertex(circuit, successor, detachmentInfo);
181static bool try_detach_single_vertex(
182 Circuit &circuit,
const Vertex &vertex,
183 VertexDetachmentInfo &detachmentInfo) {
184 if (try_detach_identity(circuit, vertex, detachmentInfo)) {
187 if (try_detach_zbasis_commuting_vertex(circuit, vertex, detachmentInfo)) {
193static bool try_detach_vertex_and_successor(
194 Circuit &circuit,
const Vertex &vertex,
195 VertexDetachmentInfo &detachmentInfo) {
196 if (not preliminary_vertex_successor_checks_pass(circuit, vertex))
198 auto successor = circuit.get_successors(vertex)[0];
199 if (try_detach_both_because_successor_is_adjoint(
200 circuit, vertex, successor, detachmentInfo)) {
203 if (try_join_rotations_and_detach_successor(
204 circuit, vertex, successor, detachmentInfo)) {
210static bool is_apriori_not_detachable(
211 const Circuit &circuit,
Vertex const &vertex) {
212 const OpDesc op_descriptor =
213 circuit.get_Op_ptr_from_Vertex(vertex)->get_desc();
215 if (!op_descriptor.is_gate())
return true;
217 if (circuit.n_out_edges(vertex) == 0 || circuit.n_in_edges(vertex) == 0) {
223static bool try_detach_vertex(
224 Circuit &circuit,
const Vertex &vertex,
225 VertexDetachmentInfo &detachmentInfo) {
226 if (is_apriori_not_detachable(circuit, vertex)) {
229 if (try_detach_single_vertex(circuit, vertex, detachmentInfo)) {
232 if (try_detach_vertex_and_successor(circuit, vertex, detachmentInfo)) {
238static VertexDetachmentInfo detach_vertices_if_redundant(
239 Circuit &circuit,
const VertexVec &vertices) {
240 VertexDetachmentInfo detachmentInfo;
241 for (
const auto &vertex : vertices) {
242 try_detach_vertex(circuit, vertex, detachmentInfo);
244 return detachmentInfo;
247static VertexSet detach_any_redundant_vertices(Circuit &circuit) {
249 VertexVec verticesToCheckForRemoval = circuit.vertices_in_order();
250 while (!verticesToCheckForRemoval.empty()) {
251 auto detachmentInfo =
252 detach_vertices_if_redundant(circuit, verticesToCheckForRemoval);
254 detachmentInfo.detachedVertices.cbegin(),
255 detachmentInfo.detachedVertices.cend());
257 verticesToCheckForRemoval, detachmentInfo.detachedVertexPredecessors);
267 VertexSet bin = detach_any_redundant_vertices(circuit);
void remove_vertices(const VertexSet &surplus, GraphRewiring graph_rewiring, VertexDeletion vertex_deletion)
detail::vertex< T > vertex
boost::graph_traits< DAG >::vertex_descriptor Vertex
@ Measure
Measure a qubit, producing a classical output.
std::list< Vertex > VertexList
Op_ptr get_op_ptr(OpType chosen_type, const Expr ¶m, unsigned n_qubits)
Get an operation with a given type, single parameter and qubit count.
std::unordered_set< Vertex > VertexSet
@ Classical
A wire carrying classical information, corresponding to some allocated Bit.
@ Boolean
A wire carrying a bit of classical information from a classical output port of one op to a classical ...
boost::graph_traits< DAG >::edge_descriptor Edge
std::shared_ptr< const Op > Op_ptr
unsigned port_t
A specific entry or exit port of a vertex.
std::vector< Vertex > VertexVec