Repository: PennyLaneAI/pennylane

Issue:
Please expose device._shot_vector via public property
This is a features request: Please expose the shot vector via some public and documented property of the device. Thank you!

This is inspired by me needing to predict the output shape of certain QNodes and in case of a non trivial shot vector and all observables being owned by an `expval` the shape is 
```
(sum([shot_tuple.copies for shot_tuple in self.device._shot_vector]), len(self.measurements))
```
(where self is a tape).

Discussion:
github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [.github/CHANGELOG.md](/PennyLaneAI/pennylane/blob/master/.github/CHANGELOG.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=h1) Report
> Merging [#1168](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=desc) (17f034d) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/94e809840cda97dbf7464469b58859738df505a9?el=desc) (94e8098) will **decrease** coverage by `0.96%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/graphs/tree.svg?width=650&height=150&src=pr&token=9S3YzlUgGk)](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #1168      +/-   ##
==========================================
- Coverage   99.08%   98.11%   -0.97%     
==========================================
  Files         141      144       +3     
  Lines       10274    10778     +504     
==========================================
+ Hits        10180    10575     +395     
- Misses         94      203     +109     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pennylane/\_device.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL19kZXZpY2UucHk=) | `96.61% <100.00%> (-2.95%)` | :arrow_down: |
| [pennylane/tape/operation\_recorder.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL3RhcGUvb3BlcmF0aW9uX3JlY29yZGVyLnB5) | `64.51% <0.00%> (-35.49%)` | :arrow_down: |
| [pennylane/measure.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL21lYXN1cmUucHk=) | `91.76% <0.00%> (-8.24%)` | :arrow_down: |
| [pennylane/circuit\_drawer/grid.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL2NpcmN1aXRfZHJhd2VyL2dyaWQucHk=) | `88.70% <0.00%> (-7.72%)` | :arrow_down: |
| [pennylane/grouping/optimize\_measurements.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL2dyb3VwaW5nL29wdGltaXplX21lYXN1cmVtZW50cy5weQ==) | `92.30% <0.00%> (-7.70%)` | :arrow_down: |
| [pennylane/configuration.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL2NvbmZpZ3VyYXRpb24ucHk=) | `93.10% <0.00%> (-6.90%)` | :arrow_down: |
| [pennylane/vqe/vqe.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL3ZxZS92cWUucHk=) | `93.85% <0.00%> (-6.15%)` | :arrow_down: |
| [pennylane/about.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL2Fib3V0LnB5) | `95.45% <0.00%> (-4.55%)` | :arrow_down: |
| [pennylane/operation.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL29wZXJhdGlvbi5weQ==) | `95.82% <0.00%> (-3.95%)` | :arrow_down: |
| [pennylane/math/tensorbox.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree#diff-cGVubnlsYW5lL21hdGgvdGVuc29yYm94LnB5) | `96.02% <0.00%> (-3.28%)` | :arrow_down: |
| ... and [24 more](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=footer). Last update [94e8098...17f034d](https://codecov.io/gh/PennyLaneAI/pennylane/pull/1168?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Thenerdstation: @josh146 I think you fixed your own change request so can we merge this? 

Patch:
diff --git a/pennylane/_device.py b/pennylane/_device.py
index b1697ef14..d07080323 100644
--- a/pennylane/_device.py
+++ b/pennylane/_device.py
@@ -264,6 +264,33 @@ class Device(abc.ABC):
                 "Shots must be a single non-negative integer or a sequence of non-negative integers."
             )
 
+    @property
+    def shot_vector(self):
+        """list[.ShotTuple[int, int]]: Returns the shot vector, a sparse
+        representation of the shot sequence used by the device
+        when evaluating QNodes.
+
+        **Example**
+
+        >>> dev = qml.device("default.qubit", wires=2, shots=[3, 1, 2, 2, 2, 2, 6, 1, 1, 5, 12, 10, 10])
+        >>> dev.shots
+        57
+        >>> dev.shot_vector
+        [ShotTuple(shots=3, copies=1),
+         ShotTuple(shots=1, copies=1),
+         ShotTuple(shots=2, copies=4),
+         ShotTuple(shots=6, copies=1),
+         ShotTuple(shots=1, copies=2),
+         ShotTuple(shots=5, copies=1),
+         ShotTuple(shots=12, copies=1),
+         ShotTuple(shots=10, copies=2)]
+
+        The sparse representation of the shot
+        sequence is returned, where tuples indicate the number of times a shot
+        integer is repeated.
+        """
+        return self._shot_vector
+
     def define_wire_map(self, wires):
         """Create the map from user-provided wire labels to the wire labels used by the device.
 


Test patch:
diff --git a/tests/test_device.py b/tests/test_device.py
index ab0b4c873..79d3ae64c 100644
--- a/tests/test_device.py
+++ b/tests/test_device.py
@@ -164,6 +164,19 @@ def mock_device(monkeypatch):
 
         yield get_device
 
+def test_shot_vector_property():
+    dev = qml.device("default.qubit", wires=1, shots=[1, 3, 3, 4, 4, 4, 3])
+    shot_vector = dev.shot_vector
+    assert len(shot_vector) == 4
+    assert shot_vector[0].shots == 1
+    assert shot_vector[0].copies == 1
+    assert shot_vector[1].shots == 3
+    assert shot_vector[1].copies == 2
+    assert shot_vector[2].shots == 4
+    assert shot_vector[2].copies == 3
+    assert shot_vector[3].shots == 3
+    assert shot_vector[3].copies == 1
+
 
 class TestDeviceSupportedLogic:
     """Test the logic associated with the supported operations and observables"""