Repository: Qiskit/qiskit-terra (python)

Issue:
marginal_distribution raises for NumPy array indices
### Environment

- **Qiskit Terra version**: 0.21
- **Python version**: 3.10
- **Operating system**: osx


### What is happening?

`marginal_distribution` raises error when passes a NumPy array of indices:

```python

marginal_distribution(counts, np.asarray([0, 2]))
```


--> 225 if indices is not None and (not indices or not set(indices).issubset(range(num_clbits))):
    226     raise QiskitError(f"indices must be in range [0, {num_clbits - 1}].")
    228 if isinstance(counts, Counts):

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()


### How can we reproduce the issue?

Try above

### What should happen?

It should work for both lists and arrays.

### Any suggestions?

_No response_

Pull request:
Fix handling of numpy arrays for indices in marginal_distribution
<!--
⚠️ 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.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->

### Summary

This commit fixes an issue with the marginal_distribution() function
where it would previously error if a numpy arrray of ints was passed in
for the indices parameter. This was caused by the input validation
looking for empty input by checking `not indices` which isn't valid for
numpy arrays. This commit fixes this by adjusting the check for
empty lists to work with any sequence input.

### Details and comments

Fixes #8283


Patch:
diff --git a/qiskit/result/utils.py b/qiskit/result/utils.py
index 498798bbe..d0fb018e8 100644
--- a/qiskit/result/utils.py
+++ b/qiskit/result/utils.py
@@ -14,7 +14,7 @@
 
 """Utility functions for working with Results."""
 
-from typing import List, Union, Optional, Dict
+from typing import Sequence, Union, Optional, Dict, List
 from collections import Counter
 from copy import deepcopy
 
@@ -199,7 +199,9 @@ def marginal_memory(
 
 
 def marginal_distribution(
-    counts: dict, indices: Optional[List[int]] = None, format_marginal: bool = False
+    counts: dict,
+    indices: Optional[Sequence[int]] = None,
+    format_marginal: bool = False,
 ) -> Dict[str, int]:
     """Marginalize counts from an experiment over some indices of interest.
 
@@ -222,7 +224,7 @@ def marginal_distribution(
         is invalid.
     """
     num_clbits = len(max(counts.keys()).replace(" ", ""))
-    if indices is not None and (not indices or not set(indices).issubset(range(num_clbits))):
+    if indices is not None and (len(indices) == 0 or not set(indices).issubset(range(num_clbits))):
         raise QiskitError(f"indices must be in range [0, {num_clbits - 1}].")
 
     if isinstance(counts, Counts):
diff --git a/releasenotes/notes/fix-numpy-indices-marginal-dist-45889e49ba337d84.yaml b/releasenotes/notes/fix-numpy-indices-marginal-dist-45889e49ba337d84.yaml
new file mode 100644
index 000000000..713a22b1f
--- /dev/null
+++ b/releasenotes/notes/fix-numpy-indices-marginal-dist-45889e49ba337d84.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    Fixed an issue with the :func:`~.marginal_distribution` function: when
+    a numpy array was passed in for the ``indices`` argument the function would
+    raise an error.
+    Fixed `#8283 <https://github.com/Qiskit/qiskit-terra/issues/8283>`__


Test patch:
diff --git a/test/python/result/test_counts.py b/test/python/result/test_counts.py
index 33d93c25e..6fa52b929 100644
--- a/test/python/result/test_counts.py
+++ b/test/python/result/test_counts.py
@@ -16,6 +16,8 @@
 
 import unittest
 
+import numpy as np
+
 from qiskit.result import counts
 from qiskit import exceptions
 from qiskit.result import utils
@@ -50,6 +52,14 @@ class TestCounts(unittest.TestCase):
         result = utils.marginal_distribution(counts_obj, [0, 1])
         self.assertEqual(expected, result)
 
+    def test_marginal_distribution_numpy_indices(self):
+        raw_counts = {"0x0": 4, "0x1": 7, "0x2": 10, "0x6": 5, "0x9": 11, "0xD": 9, "0xE": 8}
+        expected = {"00": 4, "01": 27, "10": 23}
+        indices = np.asarray([0, 1])
+        counts_obj = counts.Counts(raw_counts, creg_sizes=[["c0", 4]], memory_slots=4)
+        result = utils.marginal_distribution(counts_obj, indices)
+        self.assertEqual(expected, result)
+
     def test_int_outcomes(self):
         raw_counts = {"0x0": 21, "0x2": 12, "0x3": 5, "0x2E": 265}
         expected = {0: 21, 2: 12, 3: 5, 46: 265}