`CommutativeInverseCancellation` fails with `for_loop`
Environment
- Qiskit version: 2.0.2
- Python version: Python 3.13.2
- Operating system: Ubuntu 20.04.6 LTS
What is happening?
When applying the CommutativeInverseCancellation pass to a circuit that contains a for_loop block, a CircuitError is raised due to the lack of .inverse() implementation for for_loop.
How can we reproduce the issue?
To Reproduce:
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile
from qiskit_aer import Aer
from qiskit.transpiler.passes import *
from qiskit.transpiler import PassManager
import numpy as np
qreg = QuantumRegister(4)
creg = ClassicalRegister(4)
qc = QuantumCircuit(qreg, creg)
qc.crx(np.pi/2, 2, 0)
with qc.for_loop(range(3)) as i:
qc.cx(2, 0)
qc.measure(qreg[0], creg[0])
qc.measure(qreg[1], creg[1])
qc.measure(qreg[2], creg[2])
qc.measure(qreg[3], creg[3])
simulator = Aer.get_backend("aer_simulator")
p = PassManager(CommutativeInverseCancellation())
qc = p.run(qc)
compiled_circuit = transpile(qc, backend=simulator)
job = simulator.run(compiled_circuit, shots=10000)
result = job.result().get_counts()
print(result)
Error Message
qiskit.circuit.exceptions.CircuitError: 'inverse() not implemented for for_loop.'
What should happen?
The circuit should transpile and execute successfully.
Any suggestions?
The following modified version runs without error, even though it also contains a for_loop:
with qc.for_loop(range(3)) as i:
qc.cx(2, 0)
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc.add_register(qr)
qc.add_register(cr)
qc.measure(qr[0], cr[0])
qc.measure(qr[1], cr[1])
Another no error version is:
with qc.for_loop(range(3)) as i:
qc.cx(0, 2)
Hi @alexanderivrii , This issue looks similar to #14254 , which you had worked on before. I thought it might be related, so just wanted to bring it to your attention. Thanks!
Thanks for reporting the issue. Indeed, not all Instructions have inverses and CommutativeInverseCancellation pass does not properly check for that. A very simple fix for the current problem would be to adjust the _skip_node function to also skip control-flow nodes. However, this still does not handle the related issue #14407. There the circuit contains an Initialize instruction.
@alexanderivrii , thanks for the clarification!
I actually ran into a similar issue in #14409, which I also opened. It also involves CommutativeInverseCancellation failing due to an instruction not implementing .inverse().
If the fix you're considering here (e.g., extending _skip_node to skip control-flow ops) works well, maybe a similar strategy could help with that one too?
Thank you for reporting this, should be fixed by #14655.
Closing as the fix has been merged in #14655. Thanks for reporting!