Repository: Qiskit/qiskit

Issue:
Statevector.probabilities_dict generates incorrect outputs when qargs passed for non-qubit systems
### Environment

- **Qiskit Terra version**: 0.22.3
- **Python version**: 3.10
- **Operating system**: Mac OS


### What is happening?

In a discussion with @rupeshknn, we found a bug when passing the kwarg `qargs` to `Statevector.probabilities_dict`, which seems to occur when there are subsystems with dimension > 2. I haven't tested extensively, but it seems like things are working when all subsystems have dim = 2, so there could be some baked-in assumptions of all subsystems having dimension 2.

### How can we reproduce the issue?

Create a `Statevector`:
```
state = Statevector(np.sqrt(np.array([1., 1., 0., 0., 0., 1.])/3), dims=[3, 2])
```
Under the standard tensor-product convention (implemented in `np.kron`), and with outcome strings being in _reverse order_ relative to the tensor product convention (and relative to the indexing of `dims`), this is a uniform superposition over the outcome strings: `00`, `01`, and `12`.

Calling `state.probabilities_dict()`, or similarly, `state.probabilities_dict(qargs=[0, 1])` (i.e. using `qargs` to say we want to include all subsystems), we get the correct value under the described expectations of the above paragraph:
```
{'00': 0.3333333333333333, '01': 0.3333333333333333, '12': 0.3333333333333333}
```

If we call `state.probabilities_dict(qargs=[0])`, we are requesting to get the probabilities of the subsystem indexed with `0` (the 3 dimensional one), so we expect to see: 
```
{'0': 0.3333333333333333, '1': 0.3333333333333333, '2': 0.3333333333333333}
```
however the output is:
```
{'0': 0.3333333333333333, '1': 0.6666666666666666}
```

Similarly, for `state.probabilities_dict(qargs=[1])`, we expect to get:
```
{'0': 0.6666666666666666, '1': 0.3333333333333333}
```
but instead this actually outputs:
```
{'0': 0.3333333333333333}
```
which isn't even a probability distribution.

Another error case is calling `state.probabilities_dict(qargs=[1, 0])` (i.e., requesting the probability distribution over all subsystems but permuting the results). For this we would expect:
```
{'00': 0.3333333333333333, '10': 0.3333333333333333, '21': 0.3333333333333333}
```
however we get:
```
{'00': 0.3333333333333333, '11': 0.3333333333333333, '21': 0.3333333333333333}
```
which is almost correct, however somehow the middle outcome is now interpreted as `11` rather than `10`.

### What should happen?

The correct outputs are included side by side with the errors.

### Any suggestions?

This will likely boil down to figuring out where the errors are occurring in the array manipulation and numpy calls inside `Statevector.probabilities_dict`. As mentioned, I haven't been able to find any erroneous outputs if all subsystems have dimension `2` (even with up to 3 subsystems), so it very well could be linked to the computations implicitly assuming this.


Discussion:
An update: the guess that it may implicitly assume dimension 2 is now being updated to the guess that it is implicitly assuming all subsystem are of equal dimension.

If we pad the above example with `0.`s to make it an example with both subsystems having dimension 3, the correct results are obtained. I.e., for:
```
state = Statevector(
    np.sqrt(np.array([1., 1., 0., 0., 0., 1., 0., 0., 0.])/3), 
    dims=[3, 3]
)
```

Calling
```
state.probabilities_dict(qargs=[0])
```
correctly returns
```
{'0': 0.3333333333333333, '1': 0.3333333333333333, '2': 0.3333333333333333}
```

Calling
```
state.probabilities_dict(qargs=[1])
```
correctly returns
```
{'0': 0.6666666666666666, '1': 0.3333333333333333}
```

and calling
```
state.probabilities_dict(qargs=[1, 0])
```
correctly returns
```
{'00': 0.3333333333333333, '10': 0.3333333333333333, '21': 0.3333333333333333}
```
As pointed out by @chriseclectic , this could be related to #8899 
I think this bug is fixed by replacing https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/quantum_info/states/quantum_state.py#L457 with
```python
probs_tens = np.reshape(probs, list(reversed(dims)))
``` 

Resolving patch:
diff --git a/qiskit/quantum_info/states/quantum_state.py b/qiskit/quantum_info/states/quantum_state.py
--- a/qiskit/quantum_info/states/quantum_state.py
+++ b/qiskit/quantum_info/states/quantum_state.py
@@ -454,7 +454,7 @@ def _subsystem_probabilities(probs, dims, qargs=None):
         if qargs is None:
             return probs
         # Convert qargs to tensor axes
