From 0bc89b4a7ce65ebfb2f00267d2f1578223e6ad4e Mon Sep 17 00:00:00 2001 From: Yasuhito Takamiya Date: Tue, 24 Dec 2024 14:35:56 +0900 Subject: [PATCH] set virtual-physical mapping in TranspileResult --- .../transpiler/base_qiskit_transpiler.py | 56 ------------------- src/tranqu/transpiler/ouqu_tp_transpiler.py | 6 +- src/tranqu/transpiler/qiskit_layout_mapper.py | 39 +++++++++++++ src/tranqu/transpiler/qiskit_transpiler.py | 24 ++++++-- .../transpiler/test_ouqu_tp_transpiler.py | 3 + 5 files changed, 65 insertions(+), 63 deletions(-) delete mode 100644 src/tranqu/transpiler/base_qiskit_transpiler.py create mode 100644 src/tranqu/transpiler/qiskit_layout_mapper.py diff --git a/src/tranqu/transpiler/base_qiskit_transpiler.py b/src/tranqu/transpiler/base_qiskit_transpiler.py deleted file mode 100644 index 7cd9aad..0000000 --- a/src/tranqu/transpiler/base_qiskit_transpiler.py +++ /dev/null @@ -1,56 +0,0 @@ -from qiskit import QuantumCircuit # type: ignore[import-untyped] - -from tranqu.transpile_result import TranspileResult - -from .qiskit_stats_extractor import QiskitStatsExtractor -from .transpiler import Transpiler - - -class BaseQiskitTranspiler(Transpiler): - """Provides basic functionality for transpiling Qiskit quantum circuits. - - It includes methods to extract statistics from the transpiled quantum circuit and - create a mapping of virtual qubits to physical qubits. - """ - - def __init__(self) -> None: - self._stats_extractor = QiskitStatsExtractor() - - def _extract_stats_from(self, program: QuantumCircuit) -> dict[str, int]: - return self._stats_extractor.extract_stats_from(program) - - @staticmethod - def _create_mapping_from_layout( - transpiled_program: QuantumCircuit, - ) -> dict[str, dict[int, int]]: - mapping: dict[str, dict[int, int]] = {"qubit_mapping": {}, "bit_mapping": {}} - - layout = transpiled_program.layout - if layout is not None: - final_layout = layout.final_index_layout() - for virtual_bit, physical_bit in enumerate(final_layout): - mapping["qubit_mapping"][virtual_bit] = physical_bit - - if transpiled_program.num_clbits > 0: - mapping["bit_mapping"] = { - i: i for i in range(transpiled_program.num_clbits) - } - else: - for index in range(transpiled_program.num_qubits): - mapping["qubit_mapping"][index] = index - for index in range(transpiled_program.num_clbits): - mapping["bit_mapping"][index] = index - - return mapping - - def _create_transpile_result( - self, - original_program: QuantumCircuit, - transpiled_program: QuantumCircuit, - ) -> TranspileResult: - stats = { - "before": self._extract_stats_from(original_program), - "after": self._extract_stats_from(transpiled_program), - } - mapping = self._create_mapping_from_layout(transpiled_program) - return TranspileResult(transpiled_program, stats, mapping) diff --git a/src/tranqu/transpiler/ouqu_tp_transpiler.py b/src/tranqu/transpiler/ouqu_tp_transpiler.py index 3b638eb..ccba3f5 100644 --- a/src/tranqu/transpiler/ouqu_tp_transpiler.py +++ b/src/tranqu/transpiler/ouqu_tp_transpiler.py @@ -5,6 +5,7 @@ from tranqu.transpile_result import TranspileResult +from .qiskit_layout_mapper import QiskitLayoutMapper from .qiskit_stats_extractor import QiskitStatsExtractor from .transpiler import Transpiler @@ -18,6 +19,7 @@ class OuquTpTranspiler(Transpiler): def __init__(self) -> None: self._ouqu_tp = OuquTp() self._qiskit_stats_extractor = QiskitStatsExtractor() + self._layout_mapper = QiskitLayoutMapper() def transpile( self, @@ -52,4 +54,6 @@ def transpile( ), } - return TranspileResult(transpile_response.qasm, stats, {}) + mapping = self._layout_mapper.create_mapping_from_layout(transpiled_circuit) + + return TranspileResult(transpile_response.qasm, stats, mapping) diff --git a/src/tranqu/transpiler/qiskit_layout_mapper.py b/src/tranqu/transpiler/qiskit_layout_mapper.py new file mode 100644 index 0000000..81bef2f --- /dev/null +++ b/src/tranqu/transpiler/qiskit_layout_mapper.py @@ -0,0 +1,39 @@ +from qiskit import QuantumCircuit # type: ignore[import-untyped] + + +class QiskitLayoutMapper: + """Maps virtual qubits to physical qubits for Qiskit quantum circuits.""" + + @staticmethod + def create_mapping_from_layout( + transpiled_circuit: QuantumCircuit, + ) -> dict[str, dict[int, int]]: + """Create a mapping between virtual and physical (qu)bits. + + Args: + transpiled_circuit (QuantumCircuit): The transpiled quantum circuit. + + Returns: + dict[str, dict[int, int]]: A dictionary containing the mapping between + virtual and physical qubits and classical bits. + + """ + mapping: dict[str, dict[int, int]] = {"qubit_mapping": {}, "bit_mapping": {}} + + layout = transpiled_circuit.layout + if layout is not None: + final_layout = layout.final_index_layout() + for virtual_bit, physical_bit in enumerate(final_layout): + mapping["qubit_mapping"][virtual_bit] = physical_bit + + if transpiled_circuit.num_clbits > 0: + mapping["bit_mapping"] = { + i: i for i in range(transpiled_circuit.num_clbits) + } + else: + for index in range(transpiled_circuit.num_qubits): + mapping["qubit_mapping"][index] = index + for index in range(transpiled_circuit.num_clbits): + mapping["bit_mapping"][index] = index + + return mapping diff --git a/src/tranqu/transpiler/qiskit_transpiler.py b/src/tranqu/transpiler/qiskit_transpiler.py index 2c49235..c02fd47 100644 --- a/src/tranqu/transpiler/qiskit_transpiler.py +++ b/src/tranqu/transpiler/qiskit_transpiler.py @@ -1,20 +1,25 @@ -import copy from typing import Any from qiskit import QuantumCircuit # type: ignore[import-untyped] -from qiskit import transpile as qiskit_transpile +from qiskit import transpile as qiskit_transpile # type: ignore[import-untyped] from tranqu.transpile_result import TranspileResult -from .base_qiskit_transpiler import BaseQiskitTranspiler +from .qiskit_layout_mapper import QiskitLayoutMapper +from .qiskit_stats_extractor import QiskitStatsExtractor +from .transpiler import Transpiler -class QiskitTranspiler(BaseQiskitTranspiler): +class QiskitTranspiler(Transpiler): """Transpile quantum circuits using Qiskit. It optimizes quantum circuits using Qiskit's `transpile()` function. """ + def __init__(self) -> None: + self._stats_extractor = QiskitStatsExtractor() + self._layout_mapper = QiskitLayoutMapper() + def transpile( self, program: QuantumCircuit, @@ -36,9 +41,16 @@ def transpile( and the mapping of virtual qubits to physical qubits. """ - _options = copy.deepcopy(options or {}) + _options = options or {} if device is not None: _options["backend"] = device transpiled_program = qiskit_transpile(program, **_options) - return self._create_transpile_result(program, transpiled_program) + + stats = { + "before": self._stats_extractor.extract_stats_from(program), + "after": self._stats_extractor.extract_stats_from(transpiled_program), + } + mapping = self._layout_mapper.create_mapping_from_layout(transpiled_program) + + return TranspileResult(transpiled_program, stats, mapping) diff --git a/tests/tranqu/transpiler/test_ouqu_tp_transpiler.py b/tests/tranqu/transpiler/test_ouqu_tp_transpiler.py index 899110e..5968667 100644 --- a/tests/tranqu/transpiler/test_ouqu_tp_transpiler.py +++ b/tests/tranqu/transpiler/test_ouqu_tp_transpiler.py @@ -58,6 +58,7 @@ def test_transpile_simple_qasm3_program( assert isinstance(result.transpiled_program, str) assert result.stats != {} + assert result.virtual_physical_mapping != {} def test_transpile_qiskit_program( self, tranqu: Tranqu, simple_device: dict[str, Any] @@ -76,6 +77,7 @@ def test_transpile_qiskit_program( assert isinstance(result.transpiled_program, QuantumCircuit) assert result.stats != {} + assert result.virtual_physical_mapping != {} def test_transpile_tket_program( self, tranqu: Tranqu, simple_device: dict[str, Any] @@ -94,3 +96,4 @@ def test_transpile_tket_program( assert isinstance(result.transpiled_program, TketCircuit) assert result.stats != {} + assert result.virtual_physical_mapping != {}