Measurement conditioned on measurement?

Hello!

I want to create a quantum circuit where a measurement is applied conditioned on the result of another measurement. I tried something like this (not the full example, but it reproduces the error I get).

@qml.qnode(qml.device("default.qubit"))
def circuit():
    qml.cond(qml.measure(0), qml.measure(1))
    return qml.expval(qml.X(0) @ qml.X(1))
circuit()

The error that I get is the following

ConditionalTransformError: Only operations and quantum functions with no measurements can be applied conditionally.

My guess is that PennyLane doesn’t support this yet, or maybe something is wrong with my syntax? :thinking: I tried changing stuff around, but it didn’t work either.

If it’s the case that PennyLane cannot do this natively, is there a way to get around it?

Here’s the output of qml.about():

Name: PennyLane
Version: 0.39.0
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: /usr/local/lib/python3.10/dist-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, packaging, pennylane-lightning, requests, rustworkx, scipy, toml, typing-extensions
Required-by: PennyLane_Lightning

Platform info:           Linux-6.1.85+-x86_64-with-glibc2.35
Python version:          3.10.12
Numpy version:           1.26.4
Scipy version:           1.13.1
Installed devices:
- lightning.qubit (PennyLane_Lightning-0.39.0)
- default.clifford (PennyLane-0.39.0)
- default.gaussian (PennyLane-0.39.0)
- default.mixed (PennyLane-0.39.0)
- default.qubit (PennyLane-0.39.0)
- default.qutrit (PennyLane-0.39.0)
- default.qutrit.mixed (PennyLane-0.39.0)
- default.tensor (PennyLane-0.39.0)
- null.qubit (PennyLane-0.39.0)
- reference.qubit (PennyLane-0.39.0)

Thank you!

Hello @i_am_confusion
Welcome to the forum.

I was able to reproduce your error. For qml.cond, the conditioned operation can’t be a measurement or one that involves measurements. I don’t think there is anything wrong with your syntax, it is just that the application your looking for is not supported by qml.cond (see source for more details).

However, an idea :bulb: will be using the postselection (only available on “default qubit”) feature of qml.measure (see the bottom of the page for more). This discards the cases where the outcome of the measurement doesn’t correspond to the desired postselection.

I provide an example for you to play with.Two qubits are initialized in zero, then qubit 0 is flipped to 1 and a mid circuit measurement is implemented with postselection. When m0 is 1, all cases in this example, a CNOT is applied and the second qubit is flipped to 1 to subsequently be measured in the Z basis.

import pennylane as qml

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

@qml.qnode(dev)
def func():
    qml.X(0)
    m0 = qml.measure(0, postselect=1)
    qml.CNOT(wires=[0, 1])
    return qml.expval(qml.Z(1))

func(shots=100)

From what I see in the code you provided, in the first part, you wanted to measure qubit 1 in the computational basis only when the outcome of the measurement on qubit 0 was equal to 1. Something like the following:

@qml.qnode(dev)
def func():
    m0 = qml.measure(0, postselect=1)
    return qml.expval(qml.Z(1))

func(shots=100)

There is also a nice PennyLane demo on mid-circuit measurements.
Let me know if this helped and/or there any other questions.

Hi @dangulom !

I think this is close to what I want, but I also want to sample the measurement results from the first wire. I think postselect = 1 destroys the qubit and I wouldn’t be able to get the statistics (probability) of measuring 0 on wire 0 :thinking: . Do let me know if you have any ideas to go around this. Thanks for your help :slight_smile:

Hi!
:bulb: :smiley: I figured that could be a follow-up question, it occurred to me as well while I was typing my answer.
I could suggest a “brute-force” approach: implementing an appropriate version of your circuit (or the function) for the case with postselection = 0 so you can collect the statistics separately (yep, like running the code twice). Let me know how that sounds, I believe this could be a safe way around it.

Just to add. I tried a way around it using qml.cond() again :sweat_smile:, now with a subcircuit in the argument. See code:

def sub_circ():
    qml.X(1)
    #mcm = qml.measure(1)

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

@qml.qnode(dev)
def func():
    qml.X(0)
    m0 = qml.measure(0)
    qml.cond(m0, sub_circ)()
    return qml.sample(qml.Z(1))

print(func(shots=100))

and it only works when I don’t perform the measurement in sub_circ. Otherwise, it outputs the following error AttributeError: 'MidMeasureMP' object has no attribute 'num_params'
And I actually found an open issue related to this in the PennyLane github repo.

I see! Yes I think this approach will work. I’m glad that the PennyLane team is working on this.

Thank you for your help :slight_smile:

1 Like