From 7211d098bf2834e400d09edc1293e806de07b92c Mon Sep 17 00:00:00 2001 From: Jun Doi Date: Thu, 8 Aug 2024 17:41:39 +0900 Subject: [PATCH] remove configuration and properties from AerBackend --- qiskit_aer/backends/aer_simulator.py | 82 ++++++----- qiskit_aer/backends/aerbackend.py | 129 ++++++++++-------- qiskit_aer/backends/qasm_simulator.py | 67 ++++++--- qiskit_aer/backends/statevector_simulator.py | 15 +- qiskit_aer/backends/unitary_simulator.py | 15 +- qiskit_aer/noise/noise_model.py | 8 ++ .../backends/aer_simulator/test_options.py | 21 ++- test/terra/backends/simulator_test_case.py | 19 +-- .../terra/backends/test_parameterized_qobj.py | 81 ----------- .../backends/test_runtime_parameterization.py | 83 ----------- test/terra/extensions/test_wrappers.py | 69 ---------- 11 files changed, 187 insertions(+), 402 deletions(-) delete mode 100644 test/terra/extensions/test_wrappers.py diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index a833574978..a316f779c3 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -17,7 +17,6 @@ import logging from qiskit.providers import convert_to_target from qiskit.providers.options import Options -from qiskit.providers.models import QasmBackendConfiguration from qiskit.providers.backend import BackendV2, BackendV1 from qiskit.transpiler.target import target_to_backend_properties @@ -682,11 +681,6 @@ class AerSimulator(AerBackend): "backend_version": __version__, "n_qubits": MAX_QUBITS_STATEVECTOR, "url": "https://github.com/Qiskit/qiskit-aer", - "simulator": True, - "local": True, - "conditional": True, - "open_pulse": False, - "memory": True, "max_shots": int(1e6), "description": "A C++ QasmQobj simulator with noise", "coupling_map": None, @@ -713,9 +707,7 @@ class AerSimulator(AerBackend): _AVAILABLE_DEVICES = None - def __init__( - self, configuration=None, properties=None, provider=None, target=None, **backend_options - ): + def __init__(self, configuration=None, provider=None, target=None, **backend_options): self._controller = aer_controller_execute() # Update available methods and devices for class @@ -728,10 +720,11 @@ def __init__( # Default configuration if configuration is None: - configuration = QasmBackendConfiguration.from_dict(AerSimulator._DEFAULT_CONFIGURATION) + configuration = AerSimulator._DEFAULT_CONFIGURATION # set backend name from method and device in option - if "from" not in configuration.backend_name: + backend_name = configuration["backend_name"] + if "from" not in backend_name: method = "automatic" device = "CPU" for key, value in backend_options.items(): @@ -740,9 +733,10 @@ def __init__( if key == "device": device = value if method not in [None, "automatic"]: - configuration.backend_name += f"_{method}" + backend_name += f"_{method}" if device not in [None, "CPU"]: - configuration.backend_name += f"_{device}".lower() + backend_name += f"_{device}".lower() + configuration["backend_name"] = backend_name # Cache basis gates since computing the intersection # of noise model, method, and config gates is expensive. @@ -750,7 +744,6 @@ def __init__( super().__init__( configuration, - properties=properties, provider=provider, target=target, backend_options=backend_options, @@ -846,36 +839,38 @@ def from_backend(cls, backend, **options): else: description = backend.description - configuration = QasmBackendConfiguration( - backend_name=f"aer_simulator_from({backend.name})", - backend_version=backend.backend_version, - n_qubits=backend.num_qubits, - basis_gates=backend.operation_names, - gates=[], - local=True, - simulator=True, - conditional=True, - open_pulse=False, - memory=False, - max_shots=int(1e6), - coupling_map=( + configuration = { + "backend_name": f"aer_simulator_from({backend.name})", + "backend_version": backend.backend_version, + "n_qubits": backend.num_qubits, + "basis_gates": backend.operation_names, + "max_shots": int(1e6), + "coupling_map": ( None if backend.coupling_map is None else list(backend.coupling_map.get_edges()) ), - max_experiments=backend.max_circuits, - description=description, - ) - properties = target_to_backend_properties(backend.target) + "max_experiments": backend.max_circuits, + "description": description, + } target = backend.target elif isinstance(backend, BackendV1): + # BackendV1 will be removed in Qiskit 2.0, so we will remove this soon + warnings.warn( + " from_backend using V1 based backend is deprecated as of Aer 0.15" + " and will be removed no sooner than 3 months from that release" + " date. Please use backends based on V2.", + DeprecationWarning, + stacklevel=2, + ) # Get configuration and properties from backend - configuration = copy.copy(backend.configuration()) + config = backend.configuration() properties = copy.copy(backend.properties()) # Customize configuration name - name = configuration.backend_name - configuration.backend_name = f"aer_simulator_from({name})" + name = config.backend_name + config.backend_name = f"aer_simulator_from({name})" - target = convert_to_target(configuration, properties, None, NAME_MAPPING) + target = convert_to_target(config, properties, None, NAME_MAPPING) + configuration = config.to_dict() else: raise TypeError( "The backend argument requires a BackendV2 or BackendV1 object, " @@ -892,7 +887,7 @@ def from_backend(cls, backend, **options): options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, properties=properties, target=target, **options) + sim = cls(configuration=configuration, target=target, **options) return sim def available_methods(self): @@ -911,16 +906,15 @@ def configuration(self): Returns: BackendConfiguration: the configuration for the backend. """ - config = copy.copy(self._configuration) - for key, val in self._options_configuration.items(): - setattr(config, key, val) + config = self._configuration.copy() + config.update(self._options_configuration) method = getattr(self.options, "method", "automatic") # Update basis gates based on custom options, config, method, # and noise model - config.custom_instructions = self._CUSTOM_INSTR[method] - config.basis_gates = self._cached_basis_gates + config.custom_instructions + config["custom_instructions"] = self._CUSTOM_INSTR[method] + config["basis_gates"] = self._cached_basis_gates + config["custom_instructions"] return config def _execute_circuits(self, aer_circuits, noise_model, config): @@ -1008,7 +1002,7 @@ def _basis_gates(self): # Compute intersection with method basis gates method = getattr(self._options, "method", "automatic") method_gates = self._BASIS_GATES[method] - config_gates = self._configuration.basis_gates + config_gates = self._configuration.get("basis_gates", []) if config_gates: basis_gates = set(config_gates).intersection(method_gates) else: @@ -1062,8 +1056,8 @@ def _set_method_config(self, method=None): description = None n_qubits = None - if self._configuration.coupling_map: - n_qubits = max(list(map(max, self._configuration.coupling_map))) + 1 + if self._configuration.get("coupling_map", None) is not None: + n_qubits = max(list(map(max, self._configuration["coupling_map"]))) + 1 self._set_configuration_option("description", description) self._set_configuration_option("n_qubits", n_qubits) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 968ead84a0..43ec732cce 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -24,12 +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.circuit.controlflow import CONTROL_FLOW_OP_NAMES from ..aererror import AerError from ..jobs import AerJob, AerJobSet, split_qobj from ..noise.noise_model import NoiseModel, QuantumErrorLocation @@ -48,9 +48,7 @@ class AerBackend(Backend, ABC): """Aer Backend class.""" - def __init__( - self, configuration, properties=None, provider=None, target=None, backend_options=None - ): + def __init__(self, configuration, provider=None, target=None, backend_options=None): """Aer class for backends. This method should initialize the module and its configuration, and @@ -58,8 +56,7 @@ def __init__( not available. Args: - configuration (BackendConfiguration): backend configuration. - properties (BackendProperties or None): Optional, backend properties. + configuration (dict): backend configuration. provider (Provider): Optional, provider responsible for this backend. target (Target): initial target for backend backend_options (dict or None): Optional set custom backend options. @@ -68,32 +65,32 @@ def __init__( AerError: if there is no name in the configuration """ # Init configuration and provider in Backend - configuration.simulator = True - configuration.local = True super().__init__( provider=provider, - name=configuration.backend_name, - description=configuration.description, - backend_version=configuration.backend_version, + name=configuration["backend_name"], + description=configuration["description"], + backend_version=configuration["backend_version"], ) - # Initialize backend properties - self._properties = properties + # Initialize backend configuration self._configuration = configuration - # Custom option values for config, properties + # Custom option values for config self._options_configuration = {} - self._options_properties = {} self._target = target self._mapping = NAME_MAPPING + if target is not None: + self._from_backend = True + else: + self._from_backend = False # 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) + 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 = [] @@ -312,55 +309,77 @@ def configuration(self): Returns: BackendConfiguration: the configuration for the backend. """ - config = copy.copy(self._configuration) - for key, val in self._options_configuration.items(): - setattr(config, key, val) + config = self._configuration.copy() # If config has custom instructions add them to # basis gates to include them for the qiskit transpiler - if hasattr(config, "custom_instructions"): - config.basis_gates = config.basis_gates + config.custom_instructions + if "custom_instructions" in config: + config["basis_gates"] = config["basis_gates"] + config["custom_instructions"] return config - def properties(self): - """Return the simulator backend properties if set. - - Returns: - BackendProperties: The backend properties or ``None`` if the - backend does not have properties set. - """ - properties = copy.copy(self._properties) - for key, val in self._options_properties.items(): - setattr(properties, key, val) - return properties - @property def max_circuits(self): - if hasattr(self.configuration(), "max_experiments"): - return self.configuration().max_experiments + if "max_experiments" in self.configuration(): + return self.configuration()["max_experiments"] else: return None @property def target(self): - if self._target is not None: + if self._from_backend: return self._target - tgt = convert_to_target(self.configuration(), self.properties(), None, NAME_MAPPING) + # make target for AerBackend + + # importing packages where they are needed, to avoid cyclic-import. + # pylint: disable=cyclic-import + from qiskit.transpiler.target import ( + Target, + InstructionProperties, + ) + from qiskit.circuit.controlflow import ForLoopOp, IfElseOp, SwitchCaseOp, WhileLoopOp + from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping + from qiskit.circuit.parameter import Parameter + from qiskit.circuit.gate import Gate + + required = ["measure", "delay"] + + # Load Qiskit object representation + qiskit_inst_mapping = get_standard_gate_name_mapping() + qiskit_inst_mapping.update(NAME_MAPPING) + + num_qubits = self.configuration()["n_qubits"] + in_data = {"num_qubits": num_qubits} + basis_gates = set.union(set(required), set(self.configuration().get("basis_gates", []))) + + self._target = Target(**in_data) + for name in basis_gates: + if name in required: + self._target.add_instruction( + instruction=qiskit_inst_mapping[name], + properties={(q,): None for q in range(num_qubits)}, + name=name, + ) + elif name in qiskit_inst_mapping: + self._target.add_instruction( + instruction=qiskit_inst_mapping[name], + properties=None, + name=name, + ) + if self._coupling_map is not None: - tgt._coupling_graph = self._coupling_map.graph.copy() - return tgt + self._target._coupling_graph = self._coupling_map.graph.copy() + return self._target def set_max_qubits(self, max_qubits): """Set maximun number of qubits to be used for this backend.""" - if self._target is None: - self._configuration.n_qubits = max_qubits + if not self._from_backend: + self._configuration["n_qubits"] = max_qubits self._set_configuration_option("n_qubits", max_qubits) def clear_options(self): """Reset the simulator options to default values.""" self._options = self._default_options() self._options_configuration = {} - self._options_properties = {} def status(self): """Return backend status. @@ -370,7 +389,7 @@ def status(self): """ return BackendStatus( backend_name=self.name, - backend_version=self.configuration().backend_version, + backend_version=self.configuration()["backend_version"], operational=True, pending_jobs=0, status_msg="", @@ -416,7 +435,7 @@ def _execute_qobj_job(self, qobj, job_id="", format_result=True): output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() output["backend_name"] = self.name - output["backend_version"] = self.configuration().backend_version + output["backend_version"] = self.configuration()["backend_version"] # Push metadata to experiment headers for result in output["results"]: @@ -452,7 +471,9 @@ def _execute_circuits_job( circuits, noise_model = self._compile(circuits, **run_options) if self._target is not None: - aer_circuits, idx_maps = assemble_circuits(circuits, self.configuration().basis_gates) + aer_circuits, idx_maps = assemble_circuits( + circuits, self.configuration()["basis_gates"] + ) else: aer_circuits, idx_maps = assemble_circuits(circuits) if parameter_binds: @@ -485,7 +506,7 @@ def _execute_circuits_job( output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() output["backend_name"] = self.name - output["backend_version"] = self.configuration().backend_version + output["backend_version"] = self.configuration()["backend_version"] # Push metadata to experiment headers for result in output["results"]: @@ -695,13 +716,8 @@ def set_option(self, key, value): AerError: if key is 'method' and val isn't in available methods. """ # Add all other options to the options dict - # TODO: in the future this could be replaced with an options class - # for the simulators like configuration/properties to show all - # available options - if hasattr(self._configuration, key): + if key in self._configuration: self._set_configuration_option(key, value) - elif hasattr(self._properties, key): - self._set_properties_option(key, value) else: if not hasattr(self._options, key): raise AerError(f"Invalid option {key}") @@ -726,13 +742,6 @@ def _set_configuration_option(self, key, value): elif key in self._options_configuration: self._options_configuration.pop(key) - def _set_properties_option(self, key, value): - """Special handling for setting backend properties options.""" - if value is not None: - self._options_properties[key] = value - elif key in self._options_properties: - self._options_properties.pop(key) - def __repr__(self): """String representation of an AerBackend.""" name = self.__class__.__name__ diff --git a/qiskit_aer/backends/qasm_simulator.py b/qiskit_aer/backends/qasm_simulator.py index 174d201da1..b3f8d90497 100644 --- a/qiskit_aer/backends/qasm_simulator.py +++ b/qiskit_aer/backends/qasm_simulator.py @@ -450,17 +450,13 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend # Default configuration if configuration is None: - configuration = QasmBackendConfiguration.from_dict(QasmSimulator._DEFAULT_CONFIGURATION) - else: - configuration.open_pulse = False + configuration = QasmSimulator._DEFAULT_CONFIGURATION # Cache basis gates since computing the intersection # of noise model, method, and config gates is expensive. self._cached_basis_gates = self._DEFAULT_BASIS_GATES - super().__init__( - configuration, properties=properties, provider=provider, backend_options=backend_options - ) + super().__init__(configuration, provider=provider, backend_options=backend_options) def __repr__(self): """String representation of an AerBackend.""" @@ -534,27 +530,60 @@ def _default_options(cls): def from_backend(cls, backend, **options): """Initialize simulator from backend.""" if isinstance(backend, BackendV2): - raise AerError("QasmSimulator.from_backend does not currently support V2 Backends.") - # pylint: disable=import-outside-toplevel - # Avoid cyclic import - from ..noise.noise_model import NoiseModel - - # Get configuration and properties from backend - configuration = copy.copy(backend.configuration()) - properties = copy.copy(backend.properties()) + if backend.description is None: + description = "created by QasmSimulator.from_backend" + else: + description = backend.description + + configuration = { + "backend_name": f"aer_simulator_from({backend.name})", + "backend_version": backend.backend_version, + "n_qubits": backend.num_qubits, + "basis_gates": backend.operation_names, + "max_shots": int(1e6), + "coupling_map": ( + None if backend.coupling_map is None else list(backend.coupling_map.get_edges()) + ), + "max_experiments": backend.max_circuits, + "description": description, + } + target = backend.target + elif isinstance(backend, BackendV1): + # BackendV1 will be removed in Qiskit 2.0, so we will remove this soon + warnings.warn( + " from_backend using V1 based backend is deprecated as of Aer 0.15" + " and will be removed no sooner than 3 months from that release" + " date. Please use backends based on V2.", + DeprecationWarning, + stacklevel=2, + ) + # Get configuration and properties from backend + config = backend.configuration() + properties = copy.copy(backend.properties()) - # Customize configuration name - name = configuration.backend_name - configuration.backend_name = f"qasm_simulator({name})" + # Customize configuration name + name = config.backend_name + config.backend_name = f"aer_simulator_from({name})" + target = convert_to_target(config, properties, None, NAME_MAPPING) + configuration = config.to_dict() + else: + raise TypeError( + "The backend argument requires a BackendV2 or BackendV1 object, " + f"not a {type(backend)} object" + ) # Use automatic noise model if none is provided if "noise_model" not in options: + # pylint: disable=import-outside-toplevel + # Avoid cyclic import + from ..noise.noise_model import NoiseModel + noise_model = NoiseModel.from_backend(backend) if not noise_model.is_ideal(): options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, properties=properties, **options) + sim = cls(configuration=configuration, target=target, **options) return sim def configuration(self): @@ -563,7 +592,7 @@ def configuration(self): Returns: BackendConfiguration: the configuration for the backend. """ - config = copy.copy(self._configuration) + config = self._configuration.copy() for key, val in self._options_configuration.items(): setattr(config, key, val) # Update basis gates based on custom options, config, method, diff --git a/qiskit_aer/backends/statevector_simulator.py b/qiskit_aer/backends/statevector_simulator.py index 63fe03cdc3..179512c92f 100644 --- a/qiskit_aer/backends/statevector_simulator.py +++ b/qiskit_aer/backends/statevector_simulator.py @@ -19,7 +19,6 @@ import psutil from qiskit.providers.options import Options -from qiskit.providers.models import QasmBackendConfiguration from ..aererror import AerError from ..version import __version__ @@ -242,7 +241,7 @@ class StatevectorSimulator(AerBackend): _AVAILABLE_DEVICES = None - def __init__(self, configuration=None, properties=None, provider=None, **backend_options): + def __init__(self, configuration=None, provider=None, **backend_options): warn( "The `StatevectorSimulator` backend will be deprecated in the" " future. It has been superseded by the `AerSimulator`" @@ -258,15 +257,9 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend StatevectorSimulator._AVAILABLE_DEVICES = available_devices(self._controller) if configuration is None: - configuration = QasmBackendConfiguration.from_dict( - StatevectorSimulator._DEFAULT_CONFIGURATION - ) - else: - configuration.open_pulse = False + configuration = StatevectorSimulator._DEFAULT_CONFIGURATION - super().__init__( - configuration, properties=properties, provider=provider, backend_options=backend_options - ) + super().__init__(configuration, provider=provider, backend_options=backend_options) @classmethod def _default_options(cls): @@ -360,7 +353,7 @@ def _validate(self, qobj): raise AerError(f"{name} does not support noise.") n_qubits = qobj.config.n_qubits - max_qubits = self.configuration().n_qubits + max_qubits = self.configuration()["n_qubits"] if n_qubits > max_qubits: raise AerError( f"Number of qubits ({n_qubits}) is greater than max ({max_qubits}) " diff --git a/qiskit_aer/backends/unitary_simulator.py b/qiskit_aer/backends/unitary_simulator.py index ef02150fe9..21dcbb725e 100644 --- a/qiskit_aer/backends/unitary_simulator.py +++ b/qiskit_aer/backends/unitary_simulator.py @@ -20,7 +20,6 @@ import psutil from qiskit.providers.options import Options -from qiskit.providers.models import QasmBackendConfiguration from ..aererror import AerError from ..version import __version__ @@ -228,7 +227,7 @@ class UnitarySimulator(AerBackend): _AVAILABLE_DEVICES = None - def __init__(self, configuration=None, properties=None, provider=None, **backend_options): + def __init__(self, configuration=None, provider=None, **backend_options): warn( "The `UnitarySimulator` backend will be deprecated in the" " future. It has been superseded by the `AerSimulator`" @@ -244,15 +243,9 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend UnitarySimulator._AVAILABLE_DEVICES = available_devices(self._controller) if configuration is None: - configuration = QasmBackendConfiguration.from_dict( - UnitarySimulator._DEFAULT_CONFIGURATION - ) - else: - configuration.open_pulse = False + configuration = UnitarySimulator._DEFAULT_CONFIGURATION - super().__init__( - configuration, properties=properties, provider=provider, backend_options=backend_options - ) + super().__init__(configuration, provider=provider, backend_options=backend_options) @classmethod def _default_options(cls): @@ -346,7 +339,7 @@ def _validate(self, qobj): raise AerError(f"{name} does not support noise.") n_qubits = qobj.config.n_qubits - max_qubits = self.configuration().n_qubits + max_qubits = self.configuration()["n_qubits"] if n_qubits > max_qubits: raise AerError( f"Number of qubits ({n_qubits}) is greater than " diff --git a/qiskit_aer/noise/noise_model.py b/qiskit_aer/noise/noise_model.py index 6ff1f91760..d040cb18cf 100644 --- a/qiskit_aer/noise/noise_model.py +++ b/qiskit_aer/noise/noise_model.py @@ -381,6 +381,14 @@ def from_backend( ) dt = backend.dt elif backend_interface_version <= 1: + # BackendV1 will be removed in Qiskit 2.0, so we will remove this soon + warn( + " from_backend using V1 based backend is deprecated as of Aer 0.15" + " and will be removed no sooner than 3 months from that release" + " date. Please use backends based on V2.", + DeprecationWarning, + stacklevel=2, + ) properties = backend.properties() configuration = backend.configuration() basis_gates = configuration.basis_gates diff --git a/test/terra/backends/aer_simulator/test_options.py b/test/terra/backends/aer_simulator/test_options.py index a387e6cd63..41210fcb74 100644 --- a/test/terra/backends/aer_simulator/test_options.py +++ b/test/terra/backends/aer_simulator/test_options.py @@ -22,10 +22,7 @@ from qiskit.quantum_info.random import random_unitary from qiskit.quantum_info import state_fidelity -if qiskit.__version__.startswith("0."): - from qiskit.providers.fake_provider import FakeAlmaden as Fake20QV1 -else: - from qiskit.providers.fake_provider import Fake20QV1 +from qiskit.providers.fake_provider import GenericBackendV2 from qiskit_aer import AerSimulator @@ -153,11 +150,12 @@ def test_option_basis_gates(self, method): noise_gates = ["id", "sx", "x", "cx"] noise_model = NoiseModel(basis_gates=noise_gates) target_gates = ( - sorted(set(config.basis_gates).intersection(noise_gates)) + config.custom_instructions + sorted(set(config["basis_gates"]).intersection(noise_gates)) + + config["custom_instructions"] ) sim = self.backend(method=method, noise_model=noise_model) - basis_gates = sim.configuration().basis_gates + basis_gates = sim.configuration()["basis_gates"] self.assertEqual(sorted(basis_gates), sorted(target_gates)) @data( @@ -172,9 +170,9 @@ def test_option_order_basis_gates(self, method): """Test order of setting method and noise model gives same basis gates""" noise_model = NoiseModel(basis_gates=["id", "sx", "x", "cx"]) sim1 = self.backend(method=method, noise_model=noise_model) - basis_gates1 = sim1.configuration().basis_gates + basis_gates1 = sim1.configuration()["basis_gates"] sim2 = self.backend(noise_model=noise_model, method=method) - basis_gates2 = sim2.configuration().basis_gates + basis_gates2 = sim2.configuration()["basis_gates"] self.assertEqual(sorted(basis_gates1), sorted(basis_gates2)) @supported_methods( @@ -305,9 +303,10 @@ def test_statevector_memory(self): def test_num_qubits(self, method): """Test number of qubits is correctly checked""" - num_qubits = Fake20QV1().configuration().num_qubits - backend = AerSimulator.from_backend(Fake20QV1(), method=method) - self.assertGreaterEqual(backend.configuration().num_qubits, num_qubits) + num_qubits = 20 + fake_backend = GenericBackendV2(num_qubits=num_qubits) + backend = AerSimulator.from_backend(fake_backend, method=method) + self.assertGreaterEqual(backend.configuration()["n_qubits"], num_qubits) def test_mps_svd_method(self): """Test env. variabe to change MPS SVD method""" diff --git a/test/terra/backends/simulator_test_case.py b/test/terra/backends/simulator_test_case.py index 2173c2c413..e04ec8dcbc 100644 --- a/test/terra/backends/simulator_test_case.py +++ b/test/terra/backends/simulator_test_case.py @@ -19,9 +19,6 @@ from qiskit_aer import AerSimulator from test.terra.common import QiskitAerTestCase from qiskit.circuit import QuantumCircuit -from qiskit.compiler import assemble -from qiskit_aer.backends.backend_utils import cpp_execute_qobj -from qiskit_aer.backends.controller_wrappers import aer_controller_execute class SimulatorTestCase(QiskitAerTestCase): @@ -117,16 +114,12 @@ def check_cuStateVec(devices): if "GPU" in devices: dummy_circ = QuantumCircuit(1) dummy_circ.id(0) - qobj = assemble( - dummy_circ, - optimization_level=0, - shots=1, - method="statevector", - device="GPU", - cuStateVec_enable=True, - ) # run dummy circuit to check if Aer is built with cuStateVec - result = cpp_execute_qobj(aer_controller_execute(), qobj) - return result.get("success", False) + sim = AerSimulator() + result = sim.run( + dummy_circ, shots=1, method="statevector", device="GPU", cuStateVec_enable=True + ).result() + success = getattr(result, "success", False) + return success else: return False diff --git a/test/terra/backends/test_parameterized_qobj.py b/test/terra/backends/test_parameterized_qobj.py index b37f2d981e..afe487afdc 100644 --- a/test/terra/backends/test_parameterized_qobj.py +++ b/test/terra/backends/test_parameterized_qobj.py @@ -39,87 +39,6 @@ class TestParameterizedQobj(common.QiskitAerTestCase): BACKEND_OPTS = {"seed_simulator": 2113} - @staticmethod - def parameterized_qobj( - backend, - shots=1000, - measure=True, - snapshot=False, - save_state=False, - ): - """Return ParameterizedQobj for settings.""" - pershot = shots == 1 - pcirc1, param1 = save_expval_circuit_parameterized( - pershot=pershot, - measure=measure, - snapshot=snapshot, - ) - circuits2to4 = save_expval_circuits( - pauli=True, - skip_measure=(not measure), - pershot=pershot, - ) - pcirc2, param2 = save_expval_circuit_parameterized( - pershot=pershot, - measure=measure, - snapshot=snapshot, - ) - circuits = [pcirc1] + circuits2to4 + [pcirc2] - if save_state: - for circuit in circuits: - circuit.save_statevector(pershot=pershot) - params = [param1, [], [], [], param2] - qobj = assemble(circuits, backend=backend, shots=shots, parameterizations=params) - return qobj - - def test_parameterized_qobj_qasm_save_expval(self): - """Test parameterized qobj with Expectation Value snapshot and qasm simulator.""" - shots = 1000 - labels = save_expval_labels() * 3 - counts_targets = save_expval_counts(shots) * 3 - value_targets = save_expval_pre_meas_values() * 3 - - backend = AerSimulator() - qobj = self.parameterized_qobj(backend=backend, shots=1000, measure=True, snapshot=True) - self.assertIn("parameterizations", qobj.to_dict()["config"]) - with self.assertWarns(DeprecationWarning): - job = backend.run(qobj, **self.BACKEND_OPTS) - result = job.result() - success = getattr(result, "success", False) - num_circs = len(result.to_dict()["results"]) - self.assertTrue(success) - self.compare_counts(result, range(num_circs), counts_targets, delta=0.1 * shots) - # Check snapshots - for j, target in enumerate(value_targets): - data = result.data(j) - for label in labels: - self.assertAlmostEqual(data[label], target[label], delta=1e-7) - - def test_parameterized_qobj_statevector(self): - """Test parameterized qobj with Expectation Value snapshot and qasm simulator.""" - statevec_targets = save_expval_final_statevecs() * 3 - - backend = AerSimulator(method="statevector") - qobj = self.parameterized_qobj( - backend=backend, - measure=False, - snapshot=False, - save_state=True, - ) - self.assertIn("parameterizations", qobj.to_dict()["config"]) - with self.assertWarns(DeprecationWarning): - job = backend.run(qobj, **self.BACKEND_OPTS) - result = job.result() - success = getattr(result, "success", False) - num_circs = len(result.to_dict()["results"]) - self.assertTrue(success) - - for j in range(num_circs): - statevector = result.get_statevector(j) - np.testing.assert_array_almost_equal( - statevector, statevec_targets[j].data, decimal=7 - ) - def test_run_path(self): """Test parameterized circuit path via backed.run()""" shots = 1000 diff --git a/test/terra/backends/test_runtime_parameterization.py b/test/terra/backends/test_runtime_parameterization.py index 24f8f0e4c3..3a0ba3da3c 100644 --- a/test/terra/backends/test_runtime_parameterization.py +++ b/test/terra/backends/test_runtime_parameterization.py @@ -56,89 +56,6 @@ class TestRuntimeParameterization(SimulatorTestCase): "runtime_parameter_bind_enable": True, } - @staticmethod - def runtime_parameterization( - backend, - shots=1000, - measure=True, - snapshot=False, - save_state=False, - ): - """Return ParameterizedQobj for settings.""" - pershot = shots == 1 - pcirc1, param1 = save_expval_circuit_parameterized( - pershot=pershot, - measure=measure, - snapshot=snapshot, - ) - circuits2to4 = save_expval_circuits( - pauli=True, - skip_measure=(not measure), - pershot=pershot, - ) - pcirc2, param2 = save_expval_circuit_parameterized( - pershot=pershot, - measure=measure, - snapshot=snapshot, - ) - circuits = [pcirc1] + circuits2to4 + [pcirc2] - if save_state: - for circuit in circuits: - circuit.save_statevector(pershot=pershot) - params = [param1, [], [], [], param2] - qobj = assemble(circuits, backend=backend, shots=shots, parameterizations=params) - return qobj - - def test_runtime_parameterization_qasm_save_expval(self): - """Test parameterized qobj with Expectation Value snapshot and qasm simulator.""" - shots = 1000 - labels = save_expval_labels() * 3 - counts_targets = save_expval_counts(shots) * 3 - value_targets = save_expval_pre_meas_values() * 3 - - backend = AerSimulator() - qobj = self.runtime_parameterization( - backend=backend, shots=1000, measure=True, snapshot=True - ) - self.assertIn("parameterizations", qobj.to_dict()["config"]) - with self.assertWarns(DeprecationWarning): - job = backend.run(qobj, **self.BACKEND_OPTS) - result = job.result() - success = getattr(result, "success", False) - num_circs = len(result.to_dict()["results"]) - self.assertTrue(success) - self.compare_counts(result, range(num_circs), counts_targets, delta=0.1 * shots) - # Check snapshots - for j, target in enumerate(value_targets): - data = result.data(j) - for label in labels: - self.assertAlmostEqual(data[label], target[label], delta=1e-7) - - def test_runtime_parameterization_statevector(self): - """Test parameterized qobj with Expectation Value snapshot and qasm simulator.""" - statevec_targets = save_expval_final_statevecs() * 3 - - backend = AerSimulator(method="statevector") - qobj = self.runtime_parameterization( - backend=backend, - measure=False, - snapshot=False, - save_state=True, - ) - self.assertIn("parameterizations", qobj.to_dict()["config"]) - with self.assertWarns(DeprecationWarning): - job = backend.run(qobj, **self.BACKEND_OPTS) - result = job.result() - success = getattr(result, "success", False) - num_circs = len(result.to_dict()["results"]) - self.assertTrue(success) - - for j in range(num_circs): - statevector = result.get_statevector(j) - np.testing.assert_array_almost_equal( - statevector, statevec_targets[j].data, decimal=7 - ) - @supported_methods(SUPPORTED_METHODS) def test_run_path(self, method, device): """Test parameterized circuit path via backed.run()""" diff --git a/test/terra/extensions/test_wrappers.py b/test/terra/extensions/test_wrappers.py deleted file mode 100644 index cc7e62b50a..0000000000 --- a/test/terra/extensions/test_wrappers.py +++ /dev/null @@ -1,69 +0,0 @@ -# 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. - - -import unittest -import copy -import pickle -from multiprocessing import Pool - -from qiskit import transpile, QuantumCircuit -from qiskit_aer.backends import AerSimulator -from qiskit_aer.backends.controller_wrappers import aer_controller_execute -from qiskit_aer.backends.backend_utils import LIBRARY_DIR -from test.terra.common import QiskitAerTestCase - - -class TestControllerExecuteWrappers(QiskitAerTestCase): - """Basic functionality tests for pybind-generated wrappers""" - - CFUNCS = [aer_controller_execute()] - - def test_deepcopy(self): - """Test that the functors are deepcopy-able.""" - for cfunc in self.CFUNCS: - cahpy = copy.deepcopy(cfunc) - - def test_pickleable(self): - """Test that the functors are pickle-able (directly).""" - for cfunc in self.CFUNCS: - bites = pickle.dumps(cfunc) - cahpy = pickle.loads(bites) - - def _create_qobj(self, backend, noise_model=None): - num_qubits = 2 - circuit = QuantumCircuit(num_qubits) - circuit.x(list(range(num_qubits))) - circuit = transpile(circuit, backend) - opts = {"max_parallel_threads": 1, "library_dir": LIBRARY_DIR, "noise_model": noise_model} - qobj = backend._assemble(circuit, **opts) - return qobj - - def _map_and_test(self, cfunc, qobj): - n = 2 - with Pool(processes=1) as p: - rs = p.map(cfunc, [copy.deepcopy(qobj) for _ in range(n)]) - - self.assertEqual(len(rs), n) - for r in rs: - self.assertTrue(r["success"]) - - def test_mappable_qasm(self): - """Test that the qasm controller can be mapped.""" - cfunc = aer_controller_execute() - sim = AerSimulator() - fqobj = self._create_qobj(sim) - self._map_and_test(cfunc, fqobj) - - -if __name__ == "__main__": - unittest.main()