qml.sample¶
- sample(op=None, wires=None, dtype=None)[source]¶
Sample from the supplied observable, with the number of shots determined from QNode, returning raw samples. If no observable is provided, then basis state samples are returned directly from the device.
Note that the output shape of this measurement process depends on the shots specified on the device.
- Parameters:
op (Operator or MeasurementValue) – a quantum observable object. To get samples for mid-circuit measurements,
op
should be aMeasurementValue
.wires (Sequence[int] or int or None) – the wires we wish to sample from; ONLY set wires if op is
None
.dtype – The dtype of the samples returned by this measurement process.
- Returns:
Measurement process instance
- Return type:
- Raises:
ValueError – Cannot set wires if an observable is provided
Warning
In v0.42, a breaking change removed the squeezing of singleton dimensions, eliminating the need for specialized, error-prone handling for finite-shot results. For the QNode:
>>> @qml.qnode(qml.device('default.qubit')) ... def circuit(wires): ... return qml.sample(wires=wires)
We previously squeezed out singleton dimensions like:
>>> qml.set_shots(circuit, 1)(wires=1) array(0) >>> qml.set_shots(circuit, 2)(0) array([0, 0]) >>> qml.set_shots(circuit, 1)((0,1)) array([0, 0])
With v0.42 and newer, the above circuit will always return an array of shape
(shots, num_wires)
.>>> qml.set_shots(circuit, 1)(wires=1) array([[0]]) >>> qml.set_shots(circuit, 2)(0) array([[0], [0]]) >>> qml.set_shots(circuit, 1)((0,1)) array([[0, 0]])
Previous behavior can be recovered by applying
qml.math.squeeze(result)
to the array.The samples are drawn from the eigenvalues \(\{\lambda_i\}\) of the observable. The probability of drawing eigenvalue \(\lambda_i\) is given by \(p(\lambda_i) = |\langle \xi_i | \psi \rangle|^2\), where \(| \xi_i \rangle\) is the corresponding basis state from the observable’s eigenbasis.
Note
QNodes that return samples cannot, in general, be differentiated, since the derivative with respect to a sample — a stochastic process — is ill-defined. An alternative approach would be to use single-shot expectation values. For example, instead of this:
from functools import partial dev = qml.device("default.qubit") @partial(qml.set_shots, shots=10) @qml.qnode(dev, diff_method="parameter-shift") def circuit(angle): qml.RX(angle, wires=0) return qml.sample(qml.PauliX(0)) angle = qml.numpy.array(0.1) res = qml.jacobian(circuit)(angle)
Consider using
expval()
and a sequence of single shots, like this:from functools import partial dev = qml.device("default.qubit") @partial(qml.set_shots, shots=[(1, 10)]) @qml.qnode(dev, diff_method="parameter-shift") def circuit(angle): qml.RX(angle, wires=0) return qml.expval(qml.PauliX(0)) def cost(angle): return qml.math.hstack(circuit(angle)) angle = qml.numpy.array(0.1) res = qml.jacobian(cost)(angle)
Example
from functools import partial dev = qml.device("default.qubit", wires=2) @partial(qml.set_shots, shots=4) @qml.qnode(dev) def circuit(x): qml.RX(x, wires=0) qml.Hadamard(wires=1) qml.CNOT(wires=[0, 1]) return qml.sample(qml.Y(0))
Executing this QNode:
>>> circuit(0.5) array([ 1., 1., 1., -1.])
If no observable is provided, then the raw basis state samples obtained from the device are returned (e.g., for a qubit device, samples from the computational basis are returned). In this case,
wires
can be specified so that sample results only include measurement results of the qubits of interest.from functools import partial dev = qml.device("default.qubit", wires=2) @partial(qml.set_shots, shots=4) @qml.qnode(dev) def circuit(x): qml.RX(x, wires=0) qml.Hadamard(wires=1) qml.CNOT(wires=[0, 1]) return qml.sample()
Executing this QNode:
>>> circuit(0.5) array([[0, 1], [0, 0], [1, 1], [0, 0]])
Setting the precision of the samples
The
dtype
argument can be used to set the type and precision of the samples returned by this measurement process when theop
argument does not contain mid-circuit measurements. Otherwise, thedtype
argument is ignored.By default, the samples will be returned as floating point numbers if an observable is provided, and as integers if no observable is provided. The
dtype
argument can be used to specify further details, and set the precision to any valid interface-like dtype, e.g.'float32'
,'int8'
,'uint16'
, etc.We show two examples below using the JAX and PyTorch interfaces. This argument is compatible with all interfaces currently supported by PennyLane.
Example:
@qml.set_shots(1000000) @qml.qnode(qml.device("default.qubit", wires=1), interface="jax") def circuit(): qml.Hadamard(0) return qml.sample(dtype="int8")
Executing this QNode, we get:
>>> samples = circuit() >>> samples.dtype dtype('int8') >>> type(samples) jaxlib._jax.ArrayImpl
If an observable is provided, the samples will be floating point numbers:
@qml.set_shots(1000000) @qml.qnode(qml.device("default.qubit", wires=1), interface="torch") def circuit(): qml.Hadamard(0) return qml.sample(qml.Z(0), dtype="float32")
Executing this QNode, we get:
>>> samples = circuit() >>> samples.dtype torch.float32 >>> type(samples) torch.Tensor