diff --git a/qiskit/transpiler/passes/basis/decompose.py b/qiskit/transpiler/passes/basis/decompose.py index 444d73268b6b..b914d3f9f537 100644 --- a/qiskit/transpiler/passes/basis/decompose.py +++ b/qiskit/transpiler/passes/basis/decompose.py @@ -51,7 +51,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: # TODO: allow choosing among multiple decomposition rules rule = node.op.definition.data - if len(rule) == 1 and len(node.qargs) == len(rule[0][1]): + if len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1: dag.substitute_node(node, rule[0][0], inplace=True) else: decomposition = circuit_to_dag(node.op.definition) diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index 12e3b084c0a0..bbdb31c952e3 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -73,7 +73,7 @@ def run(self, dag): # original gate, in which case substitute_node will raise. Fall back # to substitute_node_with_dag if an the width of the definition is # different that the width of the node. - while rule and len(rule) == 1 and len(node.qargs) == len(rule[0][1]): + while rule and len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1: if rule[0][0].name in self.basis: if node.op.definition and node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase diff --git a/releasenotes/notes/preserve-qreg-order-when-unrolling-and-decomposing-3d1789cd2eb4a8f9.yaml b/releasenotes/notes/preserve-qreg-order-when-unrolling-and-decomposing-3d1789cd2eb4a8f9.yaml new file mode 100644 index 000000000000..fcecb0a57a93 --- /dev/null +++ b/releasenotes/notes/preserve-qreg-order-when-unrolling-and-decomposing-3d1789cd2eb4a8f9.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + A bug that was causing registers to be mismapped when unrolling/decomposing + a gate defined with only one 2-qubit operation. Now the decomposition will reflect + how a gate is defined. diff --git a/test/python/transpiler/test_decompose.py b/test/python/transpiler/test_decompose.py index 7950f50c97cc..159f18c61f7e 100644 --- a/test/python/transpiler/test_decompose.py +++ b/test/python/transpiler/test_decompose.py @@ -102,6 +102,22 @@ def test_decompose_oversized_instruction(self): self.assertEqual(qc1, output) + def test_decomposition_preserves_qregs_order(self): + """Test decomposing a gate preserves it's definition registers order""" + qr = QuantumRegister(2, 'qr1') + qc = QuantumCircuit(qr) + qc.cx(1, 0) + gate = qc.to_gate() + + qr2 = QuantumRegister(2, 'qr2') + qc2 = QuantumCircuit(qr2) + qc2.append(gate, qr2) + + expected = QuantumCircuit(qr2) + expected.cx(1, 0) + + self.assertEqual(qc2.decompose(), expected) + def test_decompose_global_phase_1q(self): """Test decomposition of circuit with global phase""" qc = QuantumCircuit(1) diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index 066cf9408d9d..7b9f9fbecb24 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -211,6 +211,58 @@ def test_unrolling_parameterized_composite_gates(self): self.assertEqual(circuit_to_dag(expected), out_dag) + def test_unrolling_preserves_qregs_order(self): + """Test unrolling a gate preseveres it's definition registers order""" + qr = QuantumRegister(2, 'qr1') + qc = QuantumCircuit(qr) + qc.cx(1, 0) + gate = qc.to_gate() + + qr2 = QuantumRegister(2, 'qr2') + qc2 = QuantumCircuit(qr2) + qc2.append(gate, qr2) + + dag = circuit_to_dag(qc2) + out_dag = Unroller(['cx']).run(dag) + + expected = QuantumCircuit(qr2) + expected.cx(1, 0) + + self.assertEqual(circuit_to_dag(expected), out_dag) + + def test_unrolling_nested_gates_preserves_qregs_order(self): + """Test unrolling a nested gate preseveres it's definition registers order.""" + qr = QuantumRegister(2, 'qr1') + qc = QuantumCircuit(qr) + qc.cx(1, 0) + gate_level_1 = qc.to_gate() + + qr2 = QuantumRegister(2, 'qr2') + qc2 = QuantumCircuit(qr2) + qc2.append(gate_level_1, [1, 0]) + qc2.cu1(pi, 1, 0) + gate_level_2 = qc2.to_gate() + + qr3 = QuantumRegister(2, 'qr3') + qc3 = QuantumCircuit(qr3) + qc3.append(gate_level_2, [1, 0]) + qc3.cu3(pi, pi, pi, 1, 0) + gate_level_3 = qc3.to_gate() + + qr4 = QuantumRegister(2, 'qr4') + qc4 = QuantumCircuit(qr4) + qc4.append(gate_level_3, [0, 1]) + + dag = circuit_to_dag(qc4) + out_dag = Unroller(['cx', 'cu1', 'cu3']).run(dag) + + expected = QuantumCircuit(qr4) + expected.cx(1, 0) + expected.cu1(pi, 0, 1) + expected.cu3(pi, pi, pi, 1, 0) + + self.assertEqual(circuit_to_dag(expected), out_dag) + class TestUnrollAllInstructions(QiskitTestCase): """Test unrolling a circuit containing all standard instructions."""