Repository: Qiskit/qiskit

Issue:
Consolidate Euler basis selection from basis_gates
<!-- ⚠️ 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?

As came up in #5583 , a few places in the transpiler need to find the right `OneQubitEulerDecomposer` basis to use from a given `basis_gates`. These are duplicated now, and each has its own mapping from gate name to Euler basis. It would be better if this could be consolidated and generalized, so that new bases can be added to the decomposer and picked up automatically in the transpiler.



Discussion:
Do you think just adding a constant global dict to the one qubit decomposer module would be sufficient for this? So we can just import that and replace the copies in the 2 transpiler passes. That would keep it close the source of truth for what the decomposer can do.
:+1: That'd resolve it. (I had been wondering about updating `OneQubitEulerDecomposer` to use standard gate names (or `Gate` objects) so a user wouldn't have to do the search themselves, but that I think is a larger issue.)

Resolving patch:
diff --git a/qiskit/quantum_info/synthesis/one_qubit_decompose.py b/qiskit/quantum_info/synthesis/one_qubit_decompose.py
--- a/qiskit/quantum_info/synthesis/one_qubit_decompose.py
+++ b/qiskit/quantum_info/synthesis/one_qubit_decompose.py
@@ -28,6 +28,18 @@
 
 DEFAULT_ATOL = 1e-12
 
+ONE_QUBIT_EULER_BASIS_GATES = {
+    'U3': ['u3'],
+    'U': ['u'],
+    'PSX': ['p', 'sx'],
+    'U1X': ['u1', 'rx'],
+    'RR': ['r'],
+    'ZYZ': ['rz', 'ry'],
+    'ZXZ': ['rz', 'rx'],
+    'XYX': ['rx', 'ry'],
+    'ZSX': ['rz', 'sx'],
+}
+
 
 class OneQubitEulerDecomposer:
     r"""A class for decomposing 1-qubit unitaries into Euler angle rotations.
diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py
--- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py
+++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py
@@ -19,7 +19,7 @@
 from qiskit.circuit import QuantumCircuit, QuantumRegister
 from qiskit.quantum_info import Operator
 from qiskit.transpiler.basepasses import TransformationPass
-from qiskit.quantum_info import OneQubitEulerDecomposer
+from qiskit.quantum_info.synthesis import one_qubit_decompose
 from qiskit.converters import circuit_to_dag
 
 LOG = logging.getLogger(__name__)
@@ -37,24 +37,13 @@ def __init__(self, basis=None):
                 and the Euler basis.
         """
         super().__init__()
-        self.euler_basis_names = {
-            'U3': ['u3'],
-            'U': ['u'],
-            'PSX': ['p', 'sx'],
-            'U1X': ['u1', 'rx'],
-            'RR': ['r'],
-            'ZYZ': ['rz', 'ry'],
-            'ZXZ': ['rz', 'rx'],
-            'XYX': ['rx', 'ry'],
-            'ZSX': ['rz', 'sx'],
-        }
         self.basis = None
         if basis:
             self.basis = []
             basis_set = set(basis)
-            for basis_name, gates in self.euler_basis_names.items():
+            for basis_name, gates in one_qubit_decompose.ONE_QUBIT_EULER_BASIS_GATES.items():
                 if set(gates).issubset(basis_set):
-                    self.basis.append(OneQubitEulerDecomposer(basis_name))
+                    self.basis.append(one_qubit_decompose.OneQubitEulerDecomposer(basis_name))
 
     def run(self, dag):
         """Run the Optimize1qGatesDecomposition pass on `dag`.
diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
--- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
+++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
@@ -20,7 +20,7 @@
 from qiskit.dagcircuit.dagcircuit import DAGCircuit
 from qiskit.circuit.library.standard_gates import iSwapGate, CXGate, CZGate, RXXGate
 from qiskit.extensions.quantum_initializer import isometry
-from qiskit.quantum_info.synthesis.one_qubit_decompose import OneQubitEulerDecomposer
+from qiskit.quantum_info.synthesis import one_qubit_decompose
 from qiskit.quantum_info.synthesis.two_qubit_decompose import TwoQubitBasisDecomposer
 
 
@@ -44,22 +44,9 @@ def _choose_kak_gate(basis_gates):
 
 def _choose_euler_basis(basis_gates):
     """"Choose the first available 1q basis to use in the Euler decomposition."""
-
-    euler_basis_names = {
-        'U3': ['u3'],
-        'U': ['u'],
-        'PSX': ['p', 'sx'],
-        'U1X': ['u1', 'rx'],
-        'RR': ['r'],
-        'ZYZ': ['rz', 'ry'],
-        'ZXZ': ['rz', 'rx'],
-        'XYX': ['rx', 'ry'],
-        'ZSX': ['rz', 'sx'],
-    }
-
     basis_set = set(basis_gates or [])
 
-    for basis, gates in euler_basis_names.items():
+    for basis, gates in one_qubit_decompose.ONE_QUBIT_EULER_BASIS_GATES.items():
         if set(gates).issubset(basis_set):
             return basis
 
@@ -92,7 +79,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
 
         decomposer1q, decomposer2q = None, None
         if euler_basis is not None:
-            decomposer1q = OneQubitEulerDecomposer(euler_basis)
+            decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer(euler_basis)
         if kak_gate is not None:
             decomposer2q = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis)
 


Test patch: