Repository: Qiskit/qiskit-terra (python)

Issue:
Flipping of gate direction in Transpiler for CZ gate
### What should we add?

The current version of the transpiler raises the following error when attempting to set the basis gate of a backend as `cz` 

` 'Flipping of gate direction is only supported for CX, ECR, and RZX at this time, not cz.' `

As far as I'm aware and through my own testing flipping of a CZ should be easy to implement as it's "flip" produces the same unitary operator. There is no direct identity needed. 

If this could get added that would be great! I would have done this via a pull request myself but it seems "too easy" of a solution that I must be missing something.

The Qiskit file that would need changing. 
https://github.com/Qiskit/qiskit-terra/blob/1312624309526812eb62b97e0d47699d46649a25/qiskit/transpiler/passes/utils/gate_direction.py



Pull request:
Fix flipping of gate direction in transpiler for CZ gate
<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [x] I have added the tests to cover my changes.
- [x] I have updated the documentation accordingly.
- [x] I have read the CONTRIBUTING document.
-->

### Summary

Fixes #8387.

### Details and comments

The CZ gate is symmetric, so should not fail in a pass that flips gates to match the coupling map.

Implementation based on code by @JMuff22


Patch:
diff --git a/qiskit/transpiler/passes/utils/gate_direction.py b/qiskit/transpiler/passes/utils/gate_direction.py
index 90e66821a..3c331441d 100644
--- a/qiskit/transpiler/passes/utils/gate_direction.py
+++ b/qiskit/transpiler/passes/utils/gate_direction.py
@@ -20,7 +20,7 @@ from qiskit.transpiler.exceptions import TranspilerError
 
 from qiskit.circuit import QuantumRegister
 from qiskit.dagcircuit import DAGCircuit
-from qiskit.circuit.library.standard_gates import RYGate, HGate, CXGate, ECRGate, RZXGate
+from qiskit.circuit.library.standard_gates import RYGate, HGate, CXGate, CZGate, ECRGate, RZXGate
 
 
 class GateDirection(TransformationPass):
@@ -78,6 +78,11 @@ class GateDirection(TransformationPass):
         self._ecr_dag.apply_operation_back(HGate(), [qr[0]], [])
         self._ecr_dag.apply_operation_back(HGate(), [qr[1]], [])
 
+        self._cz_dag = DAGCircuit()
+        qr = QuantumRegister(2)
+        self._cz_dag.add_qreg(qr)
+        self._cz_dag.apply_operation_back(CZGate(), [qr[1], qr[0]], [])
+
     @staticmethod
     def _rzx_dag(parameter):
         _rzx_dag = DAGCircuit()
@@ -138,6 +143,8 @@ class GateDirection(TransformationPass):
                 if (physical_q0, physical_q1) not in cmap_edges:
                     if node.name == "cx":
                         dag.substitute_node_with_dag(node, self._cx_dag)
+                    elif node.name == "cz":
+                        dag.substitute_node_with_dag(node, self._cz_dag)
                     elif node.name == "ecr":
                         dag.substitute_node_with_dag(node, self._ecr_dag)
                     elif node.name == "rzx":
@@ -169,6 +176,16 @@ class GateDirection(TransformationPass):
                             "The circuit requires a connection between physical "
                             "qubits %s and %s for cx" % (physical_q0, physical_q1)
                         )
+                elif node.name == "cz":
+                    if (physical_q0, physical_q1) in self.target["cz"]:
+                        continue
+                    if (physical_q1, physical_q0) in self.target["cz"]:
+                        dag.substitute_node_with_dag(node, self._cz_dag)
+                    else:
+                        raise TranspilerError(
+                            "The circuit requires a connection between physical "
+                            "qubits %s and %s for cz" % (physical_q0, physical_q1)
+                        )
                 elif node.name == "ecr":
                     if (physical_q0, physical_q1) in self.target["ecr"]:
                         continue
diff --git a/releasenotes/notes/fix-flipping-cz-gate-fd08305ca12d9a79.yaml b/releasenotes/notes/fix-flipping-cz-gate-fd08305ca12d9a79.yaml
new file mode 100644
index 000000000..4c27b40a2
--- /dev/null
+++ b/releasenotes/notes/fix-flipping-cz-gate-fd08305ca12d9a79.yaml
@@ -0,0 +1,5 @@
+---
+fixes:
+  - |
+    Fix a problem in the `GateDirection` transpiler pass for the CZ gate. The CZ is symmetric, so flipping the qubit arguments is allowed to match the directed coupling map.
+


Test patch:
diff --git a/test/python/transpiler/test_gate_direction.py b/test/python/transpiler/test_gate_direction.py
index 0960c840d..59fa04a51 100644
--- a/test/python/transpiler/test_gate_direction.py
+++ b/test/python/transpiler/test_gate_direction.py
@@ -15,6 +15,7 @@ import unittest
 from math import pi
 
 from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
+from qiskit.compiler import transpile
 from qiskit.transpiler import TranspilerError
 from qiskit.transpiler import CouplingMap
 from qiskit.transpiler.passes import GateDirection
@@ -245,6 +246,21 @@ class TestGateDirection(QiskitTestCase):
 
         self.assertEqual(circuit_to_dag(expected), after)
 
+    def test_regression_gh_8387(self):
+        """Regression test for flipping of CZ gate"""
+        qc = QuantumCircuit(3)
+        qc.cz(1, 0)
+        qc.barrier()
+        qc.cz(2, 0)
+
+        coupling_map = CouplingMap([[0, 1], [1, 2]])
+        _ = transpile(
+            qc,
+            basis_gates=["cz", "cx", "u3", "u2", "u1"],
+            coupling_map=coupling_map,
+            optimization_level=2,
+        )
+
 
 if __name__ == "__main__":
     unittest.main()