Repository: Qiskit/qiskit-ibm-runtime (python)

Issue:
DoubleSliceSpan.mask crashes
**Describe the bug**

It crashes in a real-world case, coming from a real execution result.


**Steps to reproduce**

```python
from qiskit_ibm_runtime.execution_span.double_slice_span import DoubleSliceSpan

span = DoubleSliceSpan(1, 2, {0: ((7,), slice(0, 1, None), slice(0, 7, None))})
span.mask(0)
```

Output:
```
Traceback (most recent call last):
  File "/mnt/wsl/balagan/doubleslicespan_mask_bug.py", line 4, in <module>
    span.mask(0)
  File "/root/miniforge3/envs/env5/lib/python3.11/site-packages/qiskit_ibm_runtime/execution_span/double_slice_span.py", line 73, in mask
    mask.reshape(np.prod(shape[:-1]), shape[-1])[(args_sl, shots_sl)] = True
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'numpy.float64' object cannot be interpreted as an integer
```


**Expected behavior**


**Suggested solutions**


**Additional Information**

- **qiskit-ibm-runtime version**: 0.34.0
- **Python version**: 3.11.10
- **Operating system**: Linux (Windows + WSL)


Pull request:
Fix DoubleSliceSpan and TwirledSliceSpan mask methods
<!--
⚠️ The 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
Fixes bug with `DoubleSliceSpan.mask` and `TwirledSliceSpan.mask` when their shapes are one-dimensional.


### Details and comments
Fixes #2184 



Patch:
diff --git a/qiskit_ibm_runtime/execution_span/double_slice_span.py b/qiskit_ibm_runtime/execution_span/double_slice_span.py
index 70238f50..659f47c0 100644
--- a/qiskit_ibm_runtime/execution_span/double_slice_span.py
+++ b/qiskit_ibm_runtime/execution_span/double_slice_span.py
@@ -70,7 +70,7 @@ class DoubleSliceSpan(ExecutionSpan):
     def mask(self, pub_idx: int) -> npt.NDArray[np.bool_]:
         shape, args_sl, shots_sl = self._data_slices[pub_idx]
         mask = np.zeros(shape, dtype=np.bool_)
-        mask.reshape(np.prod(shape[:-1]), shape[-1])[(args_sl, shots_sl)] = True
+        mask.reshape(np.prod(shape[:-1], dtype=int), shape[-1])[(args_sl, shots_sl)] = True
         return mask
 
     def filter_by_pub(self, pub_idx: int | Iterable[int]) -> "DoubleSliceSpan":
diff --git a/qiskit_ibm_runtime/execution_span/twirled_slice_span.py b/qiskit_ibm_runtime/execution_span/twirled_slice_span.py
index 06be56d7..536d67f7 100644
--- a/qiskit_ibm_runtime/execution_span/twirled_slice_span.py
+++ b/qiskit_ibm_runtime/execution_span/twirled_slice_span.py
@@ -73,18 +73,18 @@ class TwirledSliceSpan(ExecutionSpan):
         return size
 
     def mask(self, pub_idx: int) -> npt.NDArray[np.bool_]:
-        twirled_shape, at_front, shape_sl, shots_sl = self._data_slices[pub_idx]
-        mask = np.zeros(twirled_shape, dtype=np.bool_)
-        mask.reshape((np.prod(twirled_shape[:-1]), twirled_shape[-1]))[(shape_sl, shots_sl)] = True
+        shape, at_front, shape_sl, shots_sl = self._data_slices[pub_idx]
+        mask = np.zeros(shape, dtype=np.bool_)
+        mask.reshape((np.prod(shape[:-1], dtype=int), shape[-1]))[(shape_sl, shots_sl)] = True
 
         if at_front:
             # if the first axis is over twirling samples, push them right before shots
-            ndim = len(twirled_shape)
+            ndim = len(shape)
             mask = mask.transpose((*range(1, ndim - 1), 0, ndim - 1))
-            twirled_shape = twirled_shape[1:-1] + twirled_shape[:1] + twirled_shape[-1:]
+            shape = shape[1:-1] + shape[:1] + shape[-1:]
 
         # merge twirling axis and shots axis before returning
-        return mask.reshape((*twirled_shape[:-2], math.prod(twirled_shape[-2:])))
+        return mask.reshape((*shape[:-2], math.prod(shape[-2:])))
 
     def filter_by_pub(self, pub_idx: int | Iterable[int]) -> "TwirledSliceSpan":
         pub_idx = {pub_idx} if isinstance(pub_idx, int) else set(pub_idx)
diff --git a/release-notes/unreleased/2184.bug.rst b/release-notes/unreleased/2184.bug.rst
new file mode 100644
index 00000000..8f7432ba
--- /dev/null
+++ b/release-notes/unreleased/2184.bug.rst
@@ -0,0 +1,2 @@
+Fixed a bug where :meth:`~.DoubleSliceSpan.mask` and :meth:`~TwirledSliceSpan.mask` error
+when they contain a one-dimensional slice.
\ No newline at end of file


Test patch:
diff --git a/test/unit/test_execution_span.py b/test/unit/test_execution_span.py
index 26911f5f..eba5558f 100644
--- a/test/unit/test_execution_span.py
+++ b/test/unit/test_execution_span.py
@@ -226,6 +226,12 @@ class TestDoubleSliceSpan(IBMTestCase):
             DoubleSliceSpan(self.start1, self.stop1, {2: self.slices1[2]}),
         )
 
+    def test_one_dimensional_shape_mask(self):
+        """Test that mask doesn't throw with a one-dimensional shape"""
+        span = DoubleSliceSpan(self.start1, self.stop1, {0: ((7,), slice(0, 1), slice(0, 7))})
+
+        span.mask(0)
+
 
 @ddt.ddt
 class TestTwirledSliceSpan(IBMTestCase):
@@ -338,6 +344,13 @@ class TestTwirledSliceSpan(IBMTestCase):
             TwirledSliceSpan(self.start1, self.stop1, {2: self.slices1[2]}),
         )
 
+    def test_one_dimensional_shape_mask(self):
+        """Test that mask doesn't throw with a one-dimensional shape"""
+        span = TwirledSliceSpan(
+            self.start1, self.stop1, {0: ((7,), False, slice(0, 1), slice(0, 7))}
+        )
+        span.mask(0)
+
 
 @ddt.ddt
 class TestExecutionSpans(IBMTestCase):