Repository: Qiskit/qiskit

Issue:
Translation of single-qubit gate gives IndexError
### Environment

- **Qiskit Terra version**: e62ac0eb72a9abf2d1c61ca49a32c2399c3a9359
- **Python version**: 3.10.7
- **Operating system**: Arch Linux


### What is happening?

See title.

### How can we reproduce the issue?

```python
from qiskit import *
from qiskit.circuit.library import *
from qiskit.providers.fake_provider import FakeBelemV2
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import *
from qiskit.transpiler.passmanager import StagedPassManager
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.preset_passmanagers.common import *
from qiskit.transpiler.preset_passmanagers.plugin import *


def generate_pass_manager(backend) -> PassManager:
    init = generate_unroll_3q(backend.target)
    translation = generate_translation_passmanager(
        backend.target, basis_gates=backend.operation_names
    )
    return StagedPassManager(
        init=init,
        translation=translation,
    )

system_register = QuantumRegister(1)
circuit = QuantumCircuit(system_register)
circuit.append(
    ZGate().power(0.1),
    [system_register[0]],
)

backend = backend=FakeBelemV2()
pass_manager = generate_pass_manager(backend)
transpiled = pass_manager.run(circuit)
```
```
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In [1], line 31
     29 backend = backend=FakeBelemV2()
     30 pass_manager = generate_pass_manager(backend)
---> 31 transpiled = pass_manager.run(circuit)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:511, in StagedPassManager.run(self, circuits, output_name, callback)
    504 def run(
    505     self,
    506     circuits: Union[QuantumCircuit, List[QuantumCircuit]],
    507     output_name: str = None,
    508     callback: Callable = None,
    509 ) -> Union[QuantumCircuit, List[QuantumCircuit]]:
    510     self._update_passmanager()
--> 511     return super().run(circuits, output_name, callback)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:224, in PassManager.run(self, circuits, output_name, callback)
    222     return circuits
    223 if isinstance(circuits, QuantumCircuit):
--> 224     return self._run_single_circuit(circuits, output_name, callback)
    225 if len(circuits) == 1:
    226     return self._run_single_circuit(circuits[0], output_name, callback)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:279, in PassManager._run_single_circuit(self, circuit, output_name, callback)
    267 """Run all the passes on a ``circuit``.
    268 
    269 Args:
   (...)
    276     The transformed circuit.
    277 """
    278 running_passmanager = self._create_running_passmanager()
--> 279 result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
    280 self.property_set = running_passmanager.property_set
    281 return result

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:125, in RunningPassManager.run(***failed resolving arguments***)
    123 for passset in self.working_list:
    124     for pass_ in passset:
--> 125         dag = self._do_pass(pass_, dag, passset.options)
    127 circuit = dag_to_circuit(dag)
    128 if output_name:

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:172, in RunningPassManager._do_pass(self, pass_, dag, options)
    170 # Run the pass itself, if not already run
    171 if pass_ not in self.valid_passes:
--> 172     dag = self._run_this_pass(pass_, dag)
    174     # update the valid_passes property
    175     self._update_valid_passes(pass_)

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:201, in RunningPassManager._run_this_pass(self, pass_, dag)
    198 if pass_.is_transformation_pass:
    199     # Measure time if we have a callback or logging set
    200     start_time = time()
--> 201     new_dag = pass_.run(dag)
    202     end_time = time()
    203     run_time = end_time - start_time

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:308, in UnitarySynthesis.run(self, dag)
    305 if self.method == "default":
    306     # pylint: disable=attribute-defined-outside-init
    307     plugin_method._approximation_degree = self._approximation_degree
--> 308 return self._run_main_loop(
    309     dag, plugin_method, plugin_kwargs, default_method, default_kwargs
    310 )

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:349, in UnitarySynthesis._run_main_loop(self, dag, plugin_method, plugin_kwargs, default_method, default_kwargs)
    344 if method.supports_coupling_map:
    345     kwargs["coupling_map"] = (
    346         self._coupling_map,
    347         [dag_bit_indices[x] for x in node.qargs],
    348     )
--> 349 synth_dag = method.run(unitary, **kwargs)
    350 if synth_dag is not None:
    351     if isinstance(synth_dag, tuple):

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:540, in DefaultUnitarySynthesis.run(self, unitary, **options)
    538 preferred_direction = None
    539 if target is not None:
--> 540     decomposer2q, preferred_direction = self._find_decomposer_2q_from_target(
    541         target, qubits, pulse_optimize
    542     )
    543 else:
    544     decomposer2q = _basis_gates_to_decomposer_2q(basis_gates, pulse_optimize=pulse_optimize)

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:447, in DefaultUnitarySynthesis._find_decomposer_2q_from_target(self, target, qubits, pulse_optimize)
    445 def _find_decomposer_2q_from_target(self, target, qubits, pulse_optimize):
    446     qubits_tuple = tuple(qubits)
--> 447     reverse_tuple = (qubits[1], qubits[0])
    448     if qubits_tuple in self._decomposer_cache:
    449         return self._decomposer_cache[qubits_tuple]

IndexError: list index out of range
```