-        probs_tens = np.reshape(probs, dims)
+        probs_tens = np.reshape(probs, list(reversed(dims)))
         ndim = probs_tens.ndim
         qargs_axes = [ndim - 1 - i for i in reversed(qargs)]
         # Get sum axis for marginalized subsystems


Test patch:
diff --git a/test/python/quantum_info/states/test_densitymatrix.py b/test/python/quantum_info/states/test_densitymatrix.py
--- a/test/python/quantum_info/states/test_densitymatrix.py
+++ b/test/python/quantum_info/states/test_densitymatrix.py
@@ -678,6 +678,67 @@ def test_sample_counts_w(self):
                 counts = state.sample_counts(shots, qargs=qargs)
                 self.assertDictAlmostEqual(counts, target, threshold)
 
+    def test_probabilities_dict_unequal_dims(self):
+        """Test probabilities_dict for a state with unequal subsystem dimensions."""
+
+        vec = np.zeros(60, dtype=float)
+        vec[15:20] = np.ones(5)
+        vec[40:46] = np.ones(6)
+        state = DensityMatrix(vec / np.sqrt(11.0), dims=[3, 4, 5])
+
+        p = 1.0 / 11.0
+
+        self.assertDictEqual(
+            state.probabilities_dict(),
+            {
+                s: p
+                for s in [
+                    "110",
+                    "111",
+                    "112",
+                    "120",
+                    "121",
+                    "311",
+                    "312",
+                    "320",
+                    "321",
+                    "322",
+                    "330",
+                ]
+            },
+        )
+
+        # differences due to rounding
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0]), {"0": 4 * p, "1": 4 * p, "2": 3 * p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[1]), {"1": 5 * p, "2": 5 * p, "3": p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[2]), {"1": 5 * p, "3": 6 * p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0, 1]),
+            {"10": p, "11": 2 * p, "12": 2 * p, "20": 2 * p, "21": 2 * p, "22": p, "30": p},
+            delta=1e-10,
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[1, 0]),
+            {"01": p, "11": 2 * p, "21": 2 * p, "02": 2 * p, "12": 2 * p, "22": p, "03": p},
+            delta=1e-10,
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0, 2]),
+            {"10": 2 * p, "11": 2 * p, "12": p, "31": 2 * p, "32": 2 * p, "30": 2 * p},
+            delta=1e-10,
+        )
+
     def test_sample_counts_qutrit(self):
         """Test sample_counts method for qutrit state"""
         p = 0.3
diff --git a/test/python/quantum_info/states/test_statevector.py b/test/python/quantum_info/states/test_statevector.py
--- a/test/python/quantum_info/states/test_statevector.py
+++ b/test/python/quantum_info/states/test_statevector.py
@@ -710,6 +710,67 @@ def test_sample_counts_w(self):
                 counts = state.sample_counts(shots, qargs=qargs)
                 self.assertDictAlmostEqual(counts, target, threshold)
 
+    def test_probabilities_dict_unequal_dims(self):
+        """Test probabilities_dict for a state with unequal subsystem dimensions."""
+
+        vec = np.zeros(60, dtype=float)
+        vec[15:20] = np.ones(5)
+        vec[40:46] = np.ones(6)
+        state = Statevector(vec / np.sqrt(11.0), dims=[3, 4, 5])
+
+        p = 1.0 / 11.0
+
+        self.assertDictEqual(
+            state.probabilities_dict(),
+            {
+                s: p
+                for s in [
+                    "110",
+                    "111",
+                    "112",
+                    "120",
+                    "121",
+                    "311",
+                    "312",
+                    "320",
+                    "321",
+                    "322",
+                    "330",
+                ]
+            },
+        )
+
+        # differences due to rounding
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0]), {"0": 4 * p, "1": 4 * p, "2": 3 * p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[1]), {"1": 5 * p, "2": 5 * p, "3": p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[2]), {"1": 5 * p, "3": 6 * p}, delta=1e-10
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0, 1]),
+            {"10": p, "11": 2 * p, "12": 2 * p, "20": 2 * p, "21": 2 * p, "22": p, "30": p},
+            delta=1e-10,
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[1, 0]),
+            {"01": p, "11": 2 * p, "21": 2 * p, "02": 2 * p, "12": 2 * p, "22": p, "03": p},
+            delta=1e-10,
+        )
+
+        self.assertDictAlmostEqual(
+            state.probabilities_dict(qargs=[0, 2]),
+            {"10": 2 * p, "11": 2 * p, "12": p, "31": 2 * p, "32": 2 * p, "30": 2 * p},
+            delta=1e-10,
+        )
+
     def test_sample_counts_qutrit(self):
         """Test sample_counts method for qutrit state"""
         p = 0.3