qml.measure

measure(wires, reset=False, postselect=None)[source]

Perform a mid-circuit measurement in the computational basis on the supplied qubit.

Computational basis measurements are performed using the 0, 1 convention rather than the ±1 convention. Measurement outcomes can be used to conditionally apply operations, and measurement statistics can be gathered and returned by a quantum function.

If a device doesn’t support mid-circuit measurements natively, then the QNode will apply the defer_measurements() transform.

Example:

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)
def func(x, y):
    qml.RY(x, wires=0)
    qml.CNOT(wires=[0, 1])
    m_0 = qml.measure(1)

    qml.cond(m_0, qml.RY)(y, wires=0)
    return qml.probs(wires=[0])

Executing this QNode:

>>> pars = np.array([0.643, 0.246], requires_grad=True)
>>> func(*pars)
tensor([0.90165331, 0.09834669], requires_grad=True)

Wires can be reused after measurement. Moreover, measured wires can be reset to the \(|0 \rangle\) state by setting reset=True.

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)
def func():
    qml.X(1)
    m_0 = qml.measure(1, reset=True)
    return qml.probs(wires=[1])

Executing this QNode:

>>> func()
tensor([1., 0.], requires_grad=True)

Mid-circuit measurements can be manipulated using the following arithmetic operators: +, -, *, /, ~ (not), & (and), | (or), ==, <=, >=, <, > with other mid-circuit measurements or scalars.

Note

Python not, and, or, do not work since these do not have dunder methods. Instead use ~, &, |.

Mid-circuit measurement results can be processed with the usual measurement functions such as expval(). For QNodes with finite shots, sample() applied to a mid-circuit measurement result will return a binary sequence of samples. See here for more details.

Note

Computational basis measurements are performed using the 0, 1 convention rather than the ±1 convention. So, for example, expval(qml.measure(0)) and expval(qml.Z(0)) will give different answers.

dev = qml.device("default.qubit")

@qml.qnode(dev)
def circuit(x, y):
    qml.RX(x, wires=0)
    qml.RY(y, wires=1)
    m0 = qml.measure(1)
    return (
        qml.sample(m0), qml.expval(m0), qml.var(m0), qml.probs(op=m0), qml.counts(op=m0),
    )
>>> circuit(1.0, 2.0, shots=1000)
(array([0, 1, 1, ..., 1, 1, 1])), 0.702, 0.20919600000000002, array([0.298, 0.702]), {0: 298, 1: 702})
Parameters
  • wires (Wires) – The wire to measure.

  • reset (Optional[bool]) – Whether to reset the wire to the \(|0 \rangle\) state after measurement.

  • postselect (Optional[int]) – Which basis state to postselect after a mid-circuit measurement. None by default. If postselection is requested, only the post-measurement state that is used for postselection will be considered in the remaining circuit.

Returns

measurement process instance

Return type

MidMeasureMP

Raises

QuantumFunctionError – if multiple wires were specified

Postselection discards outcomes that do not meet the criteria provided by the postselect argument. For example, specifying postselect=1 on wire 0 would be equivalent to projecting the state vector onto the \(|1\rangle\) state on wire 0:

dev = qml.device("default.qubit")

@qml.qnode(dev)
def func(x):
    qml.RX(x, wires=0)
    m0 = qml.measure(0, postselect=1)
    qml.cond(m0, qml.X)(wires=1)
    return qml.sample(wires=1)

By postselecting on 1, we only consider the 1 measurement outcome on wire 0. So, the probability of measuring 1 on wire 1 after postselection should also be 1. Executing this QNode with 10 shots:

>>> func(np.pi / 2, shots=10)
array([1, 1, 1, 1, 1, 1, 1])

Note that only 7 samples are returned. This is because samples that do not meet the postselection criteria are thrown away.

If postselection is requested on a state with zero probability of being measured, the result may contain NaN or Inf values:

dev = qml.device("default.qubit")

@qml.qnode(dev)
def func(x):
    qml.RX(x, wires=0)
    m0 = qml.measure(0, postselect=1)
    qml.cond(m0, qml.X)(wires=1)
    return qml.probs(wires=1)
>>> func(0.0)
tensor([nan, nan], requires_grad=True)

In the case of qml.sample, an empty array will be returned:

dev = qml.device("default.qubit")

@qml.qnode(dev)
def func(x):
    qml.RX(x, wires=0)
    m0 = qml.measure(0, postselect=1)
    qml.cond(m0, qml.X)(wires=1)
    return qml.sample(wires=[0, 1])
>>> func(0.0, shots=[10, 10])
(array([], shape=(0, 2), dtype=int64), array([], shape=(0, 2), dtype=int64))

Note

Currently, postselection support is only available on default.qubit. Using postselection on other devices will raise an error.

Warning

All measurements are supported when using postselection. However, postselection on a zero probability state can cause some measurements to break:

  • With finite shots, one must be careful when measuring qml.probs or qml.counts, as these measurements will raise errors if there are no valid samples after postselection. This will occur with postselection states that have zero or close to zero probability.

  • With analytic execution, qml.mutual_info will raise errors when using any interfaces except jax, and qml.vn_entropy will raise an error with the tensorflow interface when the postselection state has zero probability.

  • When using JIT, QNode’s may have unexpected behaviour when postselection on a zero probability state is performed. Due to floating point precision, the zero probability may not be detected, thus letting execution continue as normal without NaN or Inf values or empty samples, leading to unexpected or incorrect results.

Contents

Using PennyLane

Release news

Development

API

Internals