Repository: Qiskit/qiskit

Issue:
Flip order of CXCancellation and 1QGateOptimization in default transpiler flow
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
Flipping the order of CXCancellation and 1QGateOptimization in the default transpiler flow allows for the possibility of single-qubit gates in between cx gates to add up to identity, which in turn allows the cx gates to collected by the cx gate cancellation.  The current ordering does not allow for this, and is thus not as efficient at reducing depth.

<img width="1039" alt="Screen Shot 2019-03-28 at 6 54 47 AM" src="https://user-images.githubusercontent.com/1249193/55152287-69f85400-5126-11e9-922c-da7bb37a8ada.png">



Discussion:
Ideally one would want to do 1Q optim then cx cancellation in a loop until the depth reaches a fixed point.
Actually I take this back, it is not so clear which one to choose.
Actually it is more efficient, provided you are going to call each once, as is currently the case.
The passmanager supports that. I can have a look.
I would also argue that cx cancellation should be before cx direction swap otherwise you cannot collection cx that have their directions swapped.  It also makes the cx cancellation pass more efficient as it is not swapping directions for cx gates that could be canceled. 

So the new order should be 1Q optim, cx cancel, cx direction.
The worst case scenario in this modification (assuming everything is run once) is two leftover U3 gates, where as keeping things the same gives a worse case of 2 cx gates.  Since cx gates are 10x more costly, minimizing their count is the way to go.

we should do this in a loop until depth reaches fixed point.

Resolving patch:
diff --git a/qiskit/transpiler/transpiler.py b/qiskit/transpiler/transpiler.py
--- a/qiskit/transpiler/transpiler.py
+++ b/qiskit/transpiler/transpiler.py
@@ -16,11 +16,13 @@
 from qiskit.converters import dag_to_circuit
 from qiskit.extensions.standard import SwapGate
 from qiskit.mapper.layout import Layout
+from qiskit.transpiler.passmanager import PassManager
 from qiskit.transpiler.passes.unroller import Unroller
 
 from .passes.cx_cancellation import CXCancellation
 from .passes.decompose import Decompose
 from .passes.optimize_1q_gates import Optimize1qGates
+from .passes.dag_fixed_point import DAGFixedPoint
 from .passes.mapping.barrier_before_final_measurements import BarrierBeforeFinalMeasurements
 from .passes.mapping.check_cnot_direction import CheckCnotDirection
 from .passes.mapping.cx_direction import CXDirection
@@ -167,7 +169,7 @@ def transpile_dag(dag, basis_gates=None, coupling_map=None,
 
             eg. [[0, 2], [1, 2], [1, 3], [3, 4]}
 
-        initial_layout (Layout): A layout object
+        initial_layout (Layout or None): A layout object
         seed_mapper (int): random seed_mapper for the swap mapper
         pass_manager (PassManager): pass manager instance for the transpilation process
             If None, a default set of passes are run.
@@ -195,6 +197,9 @@ def transpile_dag(dag, basis_gates=None, coupling_map=None,
                       "removed after 0.9", DeprecationWarning, 2)
         basis_gates = basis_gates.split(',')
 
+    if initial_layout is None:
+        initial_layout = Layout.generate_trivial_layout(*dag.qregs.values())
+
     if pass_manager:
         # run the passes specified by the pass manager
         # TODO return the property set too. See #1086
@@ -238,14 +243,16 @@ def transpile_dag(dag, basis_gates=None, coupling_map=None,
             dag = Decompose(SwapGate).run(dag)
             # Change cx directions
             dag = CXDirection(coupling).run(dag)
-            # Simplify cx gates
-            dag = CXCancellation().run(dag)
             # Unroll to the basis
             dag = Unroller(['u1', 'u2', 'u3', 'id', 'cx']).run(dag)
-            # Simplify single qubit gates
-            dag = Optimize1qGates().run(dag)
-            logger.info("post-mapping properties: %s",
-                        dag.properties())
+
+            # Simplify single qubit gates and CXs
+            pm_4_optimization = PassManager()
+            pm_4_optimization.append([Optimize1qGates(), CXCancellation(), DAGFixedPoint()],
+                                     do_while=lambda property_set: not property_set[
+                                         'dag_fixed_point'])
+            dag = transpile_dag(dag, pass_manager=pm_4_optimization)
+
         dag.name = name
 
     return dag


Test patch:
diff --git a/test/python/compiler/test_compiler.py b/test/python/compiler/test_compiler.py
--- a/test/python/compiler/test_compiler.py
+++ b/test/python/compiler/test_compiler.py
@@ -676,6 +676,27 @@ def test_final_measurement_barrier_for_simulators(self, mock_pass):
 
         self.assertTrue(mock_pass.called)
 
+    def test_optimize_to_nothing(self):
+        """ Optimze gates up to fixed point in the default pipeline
+        See https://github.com/Qiskit/qiskit-terra/issues/2035 """
+        qr = QuantumRegister(2)
+        circ = QuantumCircuit(qr)
+        circ.h(qr[0])
+        circ.cx(qr[0], qr[1])
+        circ.x(qr[0])
+        circ.y(qr[0])
+        circ.z(qr[0])
+        circ.cx(qr[0], qr[1])
+        circ.h(qr[0])
+        circ.cx(qr[0], qr[1])
+        circ.cx(qr[0], qr[1])
+        dag_circuit = circuit_to_dag(circ)
+
+        after = transpile_dag(dag_circuit, coupling_map=[[0, 1], [1, 0]])
+
+        expected = QuantumCircuit(QuantumRegister(2, 'q'))
+        self.assertEqual(after, circuit_to_dag(expected))
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)