Skip to content

Commit

Permalink
Pass to remove diagonal gates before measurement (#2208)
Browse files Browse the repository at this point in the history
* rz_and_z_optimization

* bug fixing and more testing

* changelog

* lint

* RemoveRZandZbeforeMeasure -> RemoveDiagonalGatesBeforeMeasure

* changelog

* invalid-name

* test

* diagonal_control_gates

* CrzGate, Cu1Gate, RZZGate

* lint

* from qiskit.compiler import transpile

* remove_diagonal_gates_before_measurere

* diagonal_control_gates -> diagonal_2q_gates

* quantum_predecessors

* use quantum_predecessors

* test_optimize_1rzz_2measure docstring

* lint
  • Loading branch information
Luciano authored Apr 27, 2019
1 parent e673d1c commit a85c741
Show file tree
Hide file tree
Showing 6 changed files with 476 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Added
wires instead of named bits.
- Added a ``OptimizeSwapBeforeMeasure`` pass that removes the swap gates when they
are followed by a measurement instruction, moving the latter to the proper wire. (#1890)
- Added a ``RemoveDiagonalGatesBeforeMeasure`` pass that removes the diagonal gates when they
are followed by a measurement instruction. (#2208)
- Added a ``CommutativeCancellation`` pass that cancels self-inverse gates and combines
rotations about the Z axis, leveraging previously-found gate commutation relations. (#2012)
- Added a ``Collect2qBlocks`` pass that analyzes the circuit for uninterrupted sequences
Expand Down
11 changes: 11 additions & 0 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,17 @@ def predecessors(self, node):

return self._multi_graph.predecessors(node)

def quantum_predecessors(self, node):
"""Returns list of the predecessors of a node that are
connected by a quantum edge as DAGNodes."""

predecessors = []
for predecessor in self.predecessors(node):
if isinstance(self._multi_graph.get_edge_data(predecessor, node, key=0)['wire'][0],
QuantumRegister):
predecessors.append(predecessor)
return predecessors

def ancestors(self, node):
"""Returns set of the ancestors of a node as DAGNodes."""
if isinstance(node, int):
Expand Down
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@
from .mapping.noise_adaptive_layout import NoiseAdaptiveLayout
from .mapping.basic_swap import BasicSwap
from .mapping.lookahead_swap import LookaheadSwap
from .remove_diagonal_gates_before_measure import RemoveDiagonalGatesBeforeMeasure
from .mapping.stochastic_swap import StochasticSwap
from .mapping.legacy_swap import LegacySwap
44 changes: 44 additions & 0 deletions qiskit/transpiler/passes/remove_diagonal_gates_before_measure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.


"""
Transpiler pass to remove diagonal gates (like RZ, T, Z, etc) before
a measurement. Including diagonal 2Q gates.
"""

from qiskit.circuit import Measure
from qiskit.extensions.standard import RZGate, ZGate, TGate, SGate, TdgGate, SdgGate, U1Gate,\
CzGate, CrzGate, Cu1Gate, RZZGate
from qiskit.transpiler.basepasses import TransformationPass


class RemoveDiagonalGatesBeforeMeasure(TransformationPass):
"""Remove diagonal gates (like RZ, T, Z, etc) before a measurement.
Including diagonal 2Q gates."""

def run(self, dag):
"""Return a new circuit that has been optimized."""
diagonal_1q_gates = (RZGate, ZGate, TGate, SGate, TdgGate, SdgGate, U1Gate)
diagonal_2q_gates = (CzGate, CrzGate, Cu1Gate, RZZGate)

nodes_to_remove = set()
for measure in dag.op_nodes(Measure):
predecessor = dag.quantum_predecessors(measure)[0]

if predecessor.type == 'op' and isinstance(predecessor.op, diagonal_1q_gates):
nodes_to_remove.add(predecessor)

if predecessor.type == 'op' and isinstance(predecessor.op, diagonal_2q_gates):
successors = dag.quantum_successors(predecessor)
if all([s.type == 'op' and isinstance(s.op, Measure) for s in successors]):
nodes_to_remove.add(predecessor)

for node_to_remove in nodes_to_remove:
dag.remove_op_node(node_to_remove)

return dag
18 changes: 18 additions & 0 deletions test/python/test_dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,24 @@ def test_quantum_successors(self):
self.assertEqual(successor_cnot[0].type, 'out')
self.assertIsInstance(successor_cnot[1].op, Reset)

def test_quantum_predecessors(self):
"""The method dag.quantum_predecessors() returns predecessors connected by quantum edges"""
self.dag.apply_operation_back(Reset(), [self.qubit0], [])
self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], [])
self.dag.apply_operation_back(Measure(), [self.qubit1, self.clbit1], [])

predecessor_measure = self.dag.quantum_predecessors(
self.dag.named_nodes('measure').pop())
self.assertEqual(len(predecessor_measure), 1)
cnot_node = predecessor_measure[0]

self.assertIsInstance(cnot_node.op, CnotGate)

predecessor_cnot = self.dag.quantum_predecessors(cnot_node)
self.assertEqual(len(predecessor_cnot), 2)
self.assertEqual(predecessor_cnot[1].type, 'in')
self.assertIsInstance(predecessor_cnot[0].op, Reset)

def test_get_gates_nodes(self):
"""The method dag.gate_nodes() returns all gate nodes"""
self.dag.apply_operation_back(HGate(), [self.qubit0], [])
Expand Down
Loading

0 comments on commit a85c741

Please sign in to comment.