Improve reverse_bits to support registerless bits (#7423)

* Improve reverse_bits to support registerless bits

* Change the algorithm of reverse_bits

* Reimplement reverse_bits with reversed bits

Also add more test cases.

* Simplify bit lookups

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
This commit is contained in:
Jintao YU 2022-05-17 23:11:18 +08:00 committed by GitHub
parent 0041b6ff26
commit b898359192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 18 deletions

View File

@ -475,37 +475,51 @@ class QuantumCircuit:
.. parsed-literal::
q_0: H
q_1: RX(1.57)
a_0: H
a_1: X
a_2: X
b_0: X
b_1: X
output:
.. parsed-literal::
q_0: RX(1.57)
q_1: H
b_0: X
b_1: X
a_0: X
a_1: X
a_2: H
"""
circ = QuantumCircuit(
*reversed(self.qregs),
*reversed(self.cregs),
list(reversed(self.qubits)),
list(reversed(self.clbits)),
name=self.name,
global_phase=self.global_phase,
)
num_qubits = self.num_qubits
num_clbits = self.num_clbits
old_qubits = self.qubits
old_clbits = self.clbits
new_qubits = circ.qubits
new_clbits = circ.clbits
new_qubit_map = circ.qubits[::-1]
new_clbit_map = circ.clbits[::-1]
for reg in reversed(self.qregs):
bits = [new_qubit_map[self.find_bit(qubit).index] for qubit in reversed(reg)]
circ.add_register(QuantumRegister(bits=bits, name=reg.name))
for reg in reversed(self.cregs):
bits = [new_clbit_map[self.find_bit(clbit).index] for clbit in reversed(reg)]
circ.add_register(ClassicalRegister(bits=bits, name=reg.name))
for inst, qargs, cargs in self.data:
new_qargs = [new_qubits[num_qubits - old_qubits.index(q) - 1] for q in qargs]
new_cargs = [new_clbits[num_clbits - old_clbits.index(c) - 1] for c in cargs]
new_qargs = [new_qubit_map[self.find_bit(qubit).index] for qubit in qargs]
new_cargs = [new_clbit_map[self.find_bit(clbit).index] for clbit in cargs]
circ._append(inst, new_qargs, new_cargs)
return circ

View File

@ -0,0 +1,11 @@
---
fixes:
- |
Fixed :meth:`.QuantumCircuit.reverse_bits` with circuits containing registerless
:class:`.Qubit` and :class:`.Clbit`. For example, the following will now work::
from qiskit.circuit import QuantumCircuit, Qubit, Clbit
qc = QuantumCircuit([Qubit(), Clbit()])
qc.h(0).c_if(qc.clbits[0], 0)
qc.reverse_bits()

View File

@ -1008,6 +1008,80 @@ class TestCircuitOperations(QiskitTestCase):
self.assertEqual(qc.reverse_bits(), expected)
def test_reverse_bits_with_overlapped_registers(self):
"""Test reversing order of bits when registers are overlapped."""
qr1 = QuantumRegister(2, "a")
qr2 = QuantumRegister(bits=[qr1[0], qr1[1], Qubit()], name="b")
qc = QuantumCircuit(qr1, qr2)
qc.h(qr1[0])
qc.cx(qr1[0], qr1[1])
qc.cx(qr1[1], qr2[2])
qr2 = QuantumRegister(bits=[Qubit(), qr1[0], qr1[1]], name="b")
expected = QuantumCircuit(qr2, qr1)
expected.h(qr1[1])
expected.cx(qr1[1], qr1[0])
expected.cx(qr1[0], qr2[0])
self.assertEqual(qc.reverse_bits(), expected)
def test_reverse_bits_with_registerless_bits(self):
"""Test reversing order of registerless bits."""
q0 = Qubit()
q1 = Qubit()
c0 = Clbit()
c1 = Clbit()
qc = QuantumCircuit([q0, q1], [c0, c1])
qc.h(0)
qc.cx(0, 1)
qc.x(0).c_if(1, True)
qc.measure(0, 0)
expected = QuantumCircuit([c1, c0], [q1, q0])
expected.h(1)
expected.cx(1, 0)
expected.x(1).c_if(0, True)
expected.measure(1, 1)
self.assertEqual(qc.reverse_bits(), expected)
def test_reverse_bits_with_registers_and_bits(self):
"""Test reversing order of bits with registers and registerless bits."""
qr = QuantumRegister(2, "a")
q = Qubit()
qc = QuantumCircuit(qr, [q])
qc.h(qr[0])
qc.cx(qr[0], qr[1])
qc.cx(qr[1], q)
expected = QuantumCircuit([q], qr)
expected.h(qr[1])
expected.cx(qr[1], qr[0])
expected.cx(qr[0], q)
self.assertEqual(qc.reverse_bits(), expected)
def test_reverse_bits_with_mixed_overlapped_registers(self):
"""Test reversing order of bits with overlapped registers and registerless bits."""
q = Qubit()
qr1 = QuantumRegister(bits=[q, Qubit()], name="qr1")
qr2 = QuantumRegister(bits=[qr1[1], Qubit()], name="qr2")
qc = QuantumCircuit(qr1, qr2, [Qubit()])
qc.h(q)
qc.cx(qr1[0], qr1[1])
qc.cx(qr1[1], qr2[1])
qc.cx(2, 3)
qr2 = QuantumRegister(2, "qr2")
qr1 = QuantumRegister(bits=[qr2[1], q], name="qr1")
expected = QuantumCircuit([Qubit()], qr2, qr1)
expected.h(qr1[1])
expected.cx(qr1[1], qr1[0])
expected.cx(qr1[0], qr2[0])
expected.cx(1, 0)
self.assertEqual(qc.reverse_bits(), expected)
def test_cnot_alias(self):
"""Test that the cnot method alias adds a cx gate."""
qc = QuantumCircuit(2)