From 4587384b63e894a60dc57fbd790b189c6be2d709 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 10 Nov 2023 17:39:01 +0900 Subject: [PATCH 01/22] add description if no description is provided, build coupling map if it is provided --- qiskit_aer/backends/aer_simulator.py | 22 +++++++++--- qiskit_aer/backends/aerbackend.py | 46 ++++++++----------------- qiskit_aer/backends/name_mapping.py | 51 ++++++++++------------------ 3 files changed, 50 insertions(+), 69 deletions(-) diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index 2ede8e3bbb..04fc439592 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -695,7 +695,9 @@ class AerSimulator(AerBackend): _AVAILABLE_DEVICES = None - def __init__(self, configuration=None, properties=None, provider=None, **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, target=None, **backend_options + ): self._controller = aer_controller_execute() # Update available methods and devices for class @@ -717,7 +719,11 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend self._cached_basis_gates = self._BASIS_GATES["automatic"] super().__init__( - configuration, properties=properties, provider=provider, backend_options=backend_options + configuration, + properties=properties, + provider=provider, + target=target, + backend_options=backend_options, ) @classmethod @@ -812,6 +818,11 @@ def _name(self): def from_backend(cls, backend, **options): """Initialize simulator from backend.""" if isinstance(backend, BackendV2): + if backend.description is None: + description = "created by AerSimulator.from_backend" + else: + description = backend.description + configuration = QasmBackendConfiguration( backend_name=f"'aer_simulator({backend.name})", backend_version=backend.backend_version, @@ -826,9 +837,10 @@ def from_backend(cls, backend, **options): max_shots=int(1e6), coupling_map=list(backend.coupling_map.get_edges()), max_experiments=backend.max_circuits, - description=backend.description, + description=description, ) properties = target_to_backend_properties(backend.target) + target = backend.target elif isinstance(backend, BackendV1): # Get configuration and properties from backend configuration = copy.copy(backend.configuration()) @@ -837,6 +849,8 @@ def from_backend(cls, backend, **options): # Customize configuration name name = configuration.backend_name configuration.backend_name = f"aer_simulator({name})" + + target = None else: raise TypeError( "The backend argument requires a BackendV2 or BackendV1 object, " @@ -853,7 +867,7 @@ def from_backend(cls, backend, **options): options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, properties=properties, **options) + sim = cls(configuration=configuration, properties=properties, target=target, **options) return sim def available_methods(self): diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 22f620ba77..71e6d511c6 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -36,6 +36,7 @@ from .aer_compiler import compile_circuit, assemble_circuits, generate_aer_config from .backend_utils import format_save_type, circuit_optypes from .name_mapping import NAME_MAPPING +from qiskit.transpiler import CouplingMap # pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import AerConfig @@ -48,7 +49,7 @@ class AerBackend(Backend, ABC): """Aer Backend class.""" def __init__( - self, configuration, properties=None, defaults=None, backend_options=None, provider=None + self, configuration, properties=None, provider=None, target=None, backend_options=None ): """Aer class for backends. @@ -59,8 +60,8 @@ def __init__( Args: configuration (BackendConfiguration): backend configuration. properties (BackendProperties or None): Optional, backend properties. - defaults (PulseDefaults or None): Optional, backend pulse defaults. provider (Provider): Optional, provider responsible for this backend. + target (Target): initial target for backend backend_options (dict or None): Optional set custom backend options. Raises: @@ -76,22 +77,24 @@ def __init__( backend_version=configuration.backend_version, ) - # Initialize backend properties and pulse defaults. + # Initialize backend properties self._properties = properties - self._defaults = defaults self._configuration = configuration - # Custom option values for config, properties, and defaults + # Custom option values for config, properties self._options_configuration = {} - self._options_defaults = {} self._options_properties = {} - self._target = None + self._target = target self._mapping = NAME_MAPPING # Set options from backend_options dictionary if backend_options is not None: self.set_options(**backend_options) + # build coupling map + if self.configuration().coupling_map is not None: + self._coupling_map = CouplingMap(self.configuration().coupling_map) + def _convert_circuit_binds(self, circuit, binds, idx_map): parameterizations = [] @@ -330,18 +333,6 @@ def properties(self): setattr(properties, key, val) return properties - def defaults(self): - """Return the simulator backend pulse defaults. - - Returns: - PulseDefaults: The backend pulse defaults or ``None`` if the - backend does not support pulse. - """ - defaults = copy.copy(self._defaults) - for key, val in self._options_defaults.items(): - setattr(defaults, key, val) - return defaults - @property def max_circuits(self): if hasattr(self.configuration(), "max_experiments"): @@ -351,9 +342,10 @@ def max_circuits(self): @property def target(self): - self._target = convert_to_target( - self.configuration(), self.properties(), self.defaults(), self._mapping - ) + if self._target is None: + self._target = convert_to_target( + self.configuration(), self.properties(), None, self._mapping + ) return self._target def clear_options(self): @@ -361,7 +353,6 @@ def clear_options(self): self._options = self._default_options() self._options_configuration = {} self._options_properties = {} - self._options_defaults = {} def status(self): """Return backend status. @@ -702,8 +693,6 @@ def set_option(self, key, value): self._set_configuration_option(key, value) elif hasattr(self._properties, key): self._set_properties_option(key, value) - elif hasattr(self._defaults, key): - self._set_defaults_option(key, value) else: if not hasattr(self._options, key): raise AerError(f"Invalid option {key}") @@ -735,13 +724,6 @@ def _set_properties_option(self, key, value): elif key in self._options_properties: self._options_properties.pop(key) - def _set_defaults_option(self, key, value): - """Special handling for setting backend defaults options.""" - if value is not None: - self._options_defaults[key] = value - elif key in self._options_defaults: - self._options_defaults.pop(key) - def __repr__(self): """String representation of an AerBackend.""" name = self.__class__.__name__ diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index 0caadc1999..ed4e3923d2 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -17,21 +17,21 @@ from qiskit.circuit import ControlledGate, Parameter from qiskit.circuit.reset import Reset from qiskit.circuit.library import ( - SXGate, + CSXGate, MCPhaseGate, MCXGate, - RZGate, - RXGate, + CRZGate, + CRXGate, + MCU1Gate, U2Gate, - U1Gate, - U3Gate, - YGate, - ZGate, + CU3Gate, + CYGate, + CZGate, PauliGate, - SwapGate, + CSwapGate, RGate, MCXGrayCode, - RYGate, + CRYGate, ) from qiskit.circuit.controlflow import ( IfElseOp, @@ -85,7 +85,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=SXGate(), + base_gate=CSXGate(), ) @@ -100,7 +100,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=YGate(), + base_gate=CYGate(), ) @@ -115,7 +115,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=ZGate(), + base_gate=CZGate(), ) @@ -130,7 +130,7 @@ def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=RXGate(theta), + base_gate=CRXGate(theta), ) @@ -145,7 +145,7 @@ def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=RYGate(theta), + base_gate=CRYGate(theta), ) @@ -160,7 +160,7 @@ def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=RZGate(theta), + base_gate=CRZGate(theta), ) @@ -179,21 +179,6 @@ def __init__(self, theta, phi, num_ctrl_qubits, ctrl_state=None): ) -class MCU1Gate(ControlledGate): - """mcu1 gate""" - - def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): - super().__init__( - "mcu1", - 1 + num_ctrl_qubits, - [theta], - None, - num_ctrl_qubits, - ctrl_state=ctrl_state, - base_gate=U1Gate(theta), - ) - - class MCU2Gate(ControlledGate): """mcu2 gate""" @@ -220,7 +205,7 @@ def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=U3Gate(theta, phi, lam), + base_gate=CU3Gate(theta, phi, lam), ) @@ -235,7 +220,7 @@ def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=U3Gate(theta, phi, lam), + base_gate=CU3Gate(theta, phi, lam), ) @@ -250,7 +235,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): None, num_ctrl_qubits, ctrl_state=ctrl_state, - base_gate=SwapGate(), + base_gate=CSwapGate(), ) From 45cde5b03213fb8ff0d48cccdec10197f53ac31b Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 10 Nov 2023 17:47:54 +0900 Subject: [PATCH 02/22] move import line --- qiskit_aer/backends/aerbackend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 71e6d511c6..de090c8724 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -29,6 +29,7 @@ from qiskit.pulse import Schedule, ScheduleBlock from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result +from qiskit.transpiler import CouplingMap from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj from ..noise.noise_model import NoiseModel, QuantumErrorLocation @@ -36,7 +37,6 @@ from .aer_compiler import compile_circuit, assemble_circuits, generate_aer_config from .backend_utils import format_save_type, circuit_optypes from .name_mapping import NAME_MAPPING -from qiskit.transpiler import CouplingMap # pylint: disable=import-error, no-name-in-module, abstract-method from .controller_wrappers import AerConfig From b94fd93774fa358bb8be526aa498745a7a5832c5 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 15 Nov 2023 13:36:11 +0900 Subject: [PATCH 03/22] fix target for simulator backend --- qiskit_aer/backends/aerbackend.py | 32 +++++++++++++++++++++++++++++-- setup.py | 2 ++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index de090c8724..f10c849ae8 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -30,6 +30,8 @@ from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result from qiskit.transpiler import CouplingMap +from qiskit.transpiler.target import Target +from qiskit.circuit.measure import Measure from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj from ..noise.noise_model import NoiseModel, QuantumErrorLocation @@ -343,9 +345,35 @@ def max_circuits(self): @property def target(self): if self._target is None: - self._target = convert_to_target( - self.configuration(), self.properties(), None, self._mapping + # build target for simulator + target = Target( + num_qubits=self.configuration().n_qubits, + concurrent_measurements=getattr(self.configuration(), "meas_map", None), ) + + if hasattr(self.configuration(), "dt"): + target.dt = self.configuration().dt + if hasattr(self.configuration(), "timing_constraints"): + target.granularity = self.configuration().timing_constraints.get("granularity") + target.min_length = self.configuration().timing_constraints.get("min_length") + target.pulse_alignment = self.configuration().timing_constraints.get( + "pulse_alignment" + ) + target.acquire_alignment = self.configuration().timing_constraints.get( + "acquire_alignment" + ) + + combined_global_ops = set() + if self.configuration().basis_gates: + combined_global_ops.update(self.configuration().basis_gates) + for op in combined_global_ops: + if op not in target: + if op in self._mapping: + target.add_instruction(self._mapping[op], name=op) + target.add_instruction(Measure()) + + self._target = target + return self._target def clear_options(self): diff --git a/setup.py b/setup.py index d2a67e87f3..80fdcad4a4 100644 --- a/setup.py +++ b/setup.py @@ -90,6 +90,8 @@ if is_win_32_bit: cmake_args.append("-DCMAKE_GENERATOR_PLATFORM=Win32") + + setup( name=PACKAGE_NAME, version=VERSION, From 55b635b57aca3ec6b3ba1fe9039cdf2cb648ef93 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 15 Nov 2023 13:40:19 +0900 Subject: [PATCH 04/22] format --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 80fdcad4a4..fae361e817 100644 --- a/setup.py +++ b/setup.py @@ -91,7 +91,6 @@ cmake_args.append("-DCMAKE_GENERATOR_PLATFORM=Win32") - setup( name=PACKAGE_NAME, version=VERSION, From acda9472b0e8419690f9098d788c56362af8fb88 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 15 Nov 2023 13:46:25 +0900 Subject: [PATCH 05/22] remove unused import --- qiskit_aer/backends/aerbackend.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index f10c849ae8..05928026f5 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -24,7 +24,6 @@ from qiskit.circuit import QuantumCircuit, ParameterExpression, Delay from qiskit.compiler import assemble from qiskit.providers import BackendV2 as Backend -from qiskit.providers import convert_to_target from qiskit.providers.models import BackendStatus from qiskit.pulse import Schedule, ScheduleBlock from qiskit.qobj import QasmQobj, PulseQobj From e8f43bffba060daa3f784c07e7a5237b0ba510a6 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 10:53:58 +0900 Subject: [PATCH 06/22] use translation plugin to rebuild gate sets for simulator --- qiskit_aer/backends/aerbackend.py | 58 +++++---- qiskit_aer/backends/name_mapping.py | 121 +++++++++++++----- qiskit_aer/backends/plugin/__init__.py | 0 .../backends/plugin/aer_backend_plugin.py | 47 +++++++ setup.py | 5 + 5 files changed, 174 insertions(+), 57 deletions(-) create mode 100644 qiskit_aer/backends/plugin/__init__.py create mode 100644 qiskit_aer/backends/plugin/aer_backend_plugin.py diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 05928026f5..6479b48d93 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -29,7 +29,7 @@ from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result from qiskit.transpiler import CouplingMap -from qiskit.transpiler.target import Target +from qiskit.transpiler.target import Target, InstructionProperties from qiskit.circuit.measure import Measure from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj @@ -343,37 +343,32 @@ def max_circuits(self): @property def target(self): - if self._target is None: - # build target for simulator - target = Target( - num_qubits=self.configuration().n_qubits, - concurrent_measurements=getattr(self.configuration(), "meas_map", None), - ) + if self._target is not None: + return self._target - if hasattr(self.configuration(), "dt"): - target.dt = self.configuration().dt - if hasattr(self.configuration(), "timing_constraints"): - target.granularity = self.configuration().timing_constraints.get("granularity") - target.min_length = self.configuration().timing_constraints.get("min_length") - target.pulse_alignment = self.configuration().timing_constraints.get( - "pulse_alignment" - ) - target.acquire_alignment = self.configuration().timing_constraints.get( - "acquire_alignment" - ) + # build target for simulator + target = Target( + num_qubits=self.configuration().n_qubits, + concurrent_measurements=getattr(self.configuration(), "meas_map", None), + ) - combined_global_ops = set() - if self.configuration().basis_gates: - combined_global_ops.update(self.configuration().basis_gates) - for op in combined_global_ops: - if op not in target: - if op in self._mapping: - target.add_instruction(self._mapping[op], name=op) - target.add_instruction(Measure()) + if hasattr(self.configuration(), "dt"): + target.dt = self.configuration().dt + if hasattr(self.configuration(), "timing_constraints"): + target.granularity = self.configuration().timing_constraints.get("granularity") + target.min_length = self.configuration().timing_constraints.get("min_length") + target.pulse_alignment = self.configuration().timing_constraints.get("pulse_alignment") + target.acquire_alignment = self.configuration().timing_constraints.get( + "acquire_alignment" + ) - self._target = target + for op in self.configuration().basis_gates: + if op not in target: + if op in self._mapping: + target.add_instruction(self._mapping[op], name=op) + target.add_instruction(Measure()) - return self._target + return target def clear_options(self): """Reset the simulator options to default values.""" @@ -756,3 +751,10 @@ def __repr__(self): name = self.__class__.__name__ display = f"'{self.name}'" return f"{name}({display})" + + def get_translation_stage_plugin(self): + if self._target is None: + # use plugin to prevent gate change + return "aer_backend_plugin" + else: + return None diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index ed4e3923d2..649474ce62 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -17,21 +17,50 @@ from qiskit.circuit import ControlledGate, Parameter from qiskit.circuit.reset import Reset from qiskit.circuit.library import ( + U1Gate, + U2Gate, + U3Gate, + UGate, + PhaseGate, + RGate, + RXGate, + RXXGate, + RYGate, + RYYGate, + RZGate, + RZZGate, + RZXGate, + IGate, + HGate, + XGate, + YGate, + ZGate, + SGate, + SdgGate, + SXGate, + SXdgGate, + TGate, + TdgGate, + SwapGate, + CXGate, + CYGate, + CZGate, CSXGate, + CUGate, + CU1Gate, + CU3Gate, + CSwapGate, + ECRGate, + PauliGate, + DiagonalGate, + UnitaryGate, MCPhaseGate, MCXGate, - CRZGate, CRXGate, + CRYGate, + CRZGate, MCU1Gate, - U2Gate, - CU3Gate, - CYGate, - CZGate, - PauliGate, - CSwapGate, - RGate, MCXGrayCode, - CRYGate, ) from qiskit.circuit.controlflow import ( IfElseOp, @@ -242,26 +271,70 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): PHI = Parameter("phi") LAM = Parameter("lam") NAME_MAPPING = { + "u1": U1Gate, + "u2": U2Gate, + "u3": U3Gate, + "u": UGate, + "p": PhaseGate, + "r": RGate, + "rx": RXGate, + "rxx": RXXGate, + "ry": RYGate, + "ryy": RYYGate, + "rz": RZGate, + "rzz": RZZGate, + "rz": RZXGate, + "id": IGate, + "h": HGate, + "x": XGate(), + "y": YGate, + "z": ZGate, + "s": SGate, + "sdg": SdgGate, + "sx": SXGate, + "sxdg": SXdgGate, + "t": TGate, + "tdg": TdgGate, + "swap": SwapGate, + "cx": CXGate, + "cy": CYGate, + "cz": CZGate, + "csx": CSXGate, + "cu": CUGate, + "cu1": CU1Gate, + "cu2": U2Gate(PHI, LAM).control(), + "cu3": CU3Gate, + "cswap": CSwapGate, + "ecr": ECRGate, + "pauli": PauliGate, + "diagonal": DiagonalGate, + "unitary": UnitaryGate, "mcsx": MCSXGate, "mcp": MCPhaseGate, "mcphase": MCPhaseGate, + "mcu": MCUGate, + "mcu1": MCU1Gate, + "mcu2": MCU2Gate, + "mcu3": MCU3Gate, + "mcx": MCXGate, + "mcy": MCYGate, + "mcz": MCZGate, + "mcr": MCRGate, + "mcrx": MCRXGate, + "mcry": MCRYGate, + "mcrz": MCRZGate, + "mcx_gray": MCXGrayCode, + "mcswap": MCSwapGate, + "multiplexer": UCGate, + "kraus": Kraus, + "superop": SuperOp, "initialize": Initialize, "quantum_channel": QuantumChannel, "save_expval": SaveExpectationValue, - "diagonal": DiagonalGate, "save_amplitudes": SaveAmplitudes, "roerror": ReadoutError, - "mcrx": MCRXGate, - "kraus": Kraus, "save_statevector_dict": SaveStatevectorDict, - "mcx": MCXGate, - "mcu1": MCU1Gate, - "mcu2": MCU2Gate, - "mcu3": MCU3Gate, "save_superop": SaveSuperOp, - "multiplexer": UCGate, - "mcy": MCYGate, - "superop": SuperOp, "save_clifford": SaveClifford, "save_matrix_product_state": SaveMatrixProductState, "save_density_matrix": SaveDensityMatrix, @@ -273,30 +346,20 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "break_loop": BreakLoopOp, "continue_loop": ContinueLoopOp, "save_statevector": SaveStatevector, - "mcu": MCUGate, "set_density_matrix": SetDensityMatrix, "qerror_loc": QuantumErrorLocation, - "unitary": UnitaryGate, - "mcz": MCZGate, - "pauli": PauliGate, "set_unitary": SetUnitary, "save_state": SaveState, - "mcswap": MCSwapGate, "set_matrix_product_state": SetMatrixProductState, "save_unitary": SaveUnitary, - "mcr": MCRGate, - "mcx_gray": MCXGrayCode, - "mcrz": MCRZGate, "set_superop": SetSuperOp, "save_expval_var": SaveExpectationValueVariance, "save_stabilizer": SaveStabilizer, "set_statevector": SetStatevector, - "mcry": MCRYGate, "set_stabilizer": SetStabilizer, "save_amplitudes_sq": SaveAmplitudesSquared, "save_probabilities_dict": SaveProbabilitiesDict, "save_probs_ket": SaveProbabilitiesDict, "save_probs": SaveProbabilities, - "cu2": U2Gate(PHI, LAM).control(), "reset": Reset(), } diff --git a/qiskit_aer/backends/plugin/__init__.py b/qiskit_aer/backends/plugin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py new file mode 100644 index 0000000000..ce38a19b45 --- /dev/null +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -0,0 +1,47 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2018, 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" +Aer simulator backend transpiler plug-in +""" +from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin +from qiskit.transpiler.preset_passmanagers import common +from qiskit.transpiler import PassManager, TransformationPass, PassManagerConfig +from qiskit.circuit.measure import Measure +from qiskit_aer.backends.name_mapping import NAME_MAPPING + + +class AerNoTranslation(TransformationPass): + def __init__(self, config): + super().__init__() + self.config = config + + def run(self, dag): + # clear all instructions in target + self.config.target._gate_map.clear() + self.config.target._gate_name_map.clear() + self.config.target._qarg_gate_map.clear() + self.config.target._global_operations.clear() + + # rebuild gate sets from circuit + opnodes = dag.op_nodes() + for node in opnodes: + if node.name not in self.config.target: + if node.name in NAME_MAPPING: + self.config.target.add_instruction(NAME_MAPPING[node.name], name=node.name) + self.config.target.add_instruction(Measure()) + + return dag + + +class AerBackendPlugin(PassManagerStagePlugin): + def pass_manager(self, pass_manager_config, optimization_level): + return PassManager([AerNoTranslation(config=pass_manager_config)]) diff --git a/setup.py b/setup.py index fae361e817..0302972e25 100644 --- a/setup.py +++ b/setup.py @@ -112,4 +112,9 @@ cmake_args=cmake_args, keywords="qiskit, simulator, quantum computing, backend", zip_safe=False, + entry_points={ + "qiskit.transpiler.translation": [ + "aer_backend_plugin = qiskit_aer.backends.plugin.aer_backend_plugin:AerBackendPlugin", + ] + }, ) From dbb87b46a419873aa0931786a57565567f9d59d8 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 10:57:42 +0900 Subject: [PATCH 07/22] rename plugin --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index ce38a19b45..408f16526e 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -19,7 +19,7 @@ from qiskit_aer.backends.name_mapping import NAME_MAPPING -class AerNoTranslation(TransformationPass): +class AerBackendRebuildGateSetsFromCircuit(TransformationPass): def __init__(self, config): super().__init__() self.config = config @@ -44,4 +44,4 @@ def run(self, dag): class AerBackendPlugin(PassManagerStagePlugin): def pass_manager(self, pass_manager_config, optimization_level): - return PassManager([AerNoTranslation(config=pass_manager_config)]) + return PassManager([AerBackendRebuildGateSetsFromCircuit(config=pass_manager_config)]) From 5ea99e3f513c7ee3266ffeeb604d1bc7a45fda07 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 11:08:26 +0900 Subject: [PATCH 08/22] rebuild of gate sets is eanbled only for opt level 0 and 1 --- qiskit_aer/backends/aerbackend.py | 2 +- qiskit_aer/backends/name_mapping.py | 6 +++--- .../backends/plugin/aer_backend_plugin.py | 18 ++++++++++++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 6479b48d93..aaa960e8d7 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -29,7 +29,7 @@ from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result from qiskit.transpiler import CouplingMap -from qiskit.transpiler.target import Target, InstructionProperties +from qiskit.transpiler.target import Target from qiskit.circuit.measure import Measure from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index 649474ce62..0bb809d1a1 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -70,8 +70,8 @@ BreakLoopOp, SwitchCaseOp, ) -from qiskit.extensions import Initialize, UnitaryGate -from qiskit.extensions.quantum_initializer import DiagonalGate, UCGate +from qiskit.extensions import Initialize +from qiskit.extensions.quantum_initializer import UCGate from qiskit.quantum_info.operators.channel.kraus import Kraus from qiskit.quantum_info.operators.channel import SuperOp from qiskit.quantum_info.operators.channel.quantum_channel import QuantumChannel @@ -283,7 +283,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "ryy": RYYGate, "rz": RZGate, "rzz": RZZGate, - "rz": RZXGate, + "rzx": RZXGate, "id": IGate, "h": HGate, "x": XGate(), diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 408f16526e..b0f3edef07 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -13,18 +13,22 @@ Aer simulator backend transpiler plug-in """ from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin -from qiskit.transpiler.preset_passmanagers import common -from qiskit.transpiler import PassManager, TransformationPass, PassManagerConfig +from qiskit.transpiler import PassManager, TransformationPass from qiskit.circuit.measure import Measure from qiskit_aer.backends.name_mapping import NAME_MAPPING class AerBackendRebuildGateSetsFromCircuit(TransformationPass): - def __init__(self, config): + def __init__(self, config, opt_lvl): super().__init__() self.config = config + self.optimization_level = opt_lvl def run(self, dag): + # do nothing for higher optimization level + if self.optimization_level > 1: + return dag + # clear all instructions in target self.config.target._gate_map.clear() self.config.target._gate_name_map.clear() @@ -44,4 +48,10 @@ def run(self, dag): class AerBackendPlugin(PassManagerStagePlugin): def pass_manager(self, pass_manager_config, optimization_level): - return PassManager([AerBackendRebuildGateSetsFromCircuit(config=pass_manager_config)]) + return PassManager( + [ + AerBackendRebuildGateSetsFromCircuit( + config=pass_manager_config, opt_lvl=optimization_level + ) + ] + ) From 8d1434529ca6cf547a33af716953991fb1c58fce Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 17:46:30 +0900 Subject: [PATCH 09/22] fix custom pass manager --- qiskit_aer/backends/aer_simulator.py | 8 +++ qiskit_aer/backends/aerbackend.py | 29 ++-------- qiskit_aer/backends/name_mapping.py | 2 + .../backends/plugin/aer_backend_plugin.py | 54 ++++++++++++++++--- qiskit_aer/backends/qasm_simulator.py | 1 + 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index 04fc439592..a247b1354c 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -518,6 +518,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "barrier", ] ), "density_matrix": sorted( @@ -542,6 +543,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "barrier", ] ), "matrix_product_state": sorted( @@ -568,6 +570,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "barrier", ] ), "stabilizer": sorted( @@ -591,6 +594,7 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", + "barrier", ] ), "extended_stabilizer": sorted( @@ -600,6 +604,7 @@ class AerSimulator(AerBackend): "roerror", "save_statevector", "reset", + "barrier", ] ), "unitary": sorted( @@ -608,6 +613,7 @@ class AerSimulator(AerBackend): "save_unitary", "set_unitary", "reset", + "barrier", ] ), "superop": sorted( @@ -620,6 +626,7 @@ class AerSimulator(AerBackend): "save_superop", "set_superop", "reset", + "barrier", ] ), "tensor_network": sorted( @@ -643,6 +650,7 @@ class AerSimulator(AerBackend): "set_density_matrix", "reset", "switch_case", + "barrier", ] ), } diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index aaa960e8d7..36545ffe8c 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -24,13 +24,12 @@ from qiskit.circuit import QuantumCircuit, ParameterExpression, Delay from qiskit.compiler import assemble from qiskit.providers import BackendV2 as Backend +from qiskit.providers import convert_to_target from qiskit.providers.models import BackendStatus from qiskit.pulse import Schedule, ScheduleBlock from qiskit.qobj import QasmQobj, PulseQobj from qiskit.result import Result from qiskit.transpiler import CouplingMap -from qiskit.transpiler.target import Target -from qiskit.circuit.measure import Measure from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj from ..noise.noise_model import NoiseModel, QuantumErrorLocation @@ -346,29 +345,7 @@ def target(self): if self._target is not None: return self._target - # build target for simulator - target = Target( - num_qubits=self.configuration().n_qubits, - concurrent_measurements=getattr(self.configuration(), "meas_map", None), - ) - - if hasattr(self.configuration(), "dt"): - target.dt = self.configuration().dt - if hasattr(self.configuration(), "timing_constraints"): - target.granularity = self.configuration().timing_constraints.get("granularity") - target.min_length = self.configuration().timing_constraints.get("min_length") - target.pulse_alignment = self.configuration().timing_constraints.get("pulse_alignment") - target.acquire_alignment = self.configuration().timing_constraints.get( - "acquire_alignment" - ) - - for op in self.configuration().basis_gates: - if op not in target: - if op in self._mapping: - target.add_instruction(self._mapping[op], name=op) - target.add_instruction(Measure()) - - return target + return convert_to_target(self.configuration(), self.properties(), None, NAME_MAPPING) def clear_options(self): """Reset the simulator options to default values.""" @@ -753,8 +730,8 @@ def __repr__(self): return f"{name}({display})" def get_translation_stage_plugin(self): + """use custom translation method to avoid gate exchange""" if self._target is None: - # use plugin to prevent gate change return "aer_backend_plugin" else: return None diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index 0bb809d1a1..de935f5281 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -61,6 +61,7 @@ CRZGate, MCU1Gate, MCXGrayCode, + Barrier, ) from qiskit.circuit.controlflow import ( IfElseOp, @@ -362,4 +363,5 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "save_probs_ket": SaveProbabilitiesDict, "save_probs": SaveProbabilities, "reset": Reset(), + "barrier": Barrier, } diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index b0f3edef07..943e92ebcd 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -14,11 +14,17 @@ """ from qiskit.transpiler.preset_passmanagers.plugin import PassManagerStagePlugin from qiskit.transpiler import PassManager, TransformationPass +from qiskit.transpiler.passes import BasisTranslator +from qiskit.transpiler.passes import UnitarySynthesis +from qiskit.transpiler.passes import HighLevelSynthesis +from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel from qiskit.circuit.measure import Measure from qiskit_aer.backends.name_mapping import NAME_MAPPING class AerBackendRebuildGateSetsFromCircuit(TransformationPass): + """custom translation class to rebuild basis gates with gates in circuit""" + def __init__(self, config, opt_lvl): super().__init__() self.config = config @@ -29,6 +35,23 @@ def run(self, dag): if self.optimization_level > 1: return dag + # search ops in supported name mapping + ops = [] + num_unsupported_ops = 0 + opnodes = dag.op_nodes() + for node in opnodes: + if node.name in self.config.target: + if node.name not in ops: + ops.append(node.name) + else: + num_unsupported_ops = num_unsupported_ops + 1 + + # if there are some unsupported node (i.e. RealAmplitudes) do nothing + if num_unsupported_ops > 0: + return dag + if len(ops) < 1: + return dag + # clear all instructions in target self.config.target._gate_map.clear() self.config.target._gate_name_map.clear() @@ -36,22 +59,41 @@ def run(self, dag): self.config.target._global_operations.clear() # rebuild gate sets from circuit - opnodes = dag.op_nodes() - for node in opnodes: - if node.name not in self.config.target: - if node.name in NAME_MAPPING: - self.config.target.add_instruction(NAME_MAPPING[node.name], name=node.name) + for name in ops: + if name not in self.config.target: + if name != "measure": + self.config.target.add_instruction(NAME_MAPPING[name], name=name) self.config.target.add_instruction(Measure()) return dag class AerBackendPlugin(PassManagerStagePlugin): + """custom passmanager to avoid unnecessary gate changes""" + def pass_manager(self, pass_manager_config, optimization_level): return PassManager( [ + UnitarySynthesis( + pass_manager_config.basis_gates, + approximation_degree=pass_manager_config.approximation_degree, + coupling_map=pass_manager_config.coupling_map, + backend_props=pass_manager_config.backend_properties, + plugin_config=pass_manager_config.unitary_synthesis_plugin_config, + method=pass_manager_config.unitary_synthesis_method, + target=pass_manager_config.target, + ), + HighLevelSynthesis( + hls_config=pass_manager_config.hls_config, + coupling_map=pass_manager_config.coupling_map, + target=pass_manager_config.target, + use_qubit_indices=True, + equivalence_library=sel, + basis_gates=pass_manager_config.basis_gates, + ), + BasisTranslator(sel, pass_manager_config.basis_gates, pass_manager_config.target), AerBackendRebuildGateSetsFromCircuit( config=pass_manager_config, opt_lvl=optimization_level - ) + ), ] ) diff --git a/qiskit_aer/backends/qasm_simulator.py b/qiskit_aer/backends/qasm_simulator.py index d73938a6b9..d0fb21e887 100644 --- a/qiskit_aer/backends/qasm_simulator.py +++ b/qiskit_aer/backends/qasm_simulator.py @@ -389,6 +389,7 @@ class QasmSimulator(AerBackend): "set_density_matrix", "set_stabilizer", "reset", + "barrier", ] ) From a463e1d6d0502a972575bb1120dce863820b278b Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 17:55:58 +0900 Subject: [PATCH 10/22] fix pass_manager function --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 2 +- qiskit_aer/backends/statevector_simulator.py | 1 + qiskit_aer/backends/unitary_simulator.py | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 943e92ebcd..c281d16490 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -71,7 +71,7 @@ def run(self, dag): class AerBackendPlugin(PassManagerStagePlugin): """custom passmanager to avoid unnecessary gate changes""" - def pass_manager(self, pass_manager_config, optimization_level): + def pass_manager(self, pass_manager_config, optimization_level=None) -> PassManager: return PassManager( [ UnitarySynthesis( diff --git a/qiskit_aer/backends/statevector_simulator.py b/qiskit_aer/backends/statevector_simulator.py index 342997c49f..3b954494f1 100644 --- a/qiskit_aer/backends/statevector_simulator.py +++ b/qiskit_aer/backends/statevector_simulator.py @@ -231,6 +231,7 @@ class StatevectorSimulator(AerBackend): "save_state", "set_statevector", "reset", + "barrier", ] ), "gates": [], diff --git a/qiskit_aer/backends/unitary_simulator.py b/qiskit_aer/backends/unitary_simulator.py index ca28204a9a..d47ba54935 100644 --- a/qiskit_aer/backends/unitary_simulator.py +++ b/qiskit_aer/backends/unitary_simulator.py @@ -218,7 +218,9 @@ class UnitarySimulator(AerBackend): "pauli", ] ), - "custom_instructions": sorted(["save_unitary", "save_state", "set_unitary", "reset"]), + "custom_instructions": sorted( + ["save_unitary", "save_state", "set_unitary", "reset", "barrier"] + ), "gates": [], } From e08fc8425905a4a04caac91245ee68ce315c9650 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:05:34 +0900 Subject: [PATCH 11/22] added ccx in NAME_MAPPING --- qiskit_aer/backends/name_mapping.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index de935f5281..fba25bf722 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -45,6 +45,7 @@ CXGate, CYGate, CZGate, + CCXGate, CSXGate, CUGate, CU1Gate, @@ -300,6 +301,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "cx": CXGate, "cy": CYGate, "cz": CZGate, + "ccx": CCXGate, "csx": CSXGate, "cu": CUGate, "cu1": CU1Gate, From 2162ea8b6890af4eb77615fdb5a22c997b39edd2 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:09:50 +0900 Subject: [PATCH 12/22] added missed gates in NAME_MAPPING --- qiskit_aer/backends/name_mapping.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index fba25bf722..ff9d0e4448 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -55,6 +55,7 @@ PauliGate, DiagonalGate, UnitaryGate, + CPhaseGate, MCPhaseGate, MCXGate, CRXGate, @@ -288,7 +289,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "rzx": RZXGate, "id": IGate, "h": HGate, - "x": XGate(), + "x": XGate, "y": YGate, "z": ZGate, "s": SGate, @@ -303,6 +304,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "cz": CZGate, "ccx": CCXGate, "csx": CSXGate, + "cp": CPhaseGate, "cu": CUGate, "cu1": CU1Gate, "cu2": U2Gate(PHI, LAM).control(), From 6c0dc2eb307927a4d4086b2f88acd654b485fcf3 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:20:00 +0900 Subject: [PATCH 13/22] added release note --- .../notes/fix_aerbackend-7e9a74f8219315dc.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml diff --git a/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml b/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml new file mode 100644 index 0000000000..f2cf556195 --- /dev/null +++ b/releasenotes/notes/fix_aerbackend-7e9a74f8219315dc.yaml @@ -0,0 +1,13 @@ +--- +fixes: + - | + Fixes AerBackend issues caused by upgading to BackendV2 in 0.13.0 release + and fix test failures for Qiskit 0.45 release. + + For issue #1987, added description if backend given by from_backend does not + have description. + + For issue #1988, added building coupling map from option. + + For issue #1982, added custome pass maneger to rebuild basis gates from + input circuits to prevent unnecessary gate changes From 0d6296144f9501fb30759279be15c1da8ce828f7 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:34:11 +0900 Subject: [PATCH 14/22] add check if opnodes is None --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index c281d16490..3c55757b90 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -39,6 +39,8 @@ def run(self, dag): ops = [] num_unsupported_ops = 0 opnodes = dag.op_nodes() + if opnodes is None: + return dag for node in opnodes: if node.name in self.config.target: if node.name not in ops: From d68601be7e7ef92a9d6a002e87a4e14686d4ea6f Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:50:07 +0900 Subject: [PATCH 15/22] add check config --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 3c55757b90..d67cb08073 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -34,6 +34,10 @@ def run(self, dag): # do nothing for higher optimization level if self.optimization_level > 1: return dag + if self.config is None: + return dag + if self.config.target is None: + return dag # search ops in supported name mapping ops = [] From a2c336e965935b56c3984147f598644ba78cad95 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 18:58:39 +0900 Subject: [PATCH 16/22] decrease return --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index d67cb08073..059e5c2afd 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -34,9 +34,7 @@ def run(self, dag): # do nothing for higher optimization level if self.optimization_level > 1: return dag - if self.config is None: - return dag - if self.config.target is None: + if self.config is None or self.config.target is None: return dag # search ops in supported name mapping @@ -53,9 +51,7 @@ def run(self, dag): num_unsupported_ops = num_unsupported_ops + 1 # if there are some unsupported node (i.e. RealAmplitudes) do nothing - if num_unsupported_ops > 0: - return dag - if len(ops) < 1: + if num_unsupported_ops > 0 or len(ops) < 1: return dag # clear all instructions in target From e8cf4e7d47fd20414d6c4311c00b78330fcdc7f1 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 16 Nov 2023 19:02:17 +0900 Subject: [PATCH 17/22] check opt level --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 059e5c2afd..e923d8b902 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -28,7 +28,10 @@ class AerBackendRebuildGateSetsFromCircuit(TransformationPass): def __init__(self, config, opt_lvl): super().__init__() self.config = config - self.optimization_level = opt_lvl + if opt_lvl is None: + self.optimization_level = 1 + else: + self.optimization_level = opt_lvl def run(self, dag): # do nothing for higher optimization level From 5151558e52077af812c9413f4fa75e6d82416109 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Fri, 17 Nov 2023 11:57:16 +0900 Subject: [PATCH 18/22] fix searching ops in control flow blocks --- .../backends/plugin/aer_backend_plugin.py | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index e923d8b902..594d63a73b 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -19,6 +19,8 @@ from qiskit.transpiler.passes import HighLevelSynthesis from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel from qiskit.circuit.measure import Measure +from qiskit.circuit import ControlFlowOp +from qiskit.converters import circuit_to_dag from qiskit_aer.backends.name_mapping import NAME_MAPPING @@ -33,25 +35,35 @@ def __init__(self, config, opt_lvl): else: self.optimization_level = opt_lvl - def run(self, dag): - # do nothing for higher optimization level - if self.optimization_level > 1: - return dag - if self.config is None or self.config.target is None: - return dag - - # search ops in supported name mapping - ops = [] + def _add_ops(self, dag, ops): num_unsupported_ops = 0 opnodes = dag.op_nodes() if opnodes is None: - return dag + return num_unsupported_ops + for node in opnodes: + if isinstance(node.op, ControlFlowOp): + for block in node.op.blocks: + num_unsupported_ops = num_unsupported_ops + self._add_ops( + circuit_to_dag(block), ops + ) if node.name in self.config.target: if node.name not in ops: ops.append(node.name) else: num_unsupported_ops = num_unsupported_ops + 1 + return num_unsupported_ops + + def run(self, dag): + # do nothing for higher optimization level + if self.optimization_level > 1: + return dag + if self.config is None or self.config.target is None: + return dag + + # search ops in supported name mapping + ops = [] + num_unsupported_ops = self._add_ops(dag, ops) # if there are some unsupported node (i.e. RealAmplitudes) do nothing if num_unsupported_ops > 0 or len(ops) < 1: From c88bdff251a23c99cfac0d7d30274457cf458380 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 22 Nov 2023 13:41:46 +0900 Subject: [PATCH 19/22] Update qiskit_aer/backends/plugin/aer_backend_plugin.py Co-authored-by: Matthew Treinish --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 594d63a73b..22660024b4 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -44,7 +44,7 @@ def _add_ops(self, dag, ops): for node in opnodes: if isinstance(node.op, ControlFlowOp): for block in node.op.blocks: - num_unsupported_ops = num_unsupported_ops + self._add_ops( + num_unsupported_ops += self._add_ops( circuit_to_dag(block), ops ) if node.name in self.config.target: From 3b0543ac7feda837b7129d8c5d4d89b060ba6f77 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 22 Nov 2023 13:42:56 +0900 Subject: [PATCH 20/22] Update qiskit_aer/backends/plugin/aer_backend_plugin.py Co-authored-by: Matthew Treinish --- qiskit_aer/backends/plugin/aer_backend_plugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 22660024b4..5663ec016f 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -81,6 +81,8 @@ def run(self, dag): if name != "measure": self.config.target.add_instruction(NAME_MAPPING[name], name=name) self.config.target.add_instruction(Measure()) + self.config.basis_gates.clear() + self.config.basis_gates.extend(self.config.target.operations) return dag From 8afde0be2cc5681dc2c8a3f38fce83aad110d227 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 22 Nov 2023 17:05:50 +0900 Subject: [PATCH 21/22] refer review comments --- qiskit_aer/backends/aer_simulator.py | 8 --- qiskit_aer/backends/name_mapping.py | 65 ------------------- .../backends/plugin/aer_backend_plugin.py | 36 ++++++---- qiskit_aer/backends/qasm_simulator.py | 1 - qiskit_aer/backends/statevector_simulator.py | 1 - qiskit_aer/backends/unitary_simulator.py | 4 +- 6 files changed, 23 insertions(+), 92 deletions(-) diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index a247b1354c..04fc439592 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -518,7 +518,6 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", - "barrier", ] ), "density_matrix": sorted( @@ -543,7 +542,6 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", - "barrier", ] ), "matrix_product_state": sorted( @@ -570,7 +568,6 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", - "barrier", ] ), "stabilizer": sorted( @@ -594,7 +591,6 @@ class AerSimulator(AerBackend): "continue_loop", "reset", "switch_case", - "barrier", ] ), "extended_stabilizer": sorted( @@ -604,7 +600,6 @@ class AerSimulator(AerBackend): "roerror", "save_statevector", "reset", - "barrier", ] ), "unitary": sorted( @@ -613,7 +608,6 @@ class AerSimulator(AerBackend): "save_unitary", "set_unitary", "reset", - "barrier", ] ), "superop": sorted( @@ -626,7 +620,6 @@ class AerSimulator(AerBackend): "save_superop", "set_superop", "reset", - "barrier", ] ), "tensor_network": sorted( @@ -650,7 +643,6 @@ class AerSimulator(AerBackend): "set_density_matrix", "reset", "switch_case", - "barrier", ] ), } diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index ff9d0e4448..ecc9d605a1 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -17,41 +17,14 @@ from qiskit.circuit import ControlledGate, Parameter from qiskit.circuit.reset import Reset from qiskit.circuit.library import ( - U1Gate, U2Gate, - U3Gate, - UGate, - PhaseGate, RGate, - RXGate, - RXXGate, - RYGate, - RYYGate, - RZGate, - RZZGate, - RZXGate, - IGate, - HGate, - XGate, - YGate, - ZGate, - SGate, - SdgGate, - SXGate, - SXdgGate, - TGate, - TdgGate, - SwapGate, - CXGate, CYGate, CZGate, - CCXGate, CSXGate, CUGate, - CU1Gate, CU3Gate, CSwapGate, - ECRGate, PauliGate, DiagonalGate, UnitaryGate, @@ -63,7 +36,6 @@ CRZGate, MCU1Gate, MCXGrayCode, - Barrier, ) from qiskit.circuit.controlflow import ( IfElseOp, @@ -274,43 +246,7 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): PHI = Parameter("phi") LAM = Parameter("lam") NAME_MAPPING = { - "u1": U1Gate, - "u2": U2Gate, - "u3": U3Gate, - "u": UGate, - "p": PhaseGate, - "r": RGate, - "rx": RXGate, - "rxx": RXXGate, - "ry": RYGate, - "ryy": RYYGate, - "rz": RZGate, - "rzz": RZZGate, - "rzx": RZXGate, - "id": IGate, - "h": HGate, - "x": XGate, - "y": YGate, - "z": ZGate, - "s": SGate, - "sdg": SdgGate, - "sx": SXGate, - "sxdg": SXdgGate, - "t": TGate, - "tdg": TdgGate, - "swap": SwapGate, - "cx": CXGate, - "cy": CYGate, - "cz": CZGate, - "ccx": CCXGate, - "csx": CSXGate, - "cp": CPhaseGate, - "cu": CUGate, - "cu1": CU1Gate, "cu2": U2Gate(PHI, LAM).control(), - "cu3": CU3Gate, - "cswap": CSwapGate, - "ecr": ECRGate, "pauli": PauliGate, "diagonal": DiagonalGate, "unitary": UnitaryGate, @@ -367,5 +303,4 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None): "save_probs_ket": SaveProbabilitiesDict, "save_probs": SaveProbabilities, "reset": Reset(), - "barrier": Barrier, } diff --git a/qiskit_aer/backends/plugin/aer_backend_plugin.py b/qiskit_aer/backends/plugin/aer_backend_plugin.py index 5663ec016f..73be26fcef 100644 --- a/qiskit_aer/backends/plugin/aer_backend_plugin.py +++ b/qiskit_aer/backends/plugin/aer_backend_plugin.py @@ -18,7 +18,9 @@ from qiskit.transpiler.passes import UnitarySynthesis from qiskit.transpiler.passes import HighLevelSynthesis from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel +from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping from qiskit.circuit.measure import Measure +from qiskit.circuit.library import Barrier from qiskit.circuit import ControlFlowOp from qiskit.converters import circuit_to_dag from qiskit_aer.backends.name_mapping import NAME_MAPPING @@ -34,8 +36,10 @@ def __init__(self, config, opt_lvl): self.optimization_level = 1 else: self.optimization_level = opt_lvl + self.qiskit_inst_name_map = get_standard_gate_name_mapping() + self.qiskit_inst_name_map["barrier"] = Barrier - def _add_ops(self, dag, ops): + def _add_ops(self, dag, ops: set): num_unsupported_ops = 0 opnodes = dag.op_nodes() if opnodes is None: @@ -44,12 +48,11 @@ def _add_ops(self, dag, ops): for node in opnodes: if isinstance(node.op, ControlFlowOp): for block in node.op.blocks: - num_unsupported_ops += self._add_ops( - circuit_to_dag(block), ops - ) - if node.name in self.config.target: - if node.name not in ops: - ops.append(node.name) + num_unsupported_ops += self._add_ops(circuit_to_dag(block), ops) + if node.name in self.qiskit_inst_name_map: + ops.add(node.name) + elif node.name in self.config.target: + ops.add(node.name) else: num_unsupported_ops = num_unsupported_ops + 1 return num_unsupported_ops @@ -62,7 +65,7 @@ def run(self, dag): return dag # search ops in supported name mapping - ops = [] + ops = set() num_unsupported_ops = self._add_ops(dag, ops) # if there are some unsupported node (i.e. RealAmplitudes) do nothing @@ -77,16 +80,21 @@ def run(self, dag): # rebuild gate sets from circuit for name in ops: - if name not in self.config.target: - if name != "measure": - self.config.target.add_instruction(NAME_MAPPING[name], name=name) - self.config.target.add_instruction(Measure()) - self.config.basis_gates.clear() - self.config.basis_gates.extend(self.config.target.operations) + if name in self.qiskit_inst_name_map: + self.config.target.add_instruction(self.qiskit_inst_name_map[name], name=name) + else: + self.config.target.add_instruction(NAME_MAPPING[name], name=name) + if "measure" not in ops: + self.config.target.add_instruction(Measure()) + self.config.basis_gates = list(self.config.target.operation_names) return dag +# This plugin should not be used outside of simulator +# TODO : this plugin should be moved to optimization stage plugin +# if Qiskit will have custom optimizaiton stage plugin interface +# in that case just return pass without Optimize1qGatesDecomposition class AerBackendPlugin(PassManagerStagePlugin): """custom passmanager to avoid unnecessary gate changes""" diff --git a/qiskit_aer/backends/qasm_simulator.py b/qiskit_aer/backends/qasm_simulator.py index d0fb21e887..d73938a6b9 100644 --- a/qiskit_aer/backends/qasm_simulator.py +++ b/qiskit_aer/backends/qasm_simulator.py @@ -389,7 +389,6 @@ class QasmSimulator(AerBackend): "set_density_matrix", "set_stabilizer", "reset", - "barrier", ] ) diff --git a/qiskit_aer/backends/statevector_simulator.py b/qiskit_aer/backends/statevector_simulator.py index 23236cdc13..da653bac6c 100644 --- a/qiskit_aer/backends/statevector_simulator.py +++ b/qiskit_aer/backends/statevector_simulator.py @@ -232,7 +232,6 @@ class StatevectorSimulator(AerBackend): "save_state", "set_statevector", "reset", - "barrier", ] ), "gates": [], diff --git a/qiskit_aer/backends/unitary_simulator.py b/qiskit_aer/backends/unitary_simulator.py index a476e0d039..1cb477e67b 100644 --- a/qiskit_aer/backends/unitary_simulator.py +++ b/qiskit_aer/backends/unitary_simulator.py @@ -219,9 +219,7 @@ class UnitarySimulator(AerBackend): "pauli", ] ), - "custom_instructions": sorted( - ["save_unitary", "save_state", "set_unitary", "reset", "barrier"] - ), + "custom_instructions": sorted(["save_unitary", "save_state", "set_unitary", "reset"]), "gates": [], } From c3f0cc43a9b46bd2d73824dbb6f26a46bc423b42 Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Wed, 22 Nov 2023 17:11:17 +0900 Subject: [PATCH 22/22] remove unused import --- qiskit_aer/backends/name_mapping.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/qiskit_aer/backends/name_mapping.py b/qiskit_aer/backends/name_mapping.py index ecc9d605a1..419e3cde37 100644 --- a/qiskit_aer/backends/name_mapping.py +++ b/qiskit_aer/backends/name_mapping.py @@ -22,13 +22,11 @@ CYGate, CZGate, CSXGate, - CUGate, CU3Gate, CSwapGate, PauliGate, DiagonalGate, UnitaryGate, - CPhaseGate, MCPhaseGate, MCXGate, CRXGate,