### What should happen?

It should work.

### Any suggestions?

If I replace `ZGate().power(0.1)` with `RZGate(0.1)` no error is raised.


Discussion:
Here is a simpler reproduction:
```python
from qiskit import *
from qiskit.circuit.library import *
from qiskit.providers.fake_provider import FakeBelemV2

system_register = QuantumRegister(1)
circuit = QuantumCircuit(system_register)
circuit.append(
    ZGate().power(0.1),
    [system_register[0]],
)
transpiled = transpile(circuit, backend=FakeBelemV2())
```
```
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In [1], line 11
      6 circuit = QuantumCircuit(system_register)
      7 circuit.append(
      8     ZGate().power(0.1),
      9     [system_register[0]],
     10 )
---> 11 transpiled = transpile(circuit, backend=FakeBelemV2())

File ~/projects/qiskit-terra/qiskit/compiler/transpiler.py:382, in transpile(circuits, backend, basis_gates, inst_map, coupling_map, backend_properties, initial_layout, layout_method, routing_method, translation_method, scheduling_method, instruction_durations, dt, approximation_degree, timing_constraints, seed_transpiler, optimization_level, callback, output_name, unitary_synthesis_method, unitary_synthesis_plugin_config, target, hls_config, init_method, optimization_method, ignore_backend_supplied_default_methods)
    379     for circuit, unique_args in zip(circuits, unique_transpile_args):
    380         transpile_config, pass_manager = _combine_args(shared_args, unique_args)
    381         output_circuits.append(
--> 382             _serial_transpile_circuit(
    383                 circuit,
    384                 pass_manager,
    385                 transpile_config["callback"],
    386                 transpile_config["output_name"],
    387                 transpile_config["backend_num_qubits"],
    388                 transpile_config["faulty_qubits_map"],
    389                 transpile_config["pass_manager_config"].backend_properties,
    390             )
    391         )
    392     circuits = output_circuits
    393 end_time = time()

File ~/projects/qiskit-terra/qiskit/compiler/transpiler.py:475, in _serial_transpile_circuit(circuit, pass_manager, callback, output_name, num_qubits, faulty_qubits_map, backend_prop)
    466 def _serial_transpile_circuit(
    467     circuit,
    468     pass_manager,
   (...)
    473     backend_prop=None,
    474 ):
--> 475     result = pass_manager.run(circuit, callback=callback, output_name=output_name)
    476     if faulty_qubits_map:
    477         return _remap_circuit_faulty_backend(
    478             result,
    479             num_qubits,
    480             backend_prop,
    481             faulty_qubits_map,
    482         )

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:511, in StagedPassManager.run(self, circuits, output_name, callback)
    504 def run(
    505     self,
    506     circuits: Union[QuantumCircuit, List[QuantumCircuit]],
    507     output_name: str = None,
    508     callback: Callable = None,
    509 ) -> Union[QuantumCircuit, List[QuantumCircuit]]:
    510     self._update_passmanager()
--> 511     return super().run(circuits, output_name, callback)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:224, in PassManager.run(self, circuits, output_name, callback)
    222     return circuits
    223 if isinstance(circuits, QuantumCircuit):
--> 224     return self._run_single_circuit(circuits, output_name, callback)
    225 if len(circuits) == 1:
    226     return self._run_single_circuit(circuits[0], output_name, callback)

File ~/projects/qiskit-terra/qiskit/transpiler/passmanager.py:279, in PassManager._run_single_circuit(self, circuit, output_name, callback)
    267 """Run all the passes on a ``circuit``.
    268 
    269 Args:
   (...)
    276     The transformed circuit.
    277 """
    278 running_passmanager = self._create_running_passmanager()
--> 279 result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
    280 self.property_set = running_passmanager.property_set
    281 return result

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:125, in RunningPassManager.run(***failed resolving arguments***)
    123 for passset in self.working_list:
    124     for pass_ in passset:
--> 125         dag = self._do_pass(pass_, dag, passset.options)
    127 circuit = dag_to_circuit(dag)
    128 if output_name:

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:172, in RunningPassManager._do_pass(self, pass_, dag, options)
    170 # Run the pass itself, if not already run
    171 if pass_ not in self.valid_passes:
--> 172     dag = self._run_this_pass(pass_, dag)
    174     # update the valid_passes property
    175     self._update_valid_passes(pass_)

File ~/projects/qiskit-terra/qiskit/transpiler/runningpassmanager.py:201, in RunningPassManager._run_this_pass(self, pass_, dag)
    198 if pass_.is_transformation_pass:
    199     # Measure time if we have a callback or logging set
    200     start_time = time()
--> 201     new_dag = pass_.run(dag)
    202     end_time = time()
    203     run_time = end_time - start_time

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:308, in UnitarySynthesis.run(self, dag)
    305 if self.method == "default":
    306     # pylint: disable=attribute-defined-outside-init
    307     plugin_method._approximation_degree = self._approximation_degree
--> 308 return self._run_main_loop(
    309     dag, plugin_method, plugin_kwargs, default_method, default_kwargs
    310 )

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:349, in UnitarySynthesis._run_main_loop(self, dag, plugin_method, plugin_kwargs, default_method, default_kwargs)
    344 if method.supports_coupling_map:
    345     kwargs["coupling_map"] = (
    346         self._coupling_map,
    347         [dag_bit_indices[x] for x in node.qargs],
    348     )
--> 349 synth_dag = method.run(unitary, **kwargs)
    350 if synth_dag is not None:
    351     if isinstance(synth_dag, tuple):

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:540, in DefaultUnitarySynthesis.run(self, unitary, **options)
    538 preferred_direction = None
    539 if target is not None:
--> 540     decomposer2q, preferred_direction = self._find_decomposer_2q_from_target(
    541         target, qubits, pulse_optimize
    542     )
    543 else:
    544     decomposer2q = _basis_gates_to_decomposer_2q(basis_gates, pulse_optimize=pulse_optimize)

File ~/projects/qiskit-terra/qiskit/transpiler/passes/synthesis/unitary_synthesis.py:447, in DefaultUnitarySynthesis._find_decomposer_2q_from_target(self, target, qubits, pulse_optimize)
    445 def _find_decomposer_2q_from_target(self, target, qubits, pulse_optimize):
    446     qubits_tuple = tuple(qubits)
--> 447     reverse_tuple = (qubits[1], qubits[0])
    448     if qubits_tuple in self._decomposer_cache:
    449         return self._decomposer_cache[qubits_tuple]

IndexError: list index out of range
```
Oh, this is a pretty major bug, thanks for the report. I'm not sure how the `UnitarySynthesis` plugin _ever_ works with a `Target` if it needs to resynthesise a 1q gate, because there's this assumption you've found that it'll always be able to look up a 2q decomposer.
It looks like a bug in the unitary synthesis pass caused by running it with only a single 1q gate and a target. I'll propose a fix in a 
sec (I've got it locally)

Resolving patch:
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
@@ -529,27 +529,30 @@ def run(self, unitary, **options):
         qubits = options["coupling_map"][1]
         target = options["target"]
 
-        euler_basis = _choose_euler_basis(basis_gates)
-        if euler_basis is not None:
-            decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer(euler_basis)
-        else:
-            decomposer1q = None
-
-        preferred_direction = None
-        if target is not None:
-            decomposer2q, preferred_direction = self._find_decomposer_2q_from_target(
-                target, qubits, pulse_optimize
-            )
-        else:
-            decomposer2q = _basis_gates_to_decomposer_2q(basis_gates, pulse_optimize=pulse_optimize)
-
         synth_dag = None
         wires = None
         if unitary.shape == (2, 2):
+            if target is not None:
+                euler_basis = _choose_euler_basis(target.operation_names_for_qargs(tuple(qubits)))
+            else:
+                euler_basis = _choose_euler_basis(basis_gates)
+            if euler_basis is not None:
+                decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer(euler_basis)
+            else:
+                decomposer1q = None
             if decomposer1q is None:
                 return None
             synth_dag = circuit_to_dag(decomposer1q._decompose(unitary))
         elif unitary.shape == (4, 4):
+            preferred_direction = None
+            if target is not None:
+                decomposer2q, preferred_direction = self._find_decomposer_2q_from_target(
+                    target, qubits, pulse_optimize
+                )
+            else:
+                decomposer2q = _basis_gates_to_decomposer_2q(
+                    basis_gates, pulse_optimize=pulse_optimize
+                )
             if not decomposer2q:
                 return None
             synth_dag, wires = self._synth_natural_direction(


Test patch:
diff --git a/test/python/transpiler/test_unitary_synthesis.py b/test/python/transpiler/test_unitary_synthesis.py
--- a/test/python/transpiler/test_unitary_synthesis.py
+++ b/test/python/transpiler/test_unitary_synthesis.py
@@ -24,7 +24,7 @@
 
 from qiskit import transpile
 from qiskit.test import QiskitTestCase
-from qiskit.providers.fake_provider import FakeVigo, FakeMumbaiFractionalCX
+from qiskit.providers.fake_provider import FakeVigo, FakeMumbaiFractionalCX, FakeBelemV2
 from qiskit.providers.fake_provider.fake_backend_v2 import FakeBackendV2, FakeBackend5QV2
 from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
 from qiskit.circuit.library import QuantumVolume
@@ -51,7 +51,7 @@
     SabreSwap,
     TrivialLayout,
 )
-from qiskit.circuit.library import CXGate, ECRGate, UGate
+from qiskit.circuit.library import CXGate, ECRGate, UGate, ZGate
 from qiskit.circuit import Parameter
 
 
@@ -766,6 +766,26 @@ def test_nested_control_flow(self):
         self.assertEqual(cbody.count_ops().keys(), {"u", "cx"})
         self.assertEqual(qc_uni1_mat, Operator(cbody))
 
+    def test_single_qubit_with_target(self):
+        """Test input circuit with only 1q works with target."""
+        qc = QuantumCircuit(1)
+        qc.append(ZGate(), [qc.qubits[0]])
+        dag = circuit_to_dag(qc)
+        unitary_synth_pass = UnitarySynthesis(target=FakeBelemV2().target)
+        result_dag = unitary_synth_pass.run(dag)
+        result_qc = dag_to_circuit(result_dag)
+        self.assertEqual(qc, result_qc)
+
+    def test_single_qubit_identity_with_target(self):
+        """Test input single qubit identity works with target."""
+        qc = QuantumCircuit(1)
+        qc.unitary([[1.0, 0.0], [0.0, 1.0]], 0)
+        dag = circuit_to_dag(qc)
+        unitary_synth_pass = UnitarySynthesis(target=FakeBelemV2().target)
+        result_dag = unitary_synth_pass.run(dag)
+        result_qc = dag_to_circuit(result_dag)
+        self.assertEqual(result_qc, QuantumCircuit(1))
+
 
 if __name__ == "__main__":
     unittest.main()