How to apply multiple mid-circuit measurements on the same wire with resetting and post-selection?

Hello! I’m trying to implement a circuit with several mid-circuit measurements on the auxiliary qubit. A post-selection and a resetting is intended to be applied after the measurement. The following is a simple example, and it will run into an error:

import pennylane as qml

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

@qml.qnode(dev)
def circuit():
    for i in range(3):
        qml.H(0)
        qml.measure(0, reset=True, postselect=0)
    return qml.expval(qml.X(1))

circuit()

The error information is:

File "C:\Users\Timmy\AppData\Local\Programs\Python\Python312\Lib\site-packages\pennylane\devices\preprocess.py", line 144, in validate_device_wires
    raise WireError(
pennylane.exceptions.WireError: Cannot run circuit(s) on default.qubit as they contain wires not found on the device: {2, 3, 4}

It indicates that I’m trying to operate the qubit 2 and 3, but my code does not operate these qubits. If I replace the statement qml.measure(0, reset=True, postselect=0) with qml.measure(0, reset=False, postselect=0), the same type of error will also occur.

My qml.about:

Version: 0.43.1
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemi
stry. Train a quantum computer the same way as a neural network.                                                        Home-page:
Author:
Author-email:
License-Expression: Apache-2.0
Location: C:\Users\Timmy\AppData\Local\Programs\Python\Python312\Lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, diastatic-malt, networkx, numpy, packaging, pennylane-lightning, reque
sts, rustworkx, scipy, tomlkit, typing_extensions                                                                       Required-by: pennylane_lightning

Platform info:           Windows-11-10.0.26220-SP0
Python version:          3.12.7
Numpy version:           2.3.4
Scipy version:           1.16.2
JAX version:             None
Installed devices:
- default.clifford (pennylane-0.43.1)
- default.gaussian (pennylane-0.43.1)
- default.mixed (pennylane-0.43.1)
- default.qubit (pennylane-0.43.1)
- default.qutrit (pennylane-0.43.1)
- default.qutrit.mixed (pennylane-0.43.1)
- default.tensor (pennylane-0.43.1)
- null.qubit (pennylane-0.43.1)
- reference.qubit (pennylane-0.43.1)
- lightning.qubit (pennylane_lightning-0.43.0)

Hi @Tz_19 ,

This is actually due to the way mid-circuit measurements are performed. It’s a very common error! I recently explained it in Forum post #9102, so I would recommend checking it out for more details. In short, you need to add more wires to your device, so the easiest way to do it is to let the device automatically detect the number of wires it needs. You can do this by simply not setting a number of wires when you create an instance of default.qubit.
dev=qml.device("default.qubit")

Let me know if this solves your issue!

Hi @CatalinaAlbornoz, thank you for your explanation! It seems that the memory usage will grow up quickly with the number of measurements, just like I’m simulating a larger circuit with more qubits. For example, If I run the following code:

import pennylane as qml

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

@qml.qnode(dev)
def circuit():
    for i in range(32):
        qml.H(0)
        qml.CNOT(wires=[0,1])
        qml.measure(0, reset=True, postselect=0)
    return qml.expval(qml.X(1))

print(circuit())

The following error will raise:

  File "C:\Users\Timmy\AppData\Local\Programs\Python\Python312\Lib\site-packages\pennylane\devices\qubit\initialize_state.py", line 43, in create_initial_state
    state = np.zeros((2,) * num_wires, dtype=complex)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
numpy._core._exceptions._ArrayMemoryError: Unable to allocate 256. GiB for an array with shape (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) and data type complex128

Is there any method to avoid the memory usage explosion currently? Meanwhile, given that there is a reset argument of qml.measure(), will it be possible to reuse the measured qubit directly without increasing the qubit number in the future?

Hi @Tz_19 ,

As you have your code right now this would require 33 qubits, which indeed needs a lot of memory. This is because by default the mid-circuit-measurements use the deferred measurements principle. If you check the simulation techniques section on the docs page for dynamic circuits, you’ll find a nice table with an explanation below, which suggests two different methods you could use, with their advantages and disadvantages. I would recommend that you try those methods (dynamic one-shot and tree-traversal) by setting them in the qnode argument as described in the following sections of that page. Here’s an example code:

import pennylane as qml

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

@qml.qnode(dev, mcm_method="tree-traversal")
def circuit():
    for i in range(32):
        qml.H(0)
        qml.CNOT(wires=[0,1])
        qml.measure(0, reset=True, postselect=0)
    return qml.expval(qml.X(1))

print(circuit())

I hope this helps!