Environment
- Qiskit version: 2.3.1
- Python version: 3.13
- Operating system: macOS
What is happening?
The text circuit drawer, QuantumCircuit.draw("text"), fails inside control-flow blocks that do not share the same clbits as the outer circuit when cregbundle=True. For circuits constructed using the control-flow builder interface, the bits are the same outside and inside the control-flow block, and no failure occurs.
Note that this is not a fault of the circuit construction - it is not a problem for the clbits used in the inner block of a control-flow op to be different objects to the outer circuit, because they are "bound" by the CircuitInstruction.clbits arguments that contain the instruction.
How can we reproduce the issue?
from qiskit import QuantumCircuit
from qiskit.circuit import Clbit, Qubit
from qiskit.circuit.classical import expr
cell = QuantumCircuit([Qubit(), Clbit()])
with cell.if_test(expr.lift(True)):
cell.measure(0, 0)
qc = QuantumCircuit(2, 2)
for i in range(2):
qc.compose(cell, qubits=[i], clbits=[i], inplace=True)
qc.draw("text", cregbundle=True)
gives
KeyError Traceback (most recent call last)
File ~/code/qiskit/terra/qiskit/circuit/quantumcircuit.py:3733, in QuantumCircuit.find_bit(self, bit)
3732 elif isinstance(bit, Clbit):
-> 3733 return self._data._clbit_indices[bit]
3734 else:
KeyError: <Clbit uid=1>
The above exception was the direct cause of the following exception:
[... snip ...]
File ~/code/qiskit/terra/qiskit/visualization/circuit/text.py:1369, in TextDrawing.add_control_flow(self, node, layers, wire_map)
1364 flow_wire_map.update(
1365 {inner: wire_map[outer] for outer, inner in zip(node.qargs, circuit.qubits)}
1366 )
1367 for outer, inner in zip(node.cargs, circuit.clbits):
1368 if self.cregbundle and (
-> 1369 (in_reg := get_bit_register(self._circuit, inner)) is not None
1370 ):
1371 out_reg = get_bit_register(self._circuit, outer)
1372 flow_wire_map.update({in_reg: wire_map[out_reg]})
File ~/code/qiskit/terra/qiskit/visualization/circuit/_utils.py:218, in get_bit_register(circuit, bit)
208 def get_bit_register(circuit, bit):
209 """Get the register for a bit if there is one
210
211 Args:
(...)
216 ClassicalRegister: register associated with the bit
217 """
--> 218 bit_loc = circuit.find_bit(bit)
219 return bit_loc.registers[0][0] if bit_loc.registers else None
File ~/code/qiskit/terra/qiskit/circuit/quantumcircuit.py:3737, in QuantumCircuit.find_bit(self, bit)
3735 raise CircuitError(f"Could not locate bit of unknown type: {type(bit)}")
3736 except KeyError as err:
-> 3737 raise CircuitError(
3738 f"Could not locate provided bit: {bit}. Has it been added to the QuantumCircuit?"
3739 ) from err
CircuitError: 'Could not locate provided bit: <Clbit uid=1>. Has it been added to the QuantumCircuit?'
What should happen?
The circuit should draw correctly, and it should draw exactly as if constructed manually by the builder interface such as:
from qiskit import QuantumCircuit
from qiskit.circuit import Clbit, Qubit
from qiskit.circuit.classical import expr
cell = QuantumCircuit([Qubit(), Clbit()])
qc = QuantumCircuit(2, 2)
for i in range(2):
with qc.if_test(expr.lift(True)):
qc.measure(i, i)
qc.draw("text", cregbundle=True)
┌─────────── ┌─┐ ───────┐
q_0: ┤ If-0 true ┤M├ End-0 ├───────────────────────────
└─────────── └╥┘ ───────┘ ┌─────────── ┌─┐ ───────┐
q_1: ──────────────╫───────────┤ If-0 true ┤M├ End-0 ├─
║ └─────────── └╥┘ ───────┘
c: 2/══════════════╩═════════════════════════╩═══════════
0 1
Any suggestions?
The trouble is somewhere in the creation of the flow_wire_map - it's never correct to try and look up a bit from an inner control-flow block directly in the context of the outer circuit, but that seems to be what we're doing. It's not immediately obvious to me how cregbundle works, though - a fix needs to make sure that the bundling is still behaving as expected.
Note that this is basically the same issue as #15823, but I made a separate issue because the mechanisms of the MPL and text drawers are often quite different, and it's not 100% guaranteed that something easy to fix in one will be easy to fix in the other.
Environment
What is happening?
The text circuit drawer,
QuantumCircuit.draw("text"), fails inside control-flow blocks that do not share the same clbits as the outer circuit whencregbundle=True. For circuits constructed using the control-flow builder interface, the bits are the same outside and inside the control-flow block, and no failure occurs.Note that this is not a fault of the circuit construction - it is not a problem for the
clbits used in the innerblockof a control-flow op to be different objects to the outer circuit, because they are "bound" by theCircuitInstruction.clbitsarguments that contain the instruction.How can we reproduce the issue?
gives
What should happen?
The circuit should draw correctly, and it should draw exactly as if constructed manually by the builder interface such as:
Any suggestions?
The trouble is somewhere in the creation of the
flow_wire_map- it's never correct to try and look up a bit from an inner control-flow block directly in the context of the outer circuit, but that seems to be what we're doing. It's not immediately obvious to me howcregbundleworks, though - a fix needs to make sure that the bundling is still behaving as expected.Note that this is basically the same issue as #15823, but I made a separate issue because the mechanisms of the MPL and text drawers are often quite different, and it's not 100% guaranteed that something easy to fix in one will be easy to fix in the other.