diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index 7bb3d0d74f97..ed01e335d1e2 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -544,7 +544,7 @@ def _remap_circuit_faulty_backend(circuit, num_qubits, backend_prop, faulty_qubi for real_qubit in range(num_qubits): if faulty_qubits_map[real_qubit] is not None: - new_layout[real_qubit] = circuit._layout[faulty_qubits_map[real_qubit]] + new_layout[real_qubit] = circuit._layout.initial_layout[faulty_qubits_map[real_qubit]] else: if real_qubit in faulty_qubits: new_layout[real_qubit] = faulty_qreg[faulty_qubit] diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index cfb863f77496..261a45d84e02 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -200,9 +200,9 @@ def from_label(cls, label): @classmethod def from_circuit(cls, circuit, ignore_set_layout=False, layout=None): - """Create a new Operator object from a :class`.QuantumCircuit` + """Create a new Operator object from a :class:`.QuantumCircuit` - While a :class:`.QuantumCircuit` object can passed directly as ``data`` + While a :class:`~.QuantumCircuit` object can passed directly as ``data`` to the class constructor this provides no options on how the circuit is used to create an :class:`.Operator`. This constructor method lets you control how the :class:`.Operator` is created so it can be adjusted @@ -221,7 +221,9 @@ def from_circuit(cls, circuit, ignore_set_layout=False, layout=None): layout (Layout): If specified this kwarg can be used to specify a particular layout to use to permute the qubits in the created :class:`.Operator`. If this is specified it will be used instead - of a layout contained in the ``circuit`` input. + of a layout contained in the ``circuit`` input. If specified + the virtual bits in the :class:`~.Layout` must be present in the + ``circuit`` input. Returns: Operator: An operator representing the input circuit """ @@ -230,15 +232,23 @@ def from_circuit(cls, circuit, ignore_set_layout=False, layout=None): if layout is None: if not ignore_set_layout: layout = getattr(circuit, "_layout", None) + else: + from qiskit.transpiler.layout import TranspileLayout # pylint: disable=cyclic-import + + layout = TranspileLayout( + initial_layout=layout, + input_qubit_mapping={qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) qargs = None # If there was a layout specified (either from the circuit # or via user input) use that to set qargs to permute qubits # based on that layout if layout is not None: - qargs = { - phys: circuit.find_bit(bit).index - for phys, bit in layout.get_physical_bits().items() - } + physical_to_virtual = layout.initial_layout.get_physical_bits() + qargs = [ + layout.input_qubit_mapping[physical_to_virtual[physical_bit]] + for physical_bit in range(len(physical_to_virtual)) + ] # Convert circuit to an instruction instruction = circuit.to_instruction() op._append_instruction(instruction, qargs=qargs) diff --git a/qiskit/transpiler/basepasses.py b/qiskit/transpiler/basepasses.py index 5e006d16c8da..54a1c1de4aa4 100644 --- a/qiskit/transpiler/basepasses.py +++ b/qiskit/transpiler/basepasses.py @@ -16,6 +16,7 @@ from collections.abc import Hashable from inspect import signature from .propertyset import PropertySet +from .layout import TranspileLayout class MetaPass(type): @@ -131,7 +132,10 @@ def __call__(self, circuit, property_set=None): result_circuit = circuit.copy() if self.property_set["layout"]: - result_circuit._layout = self.property_set["layout"] + result_circuit._layout = TranspileLayout( + initial_layout=self.property_set["layout"], + input_qubit_mapping=self.property_set["original_qubit_indices"], + ) if self.property_set["clbit_write_latency"] is not None: result_circuit._clbit_write_latency = self.property_set["clbit_write_latency"] if self.property_set["conditional_latency"] is not None: diff --git a/qiskit/transpiler/layout.py b/qiskit/transpiler/layout.py index 5b00ca10abbd..ccaca4923412 100644 --- a/qiskit/transpiler/layout.py +++ b/qiskit/transpiler/layout.py @@ -18,6 +18,9 @@ Physical (qu)bits are integers. """ +from dataclasses import dataclass +from typing import Dict + from qiskit.circuit.quantumregister import Qubit, QuantumRegister from qiskit.transpiler.exceptions import LayoutError from qiskit.converters import isinstanceint @@ -363,3 +366,11 @@ def from_qubit_list(qubit_list, *qregs): for qreg in qregs: out.add_register(qreg) return out + + +@dataclass +class TranspileLayout: + """Layout attributes from output circuit from transpiler.""" + + initial_layout: Layout + input_qubit_mapping: Dict[Qubit, int] diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index 42da1aea713c..cd26a1ec4e91 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -66,6 +66,9 @@ def run(self, dag): for creg in dag.cregs.values(): new_dag.add_creg(creg) if post_layout is None: + self.property_set["original_qubit_indices"] = { + bit: index for index, bit in enumerate(dag.qubits) + } for qreg in dag.qregs.values(): self.property_set["layout"].add_register(qreg) virtual_phsyical_map = layout.get_virtual_bits() diff --git a/qiskit/transpiler/runningpassmanager.py b/qiskit/transpiler/runningpassmanager.py index 6cff16cb2c03..ba9376b73d5e 100644 --- a/qiskit/transpiler/runningpassmanager.py +++ b/qiskit/transpiler/runningpassmanager.py @@ -24,6 +24,7 @@ from .propertyset import PropertySet from .fencedobjs import FencedPropertySet, FencedDAGCircuit from .exceptions import TranspilerError +from .layout import TranspileLayout logger = logging.getLogger(__name__) @@ -128,7 +129,11 @@ def run(self, circuit, output_name=None, callback=None): circuit.name = output_name else: circuit.name = name - circuit._layout = self.property_set["layout"] + if self.property_set["layout"] is not None: + circuit._layout = TranspileLayout( + initial_layout=self.property_set["layout"], + input_qubit_mapping=self.property_set["original_qubit_indices"], + ) circuit._clbit_write_latency = self.property_set["clbit_write_latency"] circuit._conditional_latency = self.property_set["conditional_latency"] diff --git a/qiskit/visualization/circuit/latex.py b/qiskit/visualization/circuit/latex.py index be0a96c34673..bfd57d6472de 100644 --- a/qiskit/visualization/circuit/latex.py +++ b/qiskit/visualization/circuit/latex.py @@ -175,7 +175,10 @@ def __init__( self._plot_barriers = plot_barriers self._reverse_bits = reverse_bits if with_layout: - self._layout = self._circuit._layout + if self._circuit._layout: + self._layout = self._circuit._layout.initial_layout + else: + self._layout = None else: self._layout = None diff --git a/qiskit/visualization/circuit/matplotlib.py b/qiskit/visualization/circuit/matplotlib.py index 7396c27c8179..32393cd9bef4 100644 --- a/qiskit/visualization/circuit/matplotlib.py +++ b/qiskit/visualization/circuit/matplotlib.py @@ -169,7 +169,10 @@ def __init__( self._plot_barriers = plot_barriers self._reverse_bits = reverse_bits if with_layout: - self._layout = self._circuit._layout + if self._circuit._layout: + self._layout = self._circuit._layout.initial_layout + else: + self._layout = None else: self._layout = None diff --git a/qiskit/visualization/circuit/text.py b/qiskit/visualization/circuit/text.py index fa3783fca7cd..71c70cf2d0e0 100644 --- a/qiskit/visualization/circuit/text.py +++ b/qiskit/visualization/circuit/text.py @@ -670,7 +670,10 @@ def __init__( self.clbits = clbits self.nodes = nodes if with_layout: - self.layout = self._circuit._layout + if self._circuit._layout: + self.layout = self._circuit._layout.initial_layout + else: + self.layout = None else: self.layout = None diff --git a/qiskit/visualization/gate_map.py b/qiskit/visualization/gate_map.py index 27459e2fc1e8..44ce2253fddf 100644 --- a/qiskit/visualization/gate_map.py +++ b/qiskit/visualization/gate_map.py @@ -812,22 +812,22 @@ def plot_circuit_layout(circuit, backend, view="virtual", qubit_coordinates=None bit_locations = { bit: {"register": register, "index": index} - for register in circuit._layout.get_registers() + for register in circuit._layout.initial_layout.get_registers() for index, bit in enumerate(register) } - for index, qubit in enumerate(circuit._layout.get_virtual_bits()): + for index, qubit in enumerate(circuit._layout.initial_layout.get_virtual_bits()): if qubit not in bit_locations: bit_locations[qubit] = {"register": None, "index": index} if view == "virtual": - for key, val in circuit._layout.get_virtual_bits().items(): + for key, val in circuit._layout.initial_layout.get_virtual_bits().items(): bit_register = bit_locations[key]["register"] if bit_register is None or bit_register.name != "ancilla": qubits.append(val) qubit_labels[val] = bit_locations[key]["index"] elif view == "physical": - for key, val in circuit._layout.get_physical_bits().items(): + for key, val in circuit._layout.initial_layout.get_physical_bits().items(): bit_register = bit_locations[val]["register"] if bit_register is None or bit_register.name != "ancilla": qubits.append(key) diff --git a/releasenotes/notes/fix-Opertor.from_circuit-transpile-5c056968ee40025e.yaml b/releasenotes/notes/fix-Opertor.from_circuit-transpile-5c056968ee40025e.yaml new file mode 100644 index 000000000000..3af3b74f7c4d --- /dev/null +++ b/releasenotes/notes/fix-Opertor.from_circuit-transpile-5c056968ee40025e.yaml @@ -0,0 +1,27 @@ +--- +upgrade: + - | + The ``._layout`` attribute of the :class:`~.QuantumCircuit` object has + been changed from storing a :class:`~.Layout` object to storing a + data class with 2 attributes, ``initial_layout`` which contains a + :class:`~.Layout` object for the initial layout set during compilation + and ``input_qubit_mapping`` which contains a dictionary mapping qubits + to position indices in the original circuit. This change was necessary to + provide all the information for a post-transpiled circuit to be able to + fully reverse the permutation caused by initial layout in all situations. While + this attribute is private and shouldn't be used externally, it is + the only way to track the initial layout through :func:`~.transpile` + so the change is being documented in case you're relying on it. If + you have a use case for the ``_layout`` attribute that is not being + addressed by the Qiskit API please open an issue so we can address this + feature gap. +fixes: + - | + The :meth:`.Operator.from_circuit` constructor method has been updated + so that it can handle the layout output from :func:`~.transpile` and + correctly reverse the qubit permutation caused by layout in all cases. + Previously, if your transpiled circuit used loose :class:`~.Qubit` objects, + multiple :class:`~.QuantumRegister` objects, or a single + :class:`~.QuantumRegister` with a name other than ``"q"`` the constructor + would have failed to create an :class:`~.Operator` from the circuit. + Fixed `#8800 `__. diff --git a/test/python/quantum_info/operators/test_operator.py b/test/python/quantum_info/operators/test_operator.py index 365b33f1ac9a..ecca4399d2a1 100644 --- a/test/python/quantum_info/operators/test_operator.py +++ b/test/python/quantum_info/operators/test_operator.py @@ -25,9 +25,11 @@ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.circuit.library import HGate, CHGate, CXGate, QFT from qiskit.test import QiskitTestCase -from qiskit.transpiler.layout import Layout +from qiskit.transpiler.layout import Layout, TranspileLayout from qiskit.quantum_info.operators.operator import Operator from qiskit.quantum_info.operators.predicates import matrix_equal +from qiskit.compiler.transpiler import transpile +from qiskit.circuit import Qubit logger = logging.getLogger(__name__) @@ -706,7 +708,10 @@ def test_from_circuit_constructor_reverse_embedded_layout(self): circuit.h(2) circuit.x(1) circuit.ry(np.pi / 2, 0) - circuit._layout = Layout({circuit.qubits[2]: 0, circuit.qubits[1]: 1, circuit.qubits[0]: 2}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[2]: 0, circuit.qubits[1]: 1, circuit.qubits[0]: 2}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit) y90 = (1 / np.sqrt(2)) * np.array([[1, -1], [1, 1]]) target = np.kron(y90, np.kron(self.UX, self.UH)) @@ -717,7 +722,10 @@ def test_from_circuit_constructor_reverse_embedded_layout(self): lam = np.pi / 4 circuit = QuantumCircuit(2) circuit.cp(lam, 1, 0) - circuit._layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit) target = np.diag([1, 1, 1, np.exp(1j * lam)]) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) @@ -726,7 +734,10 @@ def test_from_circuit_constructor_reverse_embedded_layout(self): # Test decomposition of controlled-H gate circuit = QuantumCircuit(2) circuit.ch(1, 0) - circuit._layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit) target = np.kron(self.UI, np.diag([1, 0])) + np.kron(self.UH, np.diag([0, 1])) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) @@ -739,7 +750,10 @@ def test_from_circuit_constructor_reverse_embedded_layout_ignore_set_layout(self circuit.h(2) circuit.x(1) circuit.ry(np.pi / 2, 0) - circuit._layout = Layout({circuit.qubits[2]: 0, circuit.qubits[1]: 1, circuit.qubits[0]: 2}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[2]: 0, circuit.qubits[1]: 1, circuit.qubits[0]: 2}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit, ignore_set_layout=True).reverse_qargs() y90 = (1 / np.sqrt(2)) * np.array([[1, -1], [1, 1]]) target = np.kron(y90, np.kron(self.UX, self.UH)) @@ -750,7 +764,10 @@ def test_from_circuit_constructor_reverse_embedded_layout_ignore_set_layout(self lam = np.pi / 4 circuit = QuantumCircuit(2) circuit.cp(lam, 1, 0) - circuit._layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit, ignore_set_layout=True).reverse_qargs() target = np.diag([1, 1, 1, np.exp(1j * lam)]) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) @@ -759,7 +776,10 @@ def test_from_circuit_constructor_reverse_embedded_layout_ignore_set_layout(self # Test decomposition of controlled-H gate circuit = QuantumCircuit(2) circuit.ch(1, 0) - circuit._layout = Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}) + circuit._layout = TranspileLayout( + Layout({circuit.qubits[1]: 0, circuit.qubits[0]: 1}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) op = Operator.from_circuit(circuit, ignore_set_layout=True).reverse_qargs() target = np.kron(self.UI, np.diag([1, 0])) + np.kron(self.UH, np.diag([0, 1])) global_phase_equivalent = matrix_equal(op.data, target, ignore_phase=True) @@ -806,14 +826,17 @@ def test_from_circuit_constructor_ghz_out_of_order_layout(self): circuit.cx(3, 2) circuit.cx(3, 0) circuit.cx(3, 1) - circuit._layout = Layout( - { - circuit.qubits[3]: 0, - circuit.qubits[4]: 1, - circuit.qubits[2]: 2, - circuit.qubits[0]: 3, - circuit.qubits[1]: 4, - } + circuit._layout = TranspileLayout( + Layout( + { + circuit.qubits[3]: 0, + circuit.qubits[4]: 1, + circuit.qubits[2]: 2, + circuit.qubits[0]: 3, + circuit.qubits[1]: 4, + } + ), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, ) result = Operator.from_circuit(circuit) expected = QuantumCircuit(5) @@ -828,7 +851,7 @@ def test_from_circuit_constructor_ghz_out_of_order_layout(self): def test_from_circuit_empty_circuit_empty_layout(self): """Test an out of order ghz state with a layout set.""" circuit = QuantumCircuit() - circuit._layout = Layout() + circuit._layout = TranspileLayout(Layout(), {}) op = Operator.from_circuit(circuit) self.assertEqual(Operator([1]), op) @@ -838,9 +861,104 @@ def test_from_circuit_constructor_empty_layout(self): circuit.h(0) circuit.cx(0, 1) layout = Layout() - with self.assertRaises(KeyError): + with self.assertRaises(IndexError): Operator.from_circuit(circuit, layout=layout) + def test_from_circuit_single_flat_default_register_transpiled(self): + """Test a transpiled circuit with layout set from default register.""" + circuit = QuantumCircuit(5) + circuit.h(3) + circuit.cx(3, 4) + circuit.cx(3, 2) + circuit.cx(3, 0) + circuit.cx(3, 1) + init_layout = Layout( + { + circuit.qubits[0]: 3, + circuit.qubits[1]: 4, + circuit.qubits[2]: 1, + circuit.qubits[3]: 2, + circuit.qubits[4]: 0, + } + ) + tqc = transpile(circuit, initial_layout=init_layout) + result = Operator.from_circuit(tqc) + self.assertTrue(Operator.from_circuit(circuit).equiv(result)) + + def test_from_circuit_loose_bits_transpiled(self): + """Test a transpiled circuit with layout set from loose bits.""" + bits = [Qubit() for _ in range(5)] + circuit = QuantumCircuit() + circuit.add_bits(bits) + circuit.h(3) + circuit.cx(3, 4) + circuit.cx(3, 2) + circuit.cx(3, 0) + circuit.cx(3, 1) + init_layout = Layout( + { + circuit.qubits[0]: 3, + circuit.qubits[1]: 4, + circuit.qubits[2]: 1, + circuit.qubits[3]: 2, + circuit.qubits[4]: 0, + } + ) + tqc = transpile(circuit, initial_layout=init_layout) + result = Operator.from_circuit(tqc) + self.assertTrue(Operator(circuit).equiv(result)) + + def test_from_circuit_multiple_registers_bits_transpiled(self): + """Test a transpiled circuit with layout set from loose bits.""" + regs = [QuantumRegister(1, name=f"custom_reg-{i}") for i in range(5)] + circuit = QuantumCircuit() + for reg in regs: + circuit.add_register(reg) + circuit.h(3) + circuit.cx(3, 4) + circuit.cx(3, 2) + circuit.cx(3, 0) + circuit.cx(3, 1) + tqc = transpile(circuit, initial_layout=[3, 4, 1, 2, 0]) + result = Operator.from_circuit(tqc) + self.assertTrue(Operator(circuit).equiv(result)) + + def test_from_circuit_single_flat_custom_register_transpiled(self): + """Test a transpiled circuit with layout set from loose bits.""" + circuit = QuantumCircuit(QuantumRegister(5, name="custom_reg")) + circuit.h(3) + circuit.cx(3, 4) + circuit.cx(3, 2) + circuit.cx(3, 0) + circuit.cx(3, 1) + tqc = transpile(circuit, initial_layout=[3, 4, 1, 2, 0]) + result = Operator.from_circuit(tqc) + self.assertTrue(Operator(circuit).equiv(result)) + + def test_from_circuit_mixed_reg_loose_bits_transpiled(self): + """Test a transpiled circuit with layout set from loose bits.""" + bits = [Qubit(), Qubit()] + circuit = QuantumCircuit() + circuit.add_bits(bits) + circuit.add_register(QuantumRegister(3, name="a_reg")) + circuit.h(3) + circuit.cx(3, 4) + circuit.cx(3, 2) + circuit.cx(3, 0) + circuit.cx(3, 1) + init_layout = Layout( + { + circuit.qubits[0]: 3, + circuit.qubits[1]: 4, + circuit.qubits[2]: 1, + circuit.qubits[3]: 2, + circuit.qubits[4]: 0, + } + ) + tqc = transpile(circuit, initial_layout=init_layout) + result = Operator.from_circuit(tqc) + self.assertTrue(Operator(circuit).equiv(result)) + if __name__ == "__main__": unittest.main() diff --git a/test/python/transpiler/test_bip_mapping.py b/test/python/transpiler/test_bip_mapping.py index 68101fa58a33..24e6d5233e9c 100644 --- a/test/python/transpiler/test_bip_mapping.py +++ b/test/python/transpiler/test_bip_mapping.py @@ -292,7 +292,7 @@ def test_qubit_subset(self): self.assertTrue(bit_indices[q] in qubit_subset) # ancilla qubits are set in the resulting qubit idle = QuantumRegister(1, name="ancilla") - self.assertEqual(idle[0], actual._layout[2]) + self.assertEqual(idle[0], actual._layout.initial_layout[2]) def test_unconnected_qubit_subset(self): """Fails if qubits in `qubit_subset` are not connected.""" diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 39c6529b7444..7ca6aecdfbb7 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -439,7 +439,7 @@ def test_initial_layout_fully_connected_cm(self, level): self.assertIn("SetLayout", self.passes) self.assertIn("ApplyLayout", self.passes) - self.assertEqual(transpiled._layout, Layout.from_qubit_list([qr[0], qr[1]])) + self.assertEqual(transpiled._layout.initial_layout, Layout.from_qubit_list([qr[0], qr[1]])) @data(0, 1, 2, 3) def test_partial_layout_fully_connected_cm(self, level): @@ -459,7 +459,7 @@ def test_partial_layout_fully_connected_cm(self, level): self.assertIn("ApplyLayout", self.passes) ancilla = QuantumRegister(3, "ancilla") self.assertEqual( - transpiled._layout, + transpiled._layout.initial_layout, Layout.from_qubit_list([ancilla[0], ancilla[1], qr[1], ancilla[2], qr[0]]), ) @@ -537,7 +537,7 @@ def test_layout_1711(self, level): qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) qobj = assemble(qc_b) - self.assertEqual(qc_b._layout._p2v, final_layout) + self.assertEqual(qc_b._layout.initial_layout._p2v, final_layout) compiled_ops = qobj.experiments[0].instructions for operation in compiled_ops: @@ -585,7 +585,7 @@ def test_layout_2532(self, level): qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) - self.assertEqual(qc_b._layout._p2v, final_layout) + self.assertEqual(qc_b._layout.initial_layout._p2v, final_layout) output_qr = qc_b.qregs[0] for instruction in qc_b: @@ -639,7 +639,7 @@ def test_layout_2503(self, level): qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) - self.assertEqual(qc_b._layout._p2v, final_layout) + self.assertEqual(qc_b._layout.initial_layout._p2v, final_layout) output_qr = qc_b.qregs[0] self.assertIsInstance(qc_b[0].operation, U3Gate) @@ -726,7 +726,7 @@ def test_layout_tokyo_2845(self, level): ] backend = FakeTokyo() result = transpile(qc, backend, optimization_level=level, seed_transpiler=42) - self.assertEqual(result._layout._p2v, expected_layouts[level]) + self.assertEqual(result._layout.initial_layout._p2v, expected_layouts[level]) @data(0, 1, 2, 3) def test_layout_tokyo_fully_connected_cx(self, level): @@ -799,7 +799,7 @@ def test_layout_tokyo_fully_connected_cx(self, level): ] backend = FakeTokyo() result = transpile(qc, backend, optimization_level=level, seed_transpiler=42) - self.assertEqual(result._layout._p2v, expected_layouts[level]) + self.assertEqual(result._layout.initial_layout._p2v, expected_layouts[level]) @data(0, 1, 2, 3) def test_all_levels_use_trivial_if_perfect(self, level): @@ -841,7 +841,7 @@ def test_all_levels_use_trivial_if_perfect(self, level): 19: Qubit(QuantumRegister(20, "q"), 19), } trans_qc = transpile(qc, backend, optimization_level=level, seed_transpiler=42) - self.assertEqual(trans_qc._layout._p2v, expected) + self.assertEqual(trans_qc._layout.initial_layout._p2v, expected) @data(0) def test_trivial_layout(self, level): @@ -889,7 +889,7 @@ def test_trivial_layout(self, level): backend = FakeTokyo() result = transpile(qc, backend, optimization_level=level, seed_transpiler=42) - self.assertEqual(result._layout._p2v, expected_layouts[level]) + self.assertEqual(result._layout.initial_layout._p2v, expected_layouts[level]) @data(0, 1, 2, 3) def test_initial_layout(self, level): @@ -926,7 +926,7 @@ def test_initial_layout(self, level): ) for physical, virtual in initial_layout.items(): - self.assertEqual(result._layout._p2v[physical], virtual) + self.assertEqual(result._layout.initial_layout._p2v[physical], virtual) @ddt diff --git a/test/python/transpiler/test_sabre_layout.py b/test/python/transpiler/test_sabre_layout.py index 77aa5af050b3..7aabc5ef1a83 100644 --- a/test/python/transpiler/test_sabre_layout.py +++ b/test/python/transpiler/test_sabre_layout.py @@ -131,7 +131,7 @@ def test_layout_with_classical_bits(self): ) res = transpile(qc, FakeKolkata(), layout_method="sabre", seed_transpiler=1234) self.assertIsInstance(res, QuantumCircuit) - layout = res._layout + layout = res._layout.initial_layout self.assertEqual(layout[qc.qubits[0]], 14) self.assertEqual(layout[qc.qubits[1]], 19) self.assertEqual(layout[qc.qubits[2]], 7) @@ -192,7 +192,7 @@ def test_layout_many_search_trials(self): seed_transpiler=12345, ) self.assertIsInstance(res, QuantumCircuit) - layout = res._layout + layout = res._layout.initial_layout self.assertEqual(layout[qc.qubits[0]], 19) self.assertEqual(layout[qc.qubits[1]], 22) self.assertEqual(layout[qc.qubits[2]], 17) diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py index dc9907d04e06..8a72f3bcf70d 100644 --- a/test/python/visualization/test_circuit_text_drawer.py +++ b/test/python/visualization/test_circuit_text_drawer.py @@ -24,7 +24,7 @@ from qiskit.quantum_info.operators import SuperOp from qiskit.quantum_info.random import random_unitary from qiskit.test import QiskitTestCase -from qiskit.transpiler import Layout +from qiskit.transpiler.layout import Layout, TranspileLayout from qiskit.visualization.circuit import text as elements from qiskit.visualization.circuit.circuit_visualization import _text_circuit_drawer from qiskit.extensions import UnitaryGate, HamiltonianGate @@ -4748,8 +4748,11 @@ def test_partial_layout(self): circuit = QuantumCircuit(pqr) circuit.h(0) circuit.h(3) - circuit._layout = Layout({0: qr[0], 1: None, 2: None, 3: qr[1]}) - circuit._layout.add_register(qr) + circuit._layout = TranspileLayout( + Layout({0: qr[0], 1: None, 2: None, 3: qr[1]}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) + circuit._layout.initial_layout.add_register(qr) self.assertEqual(str(_text_circuit_drawer(circuit)), expected) diff --git a/test/python/visualization/test_gate_map.py b/test/python/visualization/test_gate_map.py index de195594091e..8b07583b6238 100644 --- a/test/python/visualization/test_gate_map.py +++ b/test/python/visualization/test_gate_map.py @@ -32,7 +32,7 @@ ) from qiskit.utils import optionals from qiskit import QuantumRegister, QuantumCircuit -from qiskit.transpiler import Layout +from qiskit.transpiler.layout import Layout, TranspileLayout from .visualization import path_to_diagram_reference, QiskitVisualizationTestCase if optionals.HAS_MATPLOTLIB: @@ -77,8 +77,11 @@ def test_plot_circuit_layout(self, backend): layout_length = int(backend._configuration.n_qubits / 2) qr = QuantumRegister(layout_length, "qr") circuit = QuantumCircuit(qr) - circuit._layout = Layout({qr[i]: i * 2 for i in range(layout_length)}) - circuit._layout.add_register(qr) + circuit._layout = TranspileLayout( + Layout({qr[i]: i * 2 for i in range(layout_length)}), + {qubit: index for index, qubit in enumerate(circuit.qubits)}, + ) + circuit._layout.initial_layout.add_register(qr) n = backend.configuration().n_qubits img_ref = path_to_diagram_reference(str(n) + "_plot_circuit_layout.png") fig = plot_circuit_layout(circuit, backend)