Repository: Qiskit/qiskit

Issue:
Transpiling `cp` into `['u', 'cx']` works; transpiling `cx` into `['u', 'cp']` doesn't
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: `0.18.0`
- **Python version**: `Python 3.9.6`
- **Operating system**: `Pop!_OS 21.04 x86_64`

### What is the current behavior?
I am able to transpile a `cp` gate into using `['u', 'cx']` as basis gates, but I am unable to transpile a `cx` gate using `['u', 'cp']`. I want to be able to use `['u', 'cp']` as the transpilation target for more advanced circuits, but it does not work. Additionally, trying to transpile to `['u', 'crz']` also fails.


### Steps to reproduce the problem
```
from qiskit import QuantumCircuit, QuantumRegister
from qiskit import transpile
import numpy as np

# works fine
qr3 = QuantumRegister(2)
qc3 = QuantumCircuit(qr3)
qc3.cp(np.pi, qr3[0], qr3[1])
qc3 = transpile(qc3, basis_gates=['u', 'cx'])
print(qc3)

# fails to transpile
qr1 = QuantumRegister(2)
qc1 = QuantumCircuit(qr1)
qc1.cx(qr1[0], qr1[1])
qc1 = transpile(qc1, basis_gates=['u', 'cp'])
print(qc1)
```


### What is the expected behavior?
Transpilation  should work in both directions, and `['u', 'cp']` should be a complete gate set.

### Suggested solutions
I believe this is an issue with the way the transpiler runs; I don't understand all of the details of the transpiler to offer any useful suggestions.




Discussion:
I'm hoping #6784 can be extended to cover this situation
This can be handled by adding a rule from `cx` to `cphase+u` and `crz+u` to the equivalence library for the standard gates: https://github.com/Qiskit/qiskit-terra/blob/75e06dc915f764ea4e5c1a57097e980e9d01b119/qiskit/circuit/library/standard_gates/equivalence_library.py#L620 .
@kdk if possible, I'd like to work on this!

As far as I understood, I would need to add a decomposition of CX into CP + U and CRZ + U in the file you linked. Is that right?
> @kdk if possible, I'd like to work on this!
> 
> As far as I understood, I would need to add a decomposition of CX into CP + U and CRZ + U in the file you linked. Is that right?

Hi @epelaaez , that's right. See #7007 for a similar fix.

Resolving patch:
diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py
--- a/qiskit/circuit/library/standard_gates/equivalence_library.py
+++ b/qiskit/circuit/library/standard_gates/equivalence_library.py
@@ -958,6 +958,38 @@
     cx_to_ecr.append(inst, qargs, cargs)
 _sel.add_equivalence(CXGate(), cx_to_ecr)
 
+# CXGate
+# q_0: ──■──     q_0: ───────────────■───────────────────
+#      ┌─┴─┐  ≡       ┌────────────┐ │P(π) ┌────────────┐
+# q_1: ┤ X ├     q_1: ┤ U(π/2,0,π) ├─■─────┤ U(π/2,0,π) ├
+#      └───┘          └────────────┘       └────────────┘
+q = QuantumRegister(2, "q")
+cx_to_cp = QuantumCircuit(q)
+for inst, qargs, cargs in [
+    (UGate(pi / 2, 0, pi), [q[1]], []),
+    (CPhaseGate(pi), [q[0], q[1]], []),
+    (UGate(pi / 2, 0, pi), [q[1]], []),
+]:
+    cx_to_cp.append(inst, qargs, cargs)
+_sel.add_equivalence(CXGate(), cx_to_cp)
+
+# CXGate
+#                     ┌────────────┐
+# q_0: ──■──     q_0: ┤ U(0,0,π/2) ├────■──────────────────
+#      ┌─┴─┐  ≡       ├────────────┤┌───┴───┐┌────────────┐
+# q_1: ┤ X ├     q_1: ┤ U(π/2,0,π) ├┤ Rz(π) ├┤ U(π/2,0,π) ├
+#      └───┘          └────────────┘└───────┘└────────────┘
+q = QuantumRegister(2, "q")
+cx_to_crz = QuantumCircuit(q)
+for inst, qargs, cargs in [
+    (UGate(pi / 2, 0, pi), [q[1]], []),
+    (UGate(0, 0, pi / 2), [q[0]], []),
+    (CRZGate(pi), [q[0], q[1]], []),
+    (UGate(pi / 2, 0, pi), [q[1]], []),
+]:
+    cx_to_crz.append(inst, qargs, cargs)
+_sel.add_equivalence(CXGate(), cx_to_crz)
+
 # CXGate
 #                global phase: π/4
 #                     ┌───────────┐┌─────┐


Test patch:
diff --git a/test/python/transpiler/test_basis_translator.py b/test/python/transpiler/test_basis_translator.py
--- a/test/python/transpiler/test_basis_translator.py
+++ b/test/python/transpiler/test_basis_translator.py
@@ -819,6 +819,51 @@ def test_cx_bell_to_ecr(self):
 
         self.assertEqual(out_dag, expected_dag)
 
+    def test_cx_bell_to_cp(self):
+        """Verify we can translate a CX bell to CP,U."""
+        bell = QuantumCircuit(2)
+        bell.h(0)
+        bell.cx(0, 1)
+
+        in_dag = circuit_to_dag(bell)
+        out_dag = BasisTranslator(std_eqlib, ["cp", "u"]).run(in_dag)
+
+        self.assertTrue(set(out_dag.count_ops()).issubset(["cp", "u"]))
+        self.assertEqual(Operator(bell), Operator(dag_to_circuit(out_dag)))
+
+        qr = QuantumRegister(2, "q")
+        expected = QuantumCircuit(qr)
+        expected.u(pi / 2, 0, pi, 0)
+        expected.u(pi / 2, 0, pi, 1)
+        expected.cp(pi, 0, 1)
+        expected.u(pi / 2, 0, pi, 1)
+        expected_dag = circuit_to_dag(expected)
+
+        self.assertEqual(out_dag, expected_dag)
+
+    def test_cx_bell_to_crz(self):
+        """Verify we can translate a CX bell to CRZ,U."""
+        bell = QuantumCircuit(2)
+        bell.h(0)
+        bell.cx(0, 1)
+
+        in_dag = circuit_to_dag(bell)
+        out_dag = BasisTranslator(std_eqlib, ["crz", "u"]).run(in_dag)
+
+        self.assertTrue(set(out_dag.count_ops()).issubset(["crz", "u"]))
+        self.assertEqual(Operator(bell), Operator(dag_to_circuit(out_dag)))
+
+        qr = QuantumRegister(2, "q")
+        expected = QuantumCircuit(qr)
+        expected.u(pi / 2, 0, pi, 0)
+        expected.u(0, 0, pi / 2, 0)
+        expected.u(pi / 2, 0, pi, 1)
+        expected.crz(pi, 0, 1)
+        expected.u(pi / 2, 0, pi, 1)
+        expected_dag = circuit_to_dag(expected)
+
+        self.assertEqual(out_dag, expected_dag)
+
     def test_global_phase(self):
         """Verify global phase preserved in basis translation"""
         circ = QuantumCircuit(1)