-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Information
- Qiskit Terra version:
- Python version:
- Operating system:
What is the current behavior?
Flattening a conditional circuit gives incorrect results. It looks like the issue is probably in how the conditionals are implemented:
Steps to reproduce the problem
Manually adding an additional registers to a teleport circuit works:
def teleport_circuit():
"""Teleport qubit 0 -> 2"""
qr = QuantumRegister(3)
c0 = ClassicalRegister(1)
c1 = ClassicalRegister(1)
teleport = QuantumCircuit(qr, c0, c1)
teleport.h(qr[1])
teleport.cx(qr[1], qr[2])
teleport.cx(qr[0], qr[1])
teleport.h(qr[0])
teleport.measure(qr[0], c0[0])
teleport.measure(qr[1], c1[0])
teleport.z(qr[2]).c_if(c0, 1)
teleport.x(qr[2]).c_if(c1, 1)
return teleport
# Add extra register for measuring qubit-2
c2 = ClassicalRegister(1)
circ = teleport_circuit()
circ.add_register(c2)
circ.measure(2, c2)
# Run
counts = AerSimulator().run(circ).result().get_counts(0)
marginal_counts(counts, [2])
# Marginal Counts (correct)
{'0': 1024}
But composing and flattening gives wrong answer:
# Compose with larger circuit
circ = QuantumCircuit(3, 3)
circ = circ.compose(teleport_circuit(), range(3), range(2))
circ.measure(2, 2)
# Run
counts = AerSimulator().run(circ).result().get_counts(0)
marginal_counts(counts, [2])
# Marginal Counts (incorrect)
{'1': 228, '0': 796}
What is the expected behavior?
Flattening the conditional circuit should implement the same circuit.
Suggested solutions
From the drawer it looks liek the flattened circuit is handling conditions on the joint circuit wrong:
┌───┐┌─┐
q_0: ────────────■──┤ H ├┤M├──────────────
┌───┐ ┌─┴─┐└┬─┬┘└╥┘
q_1: ┤ H ├──■──┤ X ├─┤M├──╫───────────────
└───┘┌─┴─┐└───┘ └╥┘ ║ ┌───┐ ┌───┐
q_2: ─────┤ X ├───────╫───╫──┤ Z ├──┤ X ├─
└───┘ ║ ║ └─╥─┘ └─╥─┘
║ ║ ┌──╨──┐┌──╨──┐
c: 3/═════════════════╩═══╩═╡ = 1 ╞╡ = 2 ╞
1 0 └─────┘└─────┘
Looks like conditions are triggering on creg values 01
and 10
, but nothing on 11
which should trigger both conditional gates.
Looking at the qobj that gets assembled from these circuits we can see the difference:
Multi-register assembled qobj instructions:
assemble(circ).experiments[0].instructions =
[QasmQobjInstruction(name='h', qubits=[1]),
QasmQobjInstruction(name='cx', qubits=[1, 2]),
QasmQobjInstruction(name='cx', qubits=[0, 1]),
QasmQobjInstruction(name='h', qubits=[0]),
QasmQobjInstruction(name='measure', qubits=[0], register=[0], memory=[0]),
QasmQobjInstruction(name='measure', qubits=[1], register=[1], memory=[1]),
QasmQobjInstruction(name='bfunc', register=3, mask="0x1", relation="==", val="0x1"),
QasmQobjInstruction(name='z', qubits=[2], conditional=3),
QasmQobjInstruction(name='bfunc', register=4, mask="0x2", relation="==", val="0x2"),
QasmQobjInstruction(name='x', qubits=[2], conditional=4),
QasmQobjInstruction(name='measure', qubits=[2], register=[2], memory=[2])]
Flattened circuit assembled qobj instructions:
[QasmQobjInstruction(name='h', qubits=[1]),
QasmQobjInstruction(name='cx', qubits=[1, 2]),
QasmQobjInstruction(name='cx', qubits=[0, 1]),
QasmQobjInstruction(name='h', qubits=[0]),
QasmQobjInstruction(name='measure', qubits=[0], register=[0], memory=[0]),
QasmQobjInstruction(name='measure', qubits=[1], register=[1], memory=[1]),
QasmQobjInstruction(name='bfunc', register=3, mask="0x7", relation="==", val="0x1"),
QasmQobjInstruction(name='z', qubits=[2], conditional=3),
QasmQobjInstruction(name='bfunc', register=4, mask="0x7", relation="==", val="0x2"),
QasmQobjInstruction(name='x', qubits=[2], conditional=4),
QasmQobjInstruction(name='measure', qubits=[2], register=[2], memory=[2])]
You can see that in the second case the mask
value is being set incorrectly to 0x7 = 0b111
in both case to the full 3-bit register rather than the the single bit values.