Repository: Qiskit/qiskit

Issue:
Quantum shannon decomposition failing for some inputs
### Environment

- **Qiskit Terra version**: 0.42.1
- **Python version**: 3.10.8



### What is happening?

qs_decomposition in [qsd.py](https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/quantum_info/synthesis/qsd.py) throws an error for some examples, seemingly due to a bug in the code

### How can we reproduce the issue?

```
from qiskit.quantum_info.synthesis.qsd import qs_decomposition
qs_decomposition(np.array([[0,1],[1,0]]))
```
Output:
```
Traceback (most recent call last):
  Cell In[14], line 3
    qs_decomposition(np.array([[0,1],[1,0]]))
  File /opt/conda/lib/python3.10/site-packages/qiskit/quantum_info/synthesis/qsd.py:122 in qs_decomposition
    return _apply_a2(circ)
  File /opt/conda/lib/python3.10/site-packages/qiskit/quantum_info/synthesis/qsd.py:253 in _apply_a2
    qc3 = two_qubit_decompose.two_qubit_cnot_decompose(mat2)
UnboundLocalError: local variable 'mat2' referenced before assignment
 
Use %tb to get the full traceback.
```
Alternatively,
```
qs_decomposition(qiskit.quantum_info.random_unitary(4).to_matrix())
```
Giving the same error

### What should happen?

We should still be able to produce a decomposed circuit from these examples

### Any suggestions?

This seems to occur when line 233 of qsd.py in the function ‘_apply_a2()’ does not transpile to include any of the ‘qsd2q’ gate type for an instance.

To fix this add something such as the following before the loop on line 242:
```
if not ind2q:
    return ccirc
```
Additionally should add a test for this kind of case to the [test](https://github.com/Qiskit/qiskit-terra/blob/main/test/python/quantum_info/test_synthesis.py) 


Discussion:
I can correct this with the above indicated as long as the reasoning follows
Yeah, I believe your reasoning is correct here, thanks - I don't think there's anything to do if there's nothing to decompose.  @ewinston can check me, though, and I'll assign him to the PR if you're able to make it.  Let us know if not, though, and one of us will.
The `_apply_a2` function actually wasn't supposed to by applied for `dim == 2`. I can submit a pr for that fix. Did you ever notice this for dimension > 2?

Resolving patch:
diff --git a/qiskit/quantum_info/synthesis/qsd.py b/qiskit/quantum_info/synthesis/qsd.py
--- a/qiskit/quantum_info/synthesis/qsd.py
+++ b/qiskit/quantum_info/synthesis/qsd.py
@@ -81,7 +81,7 @@ def qs_decomposition(
         circ = decomposer_1q(mat)
     elif dim == 4:
         if decomposer_2q is None:
-            if opt_a2:
+            if opt_a2 and _depth > 0:
                 from qiskit.extensions.unitary import UnitaryGate  # pylint: disable=cyclic-import
 
                 def decomp_2q(mat):
@@ -118,7 +118,7 @@ def decomp_2q(mat):
         right_circ = _demultiplex(u1, u2, opt_a1=opt_a1, opt_a2=opt_a2, _depth=_depth)
         circ.append(right_circ.to_instruction(), qr)
 
-    if opt_a2 and _depth == 0:
+    if opt_a2 and _depth == 0 and dim > 4:
         return _apply_a2(circ)
     return circ
 
@@ -236,6 +236,8 @@ def _apply_a2(circ):
     for i, instruction in enumerate(ccirc.data):
         if instruction.operation.name == "qsd2q":
             ind2q.append(i)
+    if not ind2q:
+        return ccirc
     # rolling over diagonals
     ind2 = None  # lint
     for ind1, ind2 in zip(ind2q[0:-1:], ind2q[1::]):


Test patch:
diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py
--- a/test/python/quantum_info/test_synthesis.py
+++ b/test/python/quantum_info/test_synthesis.py
@@ -1530,7 +1530,7 @@ def test_hermitian(self, nqubits):
             expected_cx = self._qsd_l2_cx_count(nqubits) - self._qsd_l2_a1_mod(nqubits)
             self.assertLessEqual(ccirc.count_ops().get("cx"), expected_cx)
 
-    @data(*list(range(3, 6)))
+    @data(*list(range(1, 6)))
     def test_opt_a1a2(self, nqubits):
         """Test decomposition with both optimization a1 and a2 from shende2006"""
         dim = 2**nqubits
@@ -1538,9 +1538,15 @@ def test_opt_a1a2(self, nqubits):
         circ = self.qsd(umat, opt_a1=True, opt_a2=True)
         ccirc = transpile(circ, basis_gates=["u", "cx"], optimization_level=0)
         self.assertTrue(Operator(umat) == Operator(ccirc))
-        self.assertEqual(
-            ccirc.count_ops().get("cx"), (23 / 48) * 4**nqubits - (3 / 2) * 2**nqubits + 4 / 3
-        )
+        if nqubits > 2:
+            self.assertEqual(
+                ccirc.count_ops().get("cx"),
+                (23 / 48) * 4**nqubits - (3 / 2) * 2**nqubits + 4 / 3,
+            )
+        elif nqubits == 1:
+            self.assertEqual(ccirc.count_ops().get("cx", 0), 0)
+        elif nqubits == 2:
+            self.assertLessEqual(ccirc.count_ops().get("cx", 0), 3)
 
 
 class TestTwoQubitDecomposeUpToDiagonal(QiskitTestCase):