diff --git a/doc/introduction/measurements.rst b/doc/introduction/measurements.rst
index 586810e1a80..0a84cc4c326 100644
--- a/doc/introduction/measurements.rst
+++ b/doc/introduction/measurements.rst
@@ -102,7 +102,6 @@ the measurement results always coincide, and the lists are therefore equal:
>>> np.all(result[0] == result[1])
True
-
Tensor observables
------------------
@@ -127,6 +126,66 @@ accept observables as arguments,
including :func:`~.pennylane.expval`, :func:`~.pennylane.var`,
and :func:`~.pennylane.sample`.
+Counts
+------
+
+To avoid dealing with long arrays for the larger numbers of shots, one can pass an argument counts=True
+to :func:`~pennylane.sample`. In this case, the result will be a dictionary containing the number of occurrences for each
+unique sample. The previous example will be modified as follows:
+
+.. code-block:: python
+
+ dev = qml.device("default.qubit", wires=2, shots=1000)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.CNOT(wires=[0, 1])
+ # passing the counts flag
+ return qml.sample(qml.PauliZ(0), counts=True), qml.sample(qml.PauliZ(1), counts=True)
+
+After executing the circuit, we can directly see how many times each measurement outcome occurred:
+
+>>> result = circuit()
+>>> print(result)
+[{-1: 526, 1: 474} {-1: 526, 1: 474}]
+
+Similarly, if the observable is not provided, the count of each computational basis state is returned.
+
+.. code-block:: python
+
+ dev = qml.device("default.qubit", wires=2, shots=1000)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.CNOT(wires=[0, 1])
+ # passing the counts flag
+ return qml.sample(counts=True)
+
+And the result is:
+
+>>> result = circuit()
+>>> print(result)
+{'00': 495, '11': 505}
+
+If counts are obtained along with a measurement function other than :func:`~.pennylane.sample`,
+a tensor of tensors is returned to provide differentiability for the outputs of QNodes.
+
+.. code-block:: python
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.CNOT(wires=[0,1])
+ qml.PauliX(wires=2)
+ return qml.expval(qml.PauliZ(0)),qml.expval(qml.PauliZ(1)), qml.sample(counts=True)
+
+>>> result = circuit()
+>>> print(result)
+[tensor(0.026, requires_grad=True) tensor(0.026, requires_grad=True)
+ tensor({'001': 513, '111': 487}, dtype=object, requires_grad=True)]
+
Probability
-----------
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 565efc36dbd..8c2adeebab1 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -47,6 +47,43 @@
[(#2699)](https://github.com/PennyLaneAI/pennylane/pull/2699)
Improvements
+
+* Samples can be grouped into counts by passing the `counts=True` flag to `qml.sample`.
+ [(#2686)](https://github.com/PennyLaneAI/pennylane/pull/2686)
+
+ Note that the change included creating a new `Counts` measurement type in `measurements.py`.
+
+ `counts=True` can be set when obtaining raw samples in the computational basis:
+
+ ```pycon
+ >>> dev = qml.device("default.qubit", wires=2, shots=1000)
+ >>>
+ >>> @qml.qnode(dev)
+ >>> def circuit():
+ ... qml.Hadamard(wires=0)
+ ... qml.CNOT(wires=[0, 1])
+ ... # passing the counts flag
+ ... return qml.sample(counts=True)
+ >>> result = circuit()
+ >>> print(result)
+ {'00': 495, '11': 505}
+ ```
+
+ Counts can also be obtained when sampling the eigenstates of an observable:
+
+ ```pycon
+ >>> dev = qml.device("default.qubit", wires=2, shots=1000)
+ >>>
+ >>> @qml.qnode(dev)
+ >>> def circuit():
+ ... qml.Hadamard(wires=0)
+ ... qml.CNOT(wires=[0, 1])
+ ... return qml.sample(qml.PauliZ(0), counts=True), qml.sample(qml.PauliZ(1), counts=True)
+ >>> result = circuit()
+ >>> print(result)
+ [tensor({-1: 526, 1: 474}, dtype=object, requires_grad=True)
+ tensor({-1: 526, 1: 474}, dtype=object, requires_grad=True)]
+ ```
* The `qml.state` and `qml.density_matrix` measurements now support custom wire
labels.
@@ -105,5 +142,6 @@
This release contains contributions from (in alphabetical order):
-David Ittah, Edward Jiang, Ankit Khandelwal, Christina Lee, Ixchel Meza Chavez, Mudit Pandey,
+
+David Ittah, Edward Jiang, Ankit Khandelwal, Christina Lee, Ixchel Meza Chavez, Bogdan Reznychenko, Mudit Pandey,
Antal Száva, Moritz Willmann
diff --git a/pennylane/_qubit_device.py b/pennylane/_qubit_device.py
index a7808b80585..8ba5bccc69d 100644
--- a/pennylane/_qubit_device.py
+++ b/pennylane/_qubit_device.py
@@ -29,6 +29,7 @@
from pennylane.operation import operation_derivative
from pennylane.measurements import (
Sample,
+ Counts,
Variance,
Expectation,
Probability,
@@ -36,6 +37,7 @@
VnEntropy,
MutualInfo,
)
+
from pennylane import Device
from pennylane.math import sum as qmlsum
from pennylane.math import multiply as qmlmul
@@ -276,10 +278,13 @@ def execute(self, circuit, **kwargs):
if qml.math._multi_dispatch(r) == "jax": # pylint: disable=protected-access
r = r[0]
- else:
+ elif not isinstance(r[0], dict):
+ # Measurement types except for Counts
r = qml.math.squeeze(r)
-
- if shot_tuple.copies > 1:
+ if isinstance(r, (np.ndarray, list)) and r.shape and isinstance(r[0], dict):
+ # This happens when measurement type is Counts
+ results.append(r)
+ elif shot_tuple.copies > 1:
results.extend(r.T)
else:
results.append(r.T)
@@ -301,7 +306,7 @@ def execute(self, circuit, **kwargs):
if circuit.measurements[0].return_type is qml.measurements.State:
# State: assumed to only be allowed if it's the only measurement
results = self._asarray(results, dtype=self.C_DTYPE)
- else:
+ elif circuit.measurements[0].return_type is not qml.measurements.Counts:
# Measurements with expval, var or probs
results = self._asarray(results, dtype=self.R_DTYPE)
@@ -311,7 +316,8 @@ def execute(self, circuit, **kwargs):
):
# Measurements with expval or var
results = self._asarray(results, dtype=self.R_DTYPE)
- else:
+ elif any(ret is not qml.measurements.Counts for ret in ret_types):
+ # all the other cases except all counts
results = self._asarray(results)
elif circuit.all_sampled and not self._has_partitioned_shots():
@@ -475,7 +481,14 @@ def statistics(self, observables, shot_range=None, bin_size=None):
results.append(self.var(obs, shot_range=shot_range, bin_size=bin_size))
elif obs.return_type is Sample:
- results.append(self.sample(obs, shot_range=shot_range, bin_size=bin_size))
+ results.append(
+ self.sample(obs, shot_range=shot_range, bin_size=bin_size, counts=False)
+ )
+
+ elif obs.return_type is Counts:
+ results.append(
+ self.sample(obs, shot_range=shot_range, bin_size=bin_size, counts=True)
+ )
elif obs.return_type is Probability:
results.append(
@@ -958,20 +971,39 @@ def var(self, observable, shot_range=None, bin_size=None):
samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size)
return np.squeeze(np.var(samples, axis=0))
- def sample(self, observable, shot_range=None, bin_size=None):
+ def sample(self, observable, shot_range=None, bin_size=None, counts=False):
+ def _samples_to_counts(samples, no_observable_provided):
+ """Group the obtained samples into a dictionary.
+
+ **Example**
+
+ >>> samples
+ tensor([[0, 0, 1],
+ [0, 0, 1],
+ [1, 1, 1]], requires_grad=True)
+ >>> self._samples_to_counts(samples)
+ {'111':1, '001':2}
+ """
+ if no_observable_provided:
+ # If we describe a state vector, we need to convert its list representation
+ # into string (it's hashable and good-looking).
+ # Before converting to str, we need to extract elements from arrays
+ # to satisfy the case of jax interface, as jax arrays do not support str.
+ samples = ["".join([str(s.item()) for s in sample]) for sample in samples]
+ states, counts = np.unique(samples, return_counts=True)
+ return dict(zip(states, counts))
# translate to wire labels used by device
device_wires = self.map_wires(observable.wires)
name = observable.name
sample_slice = Ellipsis if shot_range is None else slice(*shot_range)
+ no_observable_provided = isinstance(observable, MeasurementProcess)
if isinstance(name, str) and name in {"PauliX", "PauliY", "PauliZ", "Hadamard"}:
# Process samples for observables with eigenvalues {1, -1}
samples = 1 - 2 * self._samples[sample_slice, device_wires[0]]
- elif isinstance(
- observable, MeasurementProcess
- ): # if no observable was provided then return the raw samples
+ elif no_observable_provided: # if no observable was provided then return the raw samples
if (
len(observable.wires) != 0
): # if wires are provided, then we only return samples from those wires
@@ -998,9 +1030,20 @@ def sample(self, observable, shot_range=None, bin_size=None):
) from e
if bin_size is None:
+ if counts:
+ return _samples_to_counts(samples, no_observable_provided)
return samples
-
- return samples.reshape((bin_size, -1))
+ if counts:
+ shape = (-1, bin_size, 3) if no_observable_provided else (-1, bin_size)
+ return [
+ _samples_to_counts(bin_sample, no_observable_provided)
+ for bin_sample in samples.reshape(shape)
+ ]
+ return (
+ samples.reshape((3, bin_size, -1))
+ if no_observable_provided
+ else samples.reshape((bin_size, -1))
+ )
def adjoint_jacobian(self, tape, starting_state=None, use_device_state=False):
"""Implements the adjoint method outlined in
diff --git a/pennylane/interfaces/autograd.py b/pennylane/interfaces/autograd.py
index 97d32291834..a404b182c78 100644
--- a/pennylane/interfaces/autograd.py
+++ b/pennylane/interfaces/autograd.py
@@ -111,10 +111,16 @@ def _execute(
for i, r in enumerate(res):
- if isinstance(res[i], np.ndarray):
+ if isinstance(r, np.ndarray):
# For backwards compatibility, we flatten ragged tape outputs
# when there is no sampling
- r = np.hstack(res[i]) if res[i].dtype == np.dtype("object") else res[i]
+ try:
+ if isinstance(r[0][0], dict):
+ # This happens when measurement type is Counts and shot vector is passed
+ continue
+ except (IndexError, KeyError):
+ pass
+ r = np.hstack(r) if r.dtype == np.dtype("object") else r
res[i] = np.tensor(r)
elif isinstance(res[i], tuple):
diff --git a/pennylane/measurements.py b/pennylane/measurements.py
index 490f04ae293..7c329927d56 100644
--- a/pennylane/measurements.py
+++ b/pennylane/measurements.py
@@ -38,6 +38,7 @@ class ObservableReturnTypes(Enum):
"""Enumeration class to represent the return types of an observable."""
Sample = "sample"
+ Counts = "counts"
Variance = "var"
Expectation = "expval"
Probability = "probs"
@@ -54,6 +55,10 @@ def __repr__(self):
Sample = ObservableReturnTypes.Sample
"""Enum: An enumeration which represents sampling an observable."""
+Counts = ObservableReturnTypes.Counts
+"""Enum: An enumeration which represents returning the number of times
+ each sample was obtained."""
+
Variance = ObservableReturnTypes.Variance
"""Enum: An enumeration which represents returning the variance of
an observable on specified wires."""
@@ -578,9 +583,10 @@ def circuit(x):
return MeasurementProcess(Variance, obs=op)
-def sample(op=None, wires=None):
+def sample(op=None, wires=None, counts=False):
r"""Sample from the supplied observable, with the number of shots
- determined from the ``dev.shots`` attribute of the corresponding device.
+ determined from the ``dev.shots`` attribute of the corresponding device,
+ returning raw samples (counts=False) or the number of counts for each sample (counts=True).
If no observable is provided then basis state samples are returned directly
from the device.
@@ -590,6 +596,7 @@ def sample(op=None, wires=None):
Args:
op (Observable or None): a quantum observable object
wires (Sequence[int] or int or None): the wires we wish to sample from, ONLY set wires if op is None
+ counts (bool): return the result as number of counts for each sample
Raises:
QuantumFunctionError: `op` is not an instance of :class:`~.Observable`
@@ -642,6 +649,27 @@ def circuit(x):
[1, 1],
[0, 0]])
+ If specified counts=True, the function returns number of counts for each sample,
+ both for observables eigenvalues or the system eigenstates.
+
+ .. code-block:: python3
+
+ dev = qml.device('default.qubit', wires=3, shots=10)
+
+ @qml.qnode(dev)
+ def my_circ():
+ qml.Hadamard(wires=0)
+ qml.CNOT(wires=[0,1])
+ qml.PauliX(wires=2)
+ return qml.sample(qml.PauliZ(0), counts = True), qml.sample(counts=True)
+
+ Executing this QNode:
+
+ >>> my_circ()
+ tensor([tensor({-1: 5, 1: 5}, dtype=object, requires_grad=True),
+ tensor({'001': 5, '111': 5}, dtype=object, requires_grad=True)],
+ dtype=object, requires_grad=True)
+
.. note::
QNodes that return samples cannot, in general, be differentiated, since the derivative
@@ -655,16 +683,17 @@ def circuit(x):
f"{op.name} is not an observable: cannot be used with sample"
)
+ sample_or_counts = Counts if counts else Sample
+
if wires is not None:
if op is not None:
raise ValueError(
"Cannot specify the wires to sample if an observable is "
"provided. The wires to sample will be determined directly from the observable."
)
+ return MeasurementProcess(sample_or_counts, obs=op, wires=qml.wires.Wires(wires))
- return MeasurementProcess(Sample, obs=op, wires=qml.wires.Wires(wires))
-
- return MeasurementProcess(Sample, obs=op)
+ return MeasurementProcess(sample_or_counts, obs=op)
def probs(wires=None, op=None):
diff --git a/pennylane/qnode.py b/pennylane/qnode.py
index 1089a1c7190..c44fdfc6d29 100644
--- a/pennylane/qnode.py
+++ b/pennylane/qnode.py
@@ -650,6 +650,9 @@ def __call__(self, *args, **kwargs):
self.tape.is_sampled and self.device._has_partitioned_shots()
):
return res
+ if self._qfunc_output.return_type is qml.measurements.Counts:
+ # return a dictionary with counts not as a single-element array
+ return res[0]
return qml.math.squeeze(res)
diff --git a/tests/test_measurements.py b/tests/test_measurements.py
index f4b13754158..ad5f923d62f 100644
--- a/tests/test_measurements.py
+++ b/tests/test_measurements.py
@@ -31,6 +31,7 @@
density_matrix,
Expectation,
Sample,
+ Counts,
State,
Variance,
Probability,
@@ -47,6 +48,7 @@
[
(Expectation, "expval"),
(Sample, "sample"),
+ (Counts, "counts"),
(Variance, "var"),
(Probability, "probs"),
(State, "state"),
@@ -513,15 +515,334 @@ def test_shape_shot_vector(self, obs):
assert res.shape(dev) == expected
def test_shape_shot_vector_no_obs(self):
- """Test that the shape is correct with the shot vector too."""
- shot_vector = (1, 2, 3)
- dev = qml.device("default.qubit", wires=3, shots=shot_vector)
- res = qml.sample()
- with pytest.raises(
- qml.measurements.MeasurementShapeError,
- match="Getting the output shape of a measurement returning samples along with a device with a shot vector is not supported.",
- ):
- res.shape(dev)
+ """Test that the shape is correct with the shot vector and no observable too."""
+ shot_vec = (2, 2)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.PauliZ(0)
+ return qml.sample(qml.PauliZ(0), counts=False)
+
+ binned_samples = circuit()
+
+ assert isinstance(binned_samples, tuple)
+ assert len(binned_samples) == len(shot_vec)
+ assert binned_samples[0].shape == (shot_vec[0],)
+
+
+class TestCounts:
+ """Tests for the counts function"""
+
+ def test_counts_dimension(self, tol):
+ """Test that the sample function outputs counts of the right size"""
+ n_sample = 10
+
+ dev = qml.device("default.qubit", wires=2, shots=n_sample)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.RX(0.54, wires=0)
+ return qml.sample(qml.PauliZ(0), counts=True), qml.sample(qml.PauliX(1), counts=True)
+
+ sample = circuit()
+
+ assert np.array_equal(sample.shape, (2,))
+ assert np.all([sum(s.values()) == n_sample for s in sample])
+
+ def test_counts_combination(self, tol):
+ """Test the output of combining expval, var and counts"""
+ n_sample = 10
+
+ dev = qml.device("default.qubit", wires=3, shots=n_sample)
+
+ @qml.qnode(dev, diff_method="parameter-shift")
+ def circuit():
+ qml.RX(0.54, wires=0)
+
+ return (
+ qml.sample(qml.PauliZ(0), counts=True),
+ qml.expval(qml.PauliX(1)),
+ qml.var(qml.PauliY(2)),
+ )
+
+ result = circuit()
+
+ assert len(result) == 3
+ assert sum(result[0].unwrap().values()) == n_sample
+ assert isinstance(result[1], np.ndarray)
+ assert isinstance(result[2], np.ndarray)
+
+ def test_single_wire_counts(self, tol):
+ """Test the return type and shape of sampling counts from a single wire"""
+ n_sample = 10
+
+ dev = qml.device("default.qubit", wires=1, shots=n_sample)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.RX(0.54, wires=0)
+
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ result = circuit()
+
+ assert isinstance(result, dict)
+ assert sum(result.values()) == n_sample
+
+ def test_multi_wire_counts_regular_shape(self, tol):
+ """Test the return type and shape of sampling multiple wires
+ where a rectangular array is expected"""
+ n_sample = 10
+
+ dev = qml.device("default.qubit", wires=3, shots=n_sample)
+
+ @qml.qnode(dev)
+ def circuit():
+ return (
+ qml.sample(qml.PauliZ(0), counts=True),
+ qml.sample(qml.PauliZ(1), counts=True),
+ qml.sample(qml.PauliZ(2), counts=True),
+ )
+
+ result = circuit()
+
+ # If all the dimensions are equal the result will end up to be a proper rectangular array
+ assert isinstance(result, np.ndarray)
+ assert result.shape[0] == 3
+ assert all(sum(r.values()) == n_sample for r in result)
+ assert all(all(v.dtype == np.dtype("int") for v in r.values()) for r in result)
+
+ def test_observable_return_type_is_counts(self):
+ """Test that the return type of the observable is :attr:`ObservableReturnTypes.Counts`"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=1, shots=n_shots)
+
+ @qml.qnode(dev)
+ def circuit():
+ res = qml.sample(qml.PauliZ(0), counts=True)
+ assert res.return_type is Counts
+ return res
+
+ circuit()
+
+ def test_providing_no_observable_and_no_wires_counts(self):
+ """Test that we can provide no observable and no wires to sample function"""
+ dev = qml.device("default.qubit", wires=2, shots=1000)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ res = qml.sample(counts=True)
+ assert res.obs is None
+ assert res.wires == qml.wires.Wires([])
+ return res
+
+ circuit()
+
+ def test_providing_no_observable_and_wires_counts(self):
+ """Test that we can provide no observable but specify wires to the sample function"""
+ wires = [0, 2]
+ wires_obj = qml.wires.Wires(wires)
+ dev = qml.device("default.qubit", wires=3, shots=1000)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ res = qml.sample(wires=wires, counts=True)
+
+ assert res.obs is None
+ assert res.wires == wires_obj
+ return res
+
+ circuit()
+
+ def test_binned_counts_for_operator(self, tol):
+ """Test that the shape is correct with the shot vector."""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.PauliZ(0)
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ binned_samples = circuit()
+
+ assert isinstance(binned_samples, np.ndarray)
+ assert isinstance(binned_samples[0], dict)
+ assert len(binned_samples) == len(shot_vec)
+ assert sum(sum(v for v in bin.values()) for bin in binned_samples) == sum(shot_vec)
+
+ def test_binned_counts_for_state_vector(self, tol):
+ """Test that the shape is correct with the shot vector and no observable too."""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev)
+ def circuit():
+ qml.Hadamard(wires=0)
+ qml.PauliZ(0)
+ return qml.sample(None, counts=True)
+
+ binned_samples = circuit()
+
+ assert isinstance(binned_samples, np.ndarray)
+ assert isinstance(binned_samples[0], dict)
+ assert len(binned_samples) == len(shot_vec)
+ assert sum(sum(v for v in bin.values()) for bin in binned_samples) == sum(shot_vec)
+
+ def test_counts_jax(self, tol):
+ """Check jax interface with computational basis state counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="jax")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res == {"000": n_shots}
+
+ def test_counts_operator_jax(self, tol):
+ """Check jax interface with observable measurement counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="jax")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res == {1: n_shots}
+
+ def test_counts_tf(self, tol):
+ """Check TensorFlow interface with computational basis state counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="tf")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res == {"000": n_shots}
+
+ def test_counts_operator_tf(self, tol):
+ """Check TensorFlow interface with observable measurement counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="tf")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res == {1: n_shots}
+
+ def test_counts_torch(self, tol):
+ """Check pyTorch interface with computational basis state counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="torch")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res == {"000": n_shots}
+
+ def test_counts_operator_torch(self, tol):
+ """Check pyTorch interface with observable measurement counts"""
+ n_shots = 10
+ dev = qml.device("default.qubit", wires=3, shots=n_shots)
+
+ @qml.qnode(dev, inteface="torch")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res == {1: n_shots}
+
+ def test_counts_jax_binned(self, tol):
+ """Check jax interface with computational basis state counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="jax")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res[0] == {"000": shot_vec[0]}
+ assert res[1] == {"000": shot_vec[1]}
+
+ def test_counts_operator_jax_binned(self, tol):
+ """Check jax interface with observable measurement counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="jax")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res[0] == {1: shot_vec[0]}
+ assert res[1] == {1: shot_vec[1]}
+
+ def test_counts_tf_binned(self, tol):
+ """Check TensorFlow interface with computational basis state counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="tf")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res[0] == {"000": shot_vec[0]}
+ assert res[1] == {"000": shot_vec[1]}
+
+ def test_counts_operator_tf_binned(self, tol):
+ """Check TensorFlow interface with observable measurement counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="tf")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res[0] == {1: shot_vec[0]}
+ assert res[1] == {1: shot_vec[1]}
+
+ def test_counts_torch_binned(self, tol):
+ """Check pyTorch interface with computational basis state counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="torch")
+ def circuit():
+ return qml.sample(counts=True)
+
+ res = circuit()
+ assert res[0] == {"000": shot_vec[0]}
+ assert res[1] == {"000": shot_vec[1]}
+
+ def test_counts_operator_torch_binned(self, tol):
+ """Check pyTorch interface with observable measurement counts"""
+ shot_vec = (10, 10)
+ dev = qml.device("default.qubit", wires=3, shots=shot_vec)
+
+ @qml.qnode(dev, inteface="torch")
+ def circuit():
+ return qml.sample(qml.PauliZ(0), counts=True)
+
+ res = circuit()
+ assert res[0] == {1: shot_vec[0]}
+ assert res[1] == {1: shot_vec[1]}
class TestMeasure: