diff --git a/docs/apidoc/index.rst b/docs/apidoc/index.rst index 763839335ef8..7cc1c54c23e1 100644 --- a/docs/apidoc/index.rst +++ b/docs/apidoc/index.rst @@ -18,8 +18,8 @@ API Reference assembler dagcircuit passmanager - providers_basicaer providers + providers_basic_provider providers_fake_provider providers_models pulse diff --git a/docs/apidoc/providers_basic_provider.rst b/docs/apidoc/providers_basic_provider.rst new file mode 100644 index 000000000000..d8647710a408 --- /dev/null +++ b/docs/apidoc/providers_basic_provider.rst @@ -0,0 +1,6 @@ +.. _qiskit-providers-basicprovider: + +.. automodule:: qiskit.providers.basic_provider + :no-members: + :no-inherited-members: + :no-special-members: diff --git a/docs/apidoc/providers_basicaer.rst b/docs/apidoc/providers_basicaer.rst deleted file mode 100644 index 8b4468130c19..000000000000 --- a/docs/apidoc/providers_basicaer.rst +++ /dev/null @@ -1,6 +0,0 @@ -.. _qiskit-providers-basicaer: - -.. automodule:: qiskit.providers.basicaer - :no-members: - :no-inherited-members: - :no-special-members: diff --git a/examples/python/ghz.py b/examples/python/ghz.py index a92e913c7003..51bafa9c2f66 100644 --- a/examples/python/ghz.py +++ b/examples/python/ghz.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -14,8 +14,8 @@ GHZ state example. It also compares running on experiment and simulator. """ -from qiskit import QuantumCircuit -from qiskit import BasicAer, transpile +from qiskit import QuantumCircuit, transpile +from qiskit.providers.basic_provider import BasicSimulator ############################################################### @@ -34,8 +34,8 @@ for i in range(num_qubits): qc.measure(i, i) -sim_backend = BasicAer.get_backend("qasm_simulator") +sim_backend = BasicSimulator() job = sim_backend.run(transpile(qc, sim_backend), shots=1024) result = job.result() -print("Qasm simulator : ") +print("Basic simulator : ") print(result.get_counts(qc)) diff --git a/examples/python/initialize.py b/examples/python/initialize.py index 30bb3c9c336d..3e47922d3304 100644 --- a/examples/python/initialize.py +++ b/examples/python/initialize.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -15,7 +15,8 @@ """ import math -from qiskit import QuantumCircuit, transpile, BasicAer +from qiskit import QuantumCircuit, transpile +from qiskit.providers.basic_provider import BasicSimulator ############################################################### @@ -58,7 +59,7 @@ print([format(abs(x * x), ".3f") for x in desired_vector]) # Initialize on local simulator -sim_backend = BasicAer.get_backend("qasm_simulator") +sim_backend = BasicSimulator() job = sim_backend.run(transpile(circuit, sim_backend), shots=shots) result = job.result() diff --git a/examples/python/load_qasm.py b/examples/python/load_qasm.py index c4ef7d97422d..af4878c41866 100644 --- a/examples/python/load_qasm.py +++ b/examples/python/load_qasm.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -13,14 +13,13 @@ """Example on how to load a file into a QuantumCircuit.""" from qiskit import QuantumCircuit -from qiskit import BasicAer +from qiskit.providers.basic_provider import BasicSimulator circ = QuantumCircuit.from_qasm_file("examples/qasm/entangled_registers.qasm") print(circ) # See the backend -sim_backend = BasicAer.get_backend("qasm_simulator") - +sim_backend = BasicSimulator() # Compile and run the Quantum circuit on a local simulator backend job_sim = sim_backend.run(circ) diff --git a/examples/python/qft.py b/examples/python/qft.py index 467b8042b61f..ca22d0d60538 100644 --- a/examples/python/qft.py +++ b/examples/python/qft.py @@ -16,7 +16,8 @@ import math from qiskit import QuantumCircuit -from qiskit import transpile, BasicAer +from qiskit import transpile +from qiskit.providers.basic_provider import BasicSimulator ############################################################### @@ -66,8 +67,8 @@ def qft(circ, n): print(qft4) print(qft5) -print("Qasm simulator") -sim_backend = BasicAer.get_backend("qasm_simulator") +print("Basic simulator") +sim_backend = BasicSimulator() job = sim_backend.run(transpile([qft3, qft4, qft5], sim_backend), shots=1024) result = job.result() print(result.get_counts(qft3)) diff --git a/examples/python/rippleadd.py b/examples/python/rippleadd.py index 6b02774b1c3c..6cb40f424c5b 100644 --- a/examples/python/rippleadd.py +++ b/examples/python/rippleadd.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -16,13 +16,13 @@ """ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit import BasicAer from qiskit import transpile +from qiskit.providers.basic_provider import BasicSimulator ############################################################### # Set the backend name and coupling map. ############################################################### -backend = BasicAer.get_backend("qasm_simulator") +backend = BasicSimulator() coupling_map = [ [0, 1], [0, 8], diff --git a/examples/python/teleport.py b/examples/python/teleport.py index c7ca3559c4c7..73d7fd61d22c 100644 --- a/examples/python/teleport.py +++ b/examples/python/teleport.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,14 +18,14 @@ """ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit -from qiskit import BasicAer from qiskit import transpile +from qiskit.providers.basic_provider import BasicSimulator ############################################################### # Set the backend name and coupling map. ############################################################### coupling_map = [[0, 1], [0, 2], [1, 2], [3, 2], [3, 4], [4, 2]] -backend = BasicAer.get_backend("qasm_simulator") +backend = BasicSimulator() ############################################################### # Make a quantum program for quantum teleportation. diff --git a/examples/python/using_qiskit_terra_level_0.py b/examples/python/using_qiskit_terra_level_0.py index 9414c83dda63..cd92701d22a2 100644 --- a/examples/python/using_qiskit_terra_level_0.py +++ b/examples/python/using_qiskit_terra_level_0.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -14,16 +14,13 @@ Example showing how to use Qiskit at introduction level. This example shows the most basic way to use Qiskit. It builds some circuits -and runs them on both the BasicAer (local Qiskit provider) or IBM Quantum (remote IBM Quantum provider). - -To control the compile parameters we have provided a transpile function which can be used -as a level 1 user. - +and runs them on the BasicProvider (local Qiskit provider). """ # Import the Qiskit modules from qiskit import QuantumCircuit -from qiskit import transpile, BasicAer +from qiskit import transpile +from qiskit.providers.basic_provider import BasicSimulator # making first circuit: bell state qc1 = QuantumCircuit(2, 2) @@ -36,12 +33,8 @@ qc2.h([0, 1]) qc2.measure([0, 1], [0, 1]) -# setting up the backend -print("(BasicAER Backends)") -print(BasicAer.backends()) - # running the job -sim_backend = BasicAer.get_backend("qasm_simulator") +sim_backend = BasicSimulator() job_sim = sim_backend.run(transpile([qc1, qc2], sim_backend)) sim_result = job_sim.result() diff --git a/qiskit/__init__.py b/qiskit/__init__.py index dd27ced4e75a..4109b14c0954 100644 --- a/qiskit/__init__.py +++ b/qiskit/__init__.py @@ -59,9 +59,6 @@ import qiskit.circuit.measure import qiskit.circuit.reset -# Please note these are global instances, not modules. -from qiskit.providers.basicaer import BasicAer - _config = _user_config.get_config() from qiskit.compiler import transpile, assemble, schedule, sequence @@ -70,7 +67,6 @@ __all__ = [ "AncillaRegister", - "BasicAer", "ClassicalRegister", "MissingOptionalLibraryError", "QiskitError", diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index a8d57f615d7c..f6e4618f0143 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -71,8 +71,7 @@ .. plot:: :include-source: - from qiskit import BasicAer, transpile, QuantumRegister, ClassicalRegister, QuantumCircuit - + from qiskit import transpile, QuantumRegister, ClassicalRegister, QuantumCircuit qr = QuantumRegister(1) cr = ClassicalRegister(1) qc = QuantumCircuit(qr, cr) @@ -82,7 +81,8 @@ .. code-block:: - backend = BasicAer.get_backend('qasm_simulator') + from qiskit.providers.basic_provider import BasicSimulator + backend = BasicSimulator() tqc = transpile(qc, backend) counts = backend.run(tqc).result().get_counts() @@ -100,7 +100,7 @@ .. plot:: :include-source: - from qiskit import BasicAer, transpile, QuantumRegister, ClassicalRegister, QuantumCircuit + from qiskit import transpile, QuantumRegister, ClassicalRegister, QuantumCircuit qr = QuantumRegister(1) cr = ClassicalRegister(1) @@ -115,7 +115,8 @@ .. code-block:: - backend = BasicAer.get_backend('qasm_simulator') + from qiskit.providers.basic_provider import BasicSimulator + backend = BasicSimulator() tqc = transpile(qc, backend) counts = backend.run(tqc).result().get_counts() diff --git a/qiskit/providers/basicaer/__init__.py b/qiskit/providers/basic_provider/__init__.py similarity index 50% rename from qiskit/providers/basicaer/__init__.py rename to qiskit/providers/basic_provider/__init__.py index d2ae5638e19f..48427c73fca0 100644 --- a/qiskit/providers/basicaer/__init__.py +++ b/qiskit/providers/basic_provider/__init__.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -11,20 +11,20 @@ # that they have been altered from the originals. """ -==================================================================== -BasicAer: Python-based Simulators (:mod:`qiskit.providers.basicaer`) -==================================================================== +================================================================================ +BasicProvider: Python-based Simulators (:mod:`qiskit.providers.basic_provider`) +================================================================================ -.. currentmodule:: qiskit.providers.basicaer +.. currentmodule:: qiskit.providers.basic_provider -A module of Python-based quantum simulators. Simulators are accessed -via the `BasicAer` provider, e.g.: +A module of Python-based quantum simulators. Simulators can be accessed +via the `BasicProvider` provider, e.g.: .. code-block:: - from qiskit import BasicAer + from qiskit.providers.basic_provider import BasicProvider - backend = BasicAer.get_backend('qasm_simulator') + backend = BasicProvider().get_backend('basic_simulator') Simulators @@ -33,9 +33,7 @@ .. autosummary:: :toctree: ../stubs/ - QasmSimulatorPy - StatevectorSimulatorPy - UnitarySimulatorPy + BasicSimulator Provider ======== @@ -43,7 +41,7 @@ .. autosummary:: :toctree: ../stubs/ - BasicAerProvider + BasicProvider Job Class ========= @@ -51,7 +49,7 @@ .. autosummary:: :toctree: ../stubs/ - BasicAerJob + BasicProviderJob Exceptions ========== @@ -59,15 +57,10 @@ .. autosummary:: :toctree: ../stubs/ - BasicAerError + BasicProviderError """ -from .basicaerprovider import BasicAerProvider -from .basicaerjob import BasicAerJob -from .qasm_simulator import QasmSimulatorPy -from .statevector_simulator import StatevectorSimulatorPy -from .unitary_simulator import UnitarySimulatorPy -from .exceptions import BasicAerError - -# Global instance to be used as the entry point for convenience. -BasicAer = BasicAerProvider() +from .basic_provider import BasicProvider +from .basic_provider_job import BasicProviderJob +from .basic_simulator import BasicSimulator +from .exceptions import BasicProviderError diff --git a/qiskit/providers/basic_provider/basic_provider.py b/qiskit/providers/basic_provider/basic_provider.py new file mode 100644 index 000000000000..9ae0009ddf5f --- /dev/null +++ b/qiskit/providers/basic_provider/basic_provider.py @@ -0,0 +1,101 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 2023. +# +# 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. + + +"""Provider for basic simulator backends, formerly known as `BasicAer`.""" + +from __future__ import annotations + +from collections.abc import Callable +from collections import OrderedDict +from typing import Type + +import logging + +from qiskit.exceptions import QiskitError +from qiskit.providers.backend import Backend +from qiskit.providers.provider import ProviderV1 +from qiskit.providers.exceptions import QiskitBackendNotFoundError +from qiskit.providers.providerutils import filter_backends + +from .basic_simulator import BasicSimulator + + +logger = logging.getLogger(__name__) + +SIMULATORS = [BasicSimulator] + + +class BasicProvider(ProviderV1): + """Provider for test simulators.""" + + def __init__(self) -> None: + super().__init__() + + # Populate the list of test backends (simulators) + self._backends = self._verify_backends() + + def get_backend(self, name: str | None = None, **kwargs) -> Backend: + return super().get_backend(name=name, **kwargs) + + def backends( + self, name: str | None = None, filters: Callable | None = None, **kwargs + ) -> list[Backend]: + backends = self._backends.values() + if name: + available = [ + backend.name() if backend.version == 1 else backend.name for backend in backends + ] + if name not in available: + raise QiskitBackendNotFoundError( + f"The '{name}' backend is not installed in your system." + ) + return filter_backends(backends, filters=filters, **kwargs) + + def _verify_backends(self) -> OrderedDict[str, Backend]: + """ + Return the test backends in `BACKENDS` that are + effectively available (as some of them might depend on the presence + of an optional dependency or on the existence of a binary). + + Returns: + dict[str:Backend]: a dict of test backend instances for + the backends that could be instantiated, keyed by backend name. + """ + ret = OrderedDict() + for backend_cls in SIMULATORS: + backend_instance = self._get_backend_instance(backend_cls) + backend_name = backend_instance.name + ret[backend_name] = backend_instance + return ret + + def _get_backend_instance(self, backend_cls: Type[Backend]) -> Backend: + """ + Return an instance of a backend from its class. + + Args: + backend_cls (class): backend class. + Returns: + Backend: a backend instance. + Raises: + QiskitError: if the backend could not be instantiated. + """ + # Verify that the backend can be instantiated. + try: + backend_instance = backend_cls(provider=self) + except Exception as err: + raise QiskitError(f"Backend {backend_cls} could not be instantiated: {err}") from err + + return backend_instance + + def __str__(self) -> str: + return "BasicProvider" diff --git a/qiskit/providers/basicaer/basicaerjob.py b/qiskit/providers/basic_provider/basic_provider_job.py similarity index 90% rename from qiskit/providers/basicaer/basicaerjob.py rename to qiskit/providers/basic_provider/basic_provider_job.py index 99c2f45bf86d..bc7dbf4781ee 100644 --- a/qiskit/providers/basicaer/basicaerjob.py +++ b/qiskit/providers/basic_provider/basic_provider_job.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -19,8 +19,8 @@ from qiskit.providers.job import JobV1 -class BasicAerJob(JobV1): - """BasicAerJob class.""" +class BasicProviderJob(JobV1): + """BasicProviderJob class.""" _async = False @@ -45,7 +45,7 @@ def result(self, timeout=None): if timeout is not None: warnings.warn( "The timeout kwarg doesn't have any meaning with " - "BasicAer because execution is synchronous and the " + "BasicProvider because execution is synchronous and the " "result already exists when run() returns.", UserWarning, ) diff --git a/qiskit/providers/basicaer/basicaertools.py b/qiskit/providers/basic_provider/basic_provider_tools.py similarity index 87% rename from qiskit/providers/basicaer/basicaertools.py rename to qiskit/providers/basic_provider/basic_provider_tools.py index 768febaecc75..030c629275ed 100644 --- a/qiskit/providers/basicaer/basicaertools.py +++ b/qiskit/providers/basic_provider/basic_provider_tools.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -10,12 +10,12 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Contains functions used by the basic aer simulators. +"""Contains functions used by the basic provider simulators. """ +from __future__ import annotations from string import ascii_uppercase, ascii_lowercase -from typing import List, Optional import numpy as np @@ -26,7 +26,7 @@ SINGLE_QUBIT_GATES = ("U", "u", "h", "p", "u1", "u2", "u3", "rz", "sx", "x") -def single_gate_matrix(gate: str, params: Optional[List[float]] = None): +def single_gate_matrix(gate: str, params: list[float] | None = None) -> np.ndarray: """Get the matrix for a single qubit. Args: @@ -73,12 +73,12 @@ def single_gate_matrix(gate: str, params: Optional[List[float]] = None): _CX_MATRIX = gates.CXGate().to_matrix() -def cx_gate_matrix(): +def cx_gate_matrix() -> np.ndarray: """Get the matrix for a controlled-NOT gate.""" - return np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex) + return _CX_MATRIX -def einsum_matmul_index(gate_indices, number_of_qubits): +def einsum_matmul_index(gate_indices: list[int], number_of_qubits: int) -> str: """Return the index string for Numpy.einsum matrix-matrix multiplication. The returned indices are to perform a matrix multiplication A.B where @@ -102,14 +102,10 @@ def einsum_matmul_index(gate_indices, number_of_qubits): # Combine indices into matrix multiplication string format # for numpy.einsum function - return "{mat_l}{mat_r}, ".format( - mat_l=mat_l, mat_r=mat_r - ) + "{tens_lin}{tens_r}->{tens_lout}{tens_r}".format( - tens_lin=tens_lin, tens_lout=tens_lout, tens_r=tens_r - ) + return f"{mat_l}{mat_r}, {tens_lin}{tens_r}->{tens_lout}{tens_r}" -def einsum_vecmul_index(gate_indices, number_of_qubits): +def einsum_vecmul_index(gate_indices: list[int], number_of_qubits: int) -> str: """Return the index string for Numpy.einsum matrix-vector multiplication. The returned indices are to perform a matrix multiplication A.v where @@ -130,12 +126,12 @@ def einsum_vecmul_index(gate_indices, number_of_qubits): # Combine indices into matrix multiplication string format # for numpy.einsum function - return f"{mat_l}{mat_r}, " + "{tens_lin}->{tens_lout}".format( - tens_lin=tens_lin, tens_lout=tens_lout - ) + return f"{mat_l}{mat_r}, {tens_lin}->{tens_lout}" -def _einsum_matmul_index_helper(gate_indices, number_of_qubits): +def _einsum_matmul_index_helper( + gate_indices: list[int], number_of_qubits: int +) -> tuple[str, str, str, str]: """Return the index string for Numpy.einsum matrix multiplication. The returned indices are to perform a matrix multiplication A.v where diff --git a/qiskit/providers/basicaer/qasm_simulator.py b/qiskit/providers/basic_provider/basic_simulator.py similarity index 70% rename from qiskit/providers/basicaer/qasm_simulator.py rename to qiskit/providers/basic_provider/basic_simulator.py index 03621e36c7b3..1042a91e5ac7 100644 --- a/qiskit/providers/basicaer/qasm_simulator.py +++ b/qiskit/providers/basic_provider/basic_simulator.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -12,20 +12,23 @@ """Contains a (slow) Python simulator. -It simulates an OpenQASM 2 quantum circuit (an experiment) that has been compiled +It simulates a quantum circuit (an experiment) that has been compiled to run on the simulator. It is exponential in the number of qubits. The simulator is run using .. code-block:: python - QasmSimulatorPy().run(run_input) + BasicSimulator().run(run_input) -Where the input is a QuantumCircuit object and the output is a BasicAerJob object, which can -later be queried for the Result object. The result will contain a 'memory' data +Where the input is a :class:`.QuantumCircuit` object and the output is a +:class:`.BasicProviderJob` object, +which can later be queried for the Result object. The result will contain a 'memory' data field, which is a result of measurements for each shot. """ +from __future__ import annotations + import uuid import time import logging @@ -34,97 +37,68 @@ from collections import Counter import numpy as np -from qiskit.providers.models import QasmBackendConfiguration -from qiskit.result import Result -from qiskit.providers.backend import BackendV1 +from qiskit.circuit import QuantumCircuit +from qiskit.circuit.library import UnitaryGate +from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping +from qiskit.providers import Provider +from qiskit.providers.backend import BackendV2 +from qiskit.providers.models import BackendConfiguration from qiskit.providers.options import Options -from qiskit.providers.basicaer.basicaerjob import BasicAerJob -from .exceptions import BasicAerError -from .basicaertools import single_gate_matrix -from .basicaertools import SINGLE_QUBIT_GATES -from .basicaertools import cx_gate_matrix -from .basicaertools import einsum_vecmul_index +from qiskit.qobj import QasmQobj, QasmQobjConfig, QasmQobjExperiment +from qiskit.result import Result +from qiskit.transpiler import Target + +from .basic_provider_job import BasicProviderJob +from .basic_provider_tools import single_gate_matrix +from .basic_provider_tools import SINGLE_QUBIT_GATES +from .basic_provider_tools import cx_gate_matrix +from .basic_provider_tools import einsum_vecmul_index +from .exceptions import BasicProviderError logger = logging.getLogger(__name__) -class QasmSimulatorPy(BackendV1): - """Python implementation of an OpenQASM 2 simulator.""" - - DEFAULT_CONFIGURATION = { - "backend_name": "qasm_simulator", - "backend_version": "2.1.0", - "n_qubits": 24, - "url": "https://github.com/Qiskit/qiskit-terra", - "simulator": True, - "local": True, - "conditional": True, - "open_pulse": False, - "memory": True, - "max_shots": 0, - "coupling_map": None, - "description": "A python simulator for qasm experiments", - "basis_gates": ["h", "u", "p", "u1", "u2", "u3", "rz", "sx", "x", "cx", "id", "unitary"], - "gates": [ - { - "name": "h", - "parameters": [], - "qasm_def": "gate h q { U(pi/2,0,pi) q; }", - }, - { - "name": "p", - "parameters": ["lambda"], - "qasm_def": "gate p(lambda) q { U(0,0,lambda) q; }", - }, - { - "name": "u", - "parameters": ["theta", "phi", "lambda"], - "qasm_def": "gate u(theta,phi,lambda) q { U(theta,phi,lambda) q; }", - }, - { - "name": "u1", - "parameters": ["lambda"], - "qasm_def": "gate u1(lambda) q { U(0,0,lambda) q; }", - }, - { - "name": "u2", - "parameters": ["phi", "lambda"], - "qasm_def": "gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }", - }, - { - "name": "u3", - "parameters": ["theta", "phi", "lambda"], - "qasm_def": "gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }", - }, - {"name": "rz", "parameters": ["phi"], "qasm_def": "gate rz(phi) q { U(0,0,phi) q; }"}, - { - "name": "sx", - "parameters": [], - "qasm_def": "gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }", - }, - {"name": "x", "parameters": [], "qasm_def": "gate x q { U(pi,7*pi/2,pi/2) q; }"}, - {"name": "cx", "parameters": [], "qasm_def": "gate cx c,t { CX c,t; }"}, - {"name": "id", "parameters": [], "qasm_def": "gate id a { U(0,0,0) a; }"}, - {"name": "unitary", "parameters": ["matrix"], "qasm_def": "unitary(matrix) q1, q2,..."}, - ], - } - - DEFAULT_OPTIONS = {"initial_statevector": None, "chop_threshold": 1e-15} - - # Class level variable to return the final state at the end of simulation - # This should be set to True for the statevector simulator - SHOW_FINAL_STATE = False - - def __init__(self, configuration=None, provider=None, **fields): +class BasicSimulator(BackendV2): + """Python implementation of a basic (non-efficient) quantum simulator.""" + + # Formerly calculated as `int(log2(local_hardware_info()["memory"]*(1024**3)/16))`. + # After the removal of `local_hardware_info()`, it's hardcoded to 24 qubits, + # which matches the ~268 MB of required memory. + MAX_QUBITS_MEMORY = 24 + + def __init__( + self, + provider: Provider | None = None, + target: Target | None = None, + **fields, + ) -> None: + """ + Args: + provider: An optional backwards reference to the + :class:`~qiskit.providers.Provider` object that the backend + is from. + target: An optional target to configure the simulator. + fields: kwargs for the values to use to override the default + options. + + Raises: + AttributeError: If a field is specified that's outside the backend's + options. + """ + super().__init__( - configuration=( - configuration or QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION) - ), provider=provider, + name="basic_simulator", + description="A python simulator for quantum experiments", + backend_version="0.1", **fields, ) - # Define attributes in __init__. - self._local_random = np.random.RandomState() + + self._target = target + self._configuration = None + + # Internal simulator variables + self._local_random = None self._classical_memory = 0 self._classical_register = 0 self._statevector = 0 @@ -135,11 +109,112 @@ def __init__(self, configuration=None, provider=None, **fields): self._initial_statevector = self.options.get("initial_statevector") self._chop_threshold = self.options.get("chop_threashold") self._qobj_config = None - # TEMP self._sample_measure = False + @property + def max_circuits(self) -> None: + return None + + @property + def target(self) -> Target: + if not self._target: + self._target = self._build_basic_target() + return self._target + + def _build_basic_target(self) -> Target: + """Helper method that returns a minimal target with a basis gate set but + no coupling map, instruction properties or calibrations. + + Returns: + The configured target. + """ + # Set num_qubits to None to signal the transpiler not to + # resize the circuit to fit a specific (potentially too large) + # number of qubits. The number of qubits in the circuits given to the + # `run` method will determine the size of the simulated statevector. + target = Target( + description="Basic Target", + num_qubits=None, + ) + basis_gates = [ + "h", + "u", + "p", + "u1", + "u2", + "u3", + "rz", + "sx", + "x", + "cx", + "id", + "unitary", + "measure", + "delay", + "reset", + ] + inst_mapping = get_standard_gate_name_mapping() + for name in basis_gates: + if name in inst_mapping: + instruction = inst_mapping[name] + target.add_instruction(instruction, properties=None, name=name) + elif name == "unitary": + # This is a placeholder for a UnitaryGate instance, + # to signal the transpiler not to decompose unitaries + # in the circuit. + target.add_instruction(UnitaryGate, name="unitary") + else: + raise BasicProviderError( + "Gate is not a valid basis gate for this simulator: %s" % name + ) + return target + + def configuration(self) -> BackendConfiguration: + """Return the simulator backend configuration. + + Returns: + The configuration for the backend. + """ + # Note: this is a custom attribute of the BasicSimulator class and + # not part of the BackendV2 interface. It has only been added for + # compatibility with the `assemble` function (currently used in `run`), + # which still relies on legacy BackendV1 attributes. Once the internal + # use of `assemble` is resolved, this attribute will no longer be + # necessary. + + if self._configuration: + return self._configuration + + gates = [ + { + "name": name, + "parameters": self.target.operation_from_name(name).params, + } + for name in self.target.operation_names + ] + + self._configuration = BackendConfiguration( + backend_name=self.name, + backend_version=self.backend_version, + n_qubits=self.num_qubits, + basis_gates=self.target.operation_names, + gates=gates, + local=True, + simulator=True, + conditional=True, + open_pulse=False, + memory=True, + # This max_shots is used by the assembler, setting it to 0 + # to maintain the behavior from the previous implementation. + # Not related to the actual shots set in the backend options + max_shots=0, + coupling_map=None, + description="A python simulator for quantum experiments", + ) + return self._configuration + @classmethod - def _default_options(cls): + def _default_options(cls) -> Options: return Options( shots=1024, memory=False, @@ -150,7 +225,7 @@ def _default_options(cls): parameter_binds=None, ) - def _add_unitary(self, gate, qubits): + def _add_unitary(self, gate: np.ndarray, qubits: list[int]) -> None: """Apply an N-qubit unitary matrix. Args: @@ -168,14 +243,14 @@ def _add_unitary(self, gate, qubits): indexes, gate_tensor, self._statevector, dtype=complex, casting="no" ) - def _get_measure_outcome(self, qubit): + def _get_measure_outcome(self, qubit: int) -> tuple[str, int]: """Simulate the outcome of measurement of a qubit. Args: - qubit (int): the qubit to measure + qubit: the qubit to measure Return: - tuple: pair (outcome, probability) where outcome is '0' or '1' and + pair (outcome, probability) where outcome is '0' or '1' and probability is the probability of the returned outcome. """ # Axis for numpy.sum to compute probabilities @@ -183,22 +258,24 @@ def _get_measure_outcome(self, qubit): axis.remove(self._number_of_qubits - 1 - qubit) probabilities = np.sum(np.abs(self._statevector) ** 2, axis=tuple(axis)) # Compute einsum index string for 1-qubit matrix multiplication - random_number = self._local_random.rand() + random_number = self._local_random.random() if random_number < probabilities[0]: return "0", probabilities[0] # Else outcome was '1' return "1", probabilities[1] - def _add_sample_measure(self, measure_params, num_samples): + def _add_sample_measure( + self, measure_params: list[list[int, int]], num_samples: int + ) -> list[hex]: """Generate memory samples from current statevector. Args: - measure_params (list): List of (qubit, cmembit) values for + measure_params: List of (qubit, cmembit) values for measure instructions to sample. - num_samples (int): The number of memory samples to generate. + num_samples: The number of memory samples to generate. Returns: - list: A list of memory values in hex format. + A list of memory values in hex format. """ # Get unique qubits that are actually measured and sort in # ascending order @@ -232,13 +309,13 @@ def _add_sample_measure(self, measure_params, num_samples): memory.append(hex(int(value, 2))) return memory - def _add_qasm_measure(self, qubit, cmembit, cregbit=None): + def _add_measure(self, qubit: int, cmembit: int, cregbit: int | None = None) -> None: """Apply a measure instruction to a qubit. Args: - qubit (int): qubit is the qubit measured. - cmembit (int): is the classical memory bit to store outcome in. - cregbit (int, optional): is the classical register bit to store outcome in. + qubit: qubit is the qubit measured. + cmembit: is the classical memory bit to store outcome in. + cregbit: is the classical register bit to store outcome in. """ # get measure outcome outcome, probability = self._get_measure_outcome(qubit) @@ -260,11 +337,11 @@ def _add_qasm_measure(self, qubit, cmembit, cregbit=None): # update classical state self._add_unitary(update_diag, [qubit]) - def _add_qasm_reset(self, qubit): + def _add_reset(self, qubit: int) -> None: """Apply a reset instruction to a qubit. Args: - qubit (int): the qubit being rest + qubit: the qubit being rest This is done by doing a simulating a measurement outcome and projecting onto the outcome state while @@ -280,20 +357,22 @@ def _add_qasm_reset(self, qubit): update = [[0, 1 / np.sqrt(probability)], [0, 0]] self._add_unitary(update, [qubit]) - def _validate_initial_statevector(self): + def _validate_initial_statevector(self) -> None: """Validate an initial statevector""" - # If initial statevector isn't set we don't need to validate + # If the initial statevector isn't set we don't need to validate if self._initial_statevector is None: return # Check statevector is correct length for number of qubits length = len(self._initial_statevector) required_dim = 2**self._number_of_qubits if length != required_dim: - raise BasicAerError( + raise BasicProviderError( f"initial statevector is incorrect length: {length} != {required_dim}" ) - def _set_options(self, qobj_config=None, backend_options=None): + def _set_options( + self, qobj_config: QasmQobjConfig | None = None, backend_options: dict | None = None + ) -> None: """Set the backend options for all experiments in a qobj""" # Reset default options self._initial_statevector = self.options.get("initial_statevector") @@ -316,7 +395,7 @@ def _set_options(self, qobj_config=None, backend_options=None): # Check the initial statevector is normalized norm = np.linalg.norm(self._initial_statevector) if round(norm, 12) != 1: - raise BasicAerError(f"initial statevector is not normalized: norm {norm} != 1") + raise BasicProviderError(f"initial statevector is not normalized: norm {norm} != 1") # Check for custom chop threshold # Replace with custom options if "chop_threshold" in backend_options: @@ -324,7 +403,7 @@ def _set_options(self, qobj_config=None, backend_options=None): elif hasattr(qobj_config, "chop_threshold"): self._chop_threshold = qobj_config.chop_threshold - def _initialize_statevector(self): + def _initialize_statevector(self) -> None: """Set the initial statevector for simulation""" if self._initial_statevector is None: # Set to default state of all qubits in |0> @@ -335,17 +414,11 @@ def _initialize_statevector(self): # Reshape to rank-N tensor self._statevector = np.reshape(self._statevector, self._number_of_qubits * [2]) - def _get_statevector(self): - """Return the current statevector""" - vec = np.reshape(self._statevector, 2**self._number_of_qubits) - vec[abs(vec) < self._chop_threshold] = 0.0 - return vec - - def _validate_measure_sampling(self, experiment): + def _validate_measure_sampling(self, experiment: QasmQobjExperiment) -> None: """Determine if measure sampling is allowed for an experiment Args: - experiment (QasmQobjExperiment): a qobj experiment. + experiment: a qobj experiment. """ # If shots=1 we should disable measure sampling. # This is also required for statevector simulator to return the @@ -381,15 +454,17 @@ def _validate_measure_sampling(self, experiment): # measure sampling is allowed self._sample_measure = True - def run(self, run_input, **backend_options): + def run( + self, run_input: QuantumCircuit | list[QuantumCircuit], **backend_options + ) -> BasicProviderJob: """Run on the backend. Args: - run_input (QuantumCircuit or list): payload of the experiment - backend_options (dict): backend options + run_input: payload of the experiment + backend_options: backend options Returns: - BasicAerJob: derived from BaseJob + BasicProviderJob: derived from BaseJob Additional Information: backend_options: Is a dict of options for the backend. It may contain @@ -406,6 +481,7 @@ def run(self, run_input, **backend_options): "initial_statevector": np.array([1, 0, 0, 1j]) / np.sqrt(2), } """ + # TODO: replace assemble with new run flow from qiskit.compiler import assemble out_options = {} @@ -420,18 +496,18 @@ def run(self, run_input, **backend_options): qobj_options = qobj.config self._set_options(qobj_config=qobj_options, backend_options=backend_options) job_id = str(uuid.uuid4()) - job = BasicAerJob(self, job_id, self._run_job(job_id, qobj)) + job = BasicProviderJob(self, job_id, self._run_job(job_id, qobj)) return job - def _run_job(self, job_id, qobj): + def _run_job(self, job_id: str, qobj: QasmQobj) -> Result: """Run experiments in qobj Args: - job_id (str): unique id for the job. - qobj (Qobj): job description + job_id: unique id for the job. + qobj: job description Returns: - Result: Result object + Result object """ self._validate(qobj) result_list = [] @@ -443,8 +519,8 @@ def _run_job(self, job_id, qobj): result_list.append(self.run_experiment(experiment)) end = time.time() result = { - "backend_name": self.name(), - "backend_version": self._configuration.backend_version, + "backend_name": self.name, + "backend_version": self.backend_version, "qobj_id": qobj.qobj_id, "job_id": job_id, "results": result_list, @@ -456,14 +532,14 @@ def _run_job(self, job_id, qobj): return Result.from_dict(result) - def run_experiment(self, experiment): + def run_experiment(self, experiment: QasmQobjExperiment) -> dict[str, ...]: """Run an experiment (circuit) and return a single experiment result. Args: - experiment (QasmQobjExperiment): experiment from qobj experiments list + experiment: experiment from qobj experiments list Returns: - dict: A result dictionary which looks something like:: + A result dictionary which looks something like:: { "name": name of this experiment (obtained from qobj.experiment header) @@ -479,7 +555,7 @@ def run_experiment(self, experiment): "time_taken": simulation time of this single experiment } Raises: - BasicAerError: if an error occurred. + BasicProviderError: if an error occurred. """ start = time.time() self._number_of_qubits = experiment.config.n_qubits @@ -489,8 +565,10 @@ def run_experiment(self, experiment): self._classical_register = 0 self._sample_measure = False global_phase = experiment.header.global_phase + # Validate the dimension of initial statevector if set self._validate_initial_statevector() + # Get the seed looking in circuit, qobj, and then random. if hasattr(experiment.config, "seed_simulator"): seed_simulator = experiment.config.seed_simulator @@ -501,7 +579,7 @@ def run_experiment(self, experiment): # and set the maximum value to be (2 ** 31) - 1 seed_simulator = np.random.randint(2147483647, dtype="int32") - self._local_random.seed(seed=seed_simulator) + self._local_random = np.random.default_rng(seed=seed_simulator) # Check if measure sampling is supported for current circuit self._validate_measure_sampling(experiment) @@ -538,7 +616,6 @@ def run_experiment(self, experiment): value >>= 1 if value != int(operation.conditional.val, 16): continue - # Check if single gate if operation.name == "unitary": qubits = operation.qubits @@ -560,7 +637,7 @@ def run_experiment(self, experiment): # Check if reset elif operation.name == "reset": qubit = operation.qubits[0] - self._add_qasm_reset(qubit) + self._add_reset(qubit) # Check if barrier elif operation.name == "barrier": pass @@ -576,7 +653,7 @@ def run_experiment(self, experiment): measure_sample_ops.append((qubit, cmembit)) else: # If not sampling perform measurement as normal - self._add_qasm_measure(qubit, cmembit, cregbit) + self._add_measure(qubit, cmembit, cregbit) elif operation.name == "bfunc": mask = int(operation.mask, 16) relation = operation.relation @@ -600,7 +677,7 @@ def run_experiment(self, experiment): elif relation == ">=": outcome = compared >= 0 else: - raise BasicAerError("Invalid boolean function relation.") + raise BasicProviderError("Invalid boolean function relation.") # Store outcome in register and optionally memory slot regbit = 1 << cregbit @@ -613,9 +690,9 @@ def run_experiment(self, experiment): int(outcome) << cmembit ) else: - backend = self.name() + backend = self.name err_msg = '{0} encountered unrecognized operation "{1}"' - raise BasicAerError(err_msg.format(backend, operation.name)) + raise BasicProviderError(err_msg.format(backend, operation.name)) # Add final creg data to memory list if self._number_of_cmembits > 0: @@ -632,14 +709,6 @@ def run_experiment(self, experiment): # Optionally add memory list if self._memory: data["memory"] = memory - # Optionally add final statevector - if self.SHOW_FINAL_STATE: - data["statevector"] = self._get_statevector() - # Remove empty counts and memory for statevector simulator - if not data["counts"]: - data.pop("counts") - if "memory" in data and not data["memory"]: - data.pop("memory") end = time.time() return { "name": experiment.header.name, @@ -652,14 +721,14 @@ def run_experiment(self, experiment): "header": experiment.header.to_dict(), } - def _validate(self, qobj): + def _validate(self, qobj: QasmQobj) -> None: """Semantic validations of the qobj which cannot be done via schemas.""" n_qubits = qobj.config.n_qubits - max_qubits = self.configuration().n_qubits + max_qubits = self.MAX_QUBITS_MEMORY if n_qubits > max_qubits: - raise BasicAerError( + raise BasicProviderError( f"Number of qubits {n_qubits} is greater than maximum ({max_qubits}) " - f'for "{self.name()}".' + f'for "{self.name}".' ) for experiment in qobj.experiments: name = experiment.header.name diff --git a/qiskit/providers/basicaer/exceptions.py b/qiskit/providers/basic_provider/exceptions.py similarity index 80% rename from qiskit/providers/basicaer/exceptions.py rename to qiskit/providers/basic_provider/exceptions.py index a973e4f73fe0..dc5923e77c54 100644 --- a/qiskit/providers/basicaer/exceptions.py +++ b/qiskit/providers/basic_provider/exceptions.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -11,14 +11,14 @@ # that they have been altered from the originals. """ -Exception for errors raised by Basic Aer. +Exception for errors raised by the Basic Provider. """ from qiskit.exceptions import QiskitError -class BasicAerError(QiskitError): - """Base class for errors raised by Basic Aer.""" +class BasicProviderError(QiskitError): + """Base class for errors raised by the Basic Provider.""" def __init__(self, *message): """Set the error message.""" diff --git a/qiskit/providers/basicaer/basicaerprovider.py b/qiskit/providers/basicaer/basicaerprovider.py deleted file mode 100644 index b46a83826a18..000000000000 --- a/qiskit/providers/basicaer/basicaerprovider.py +++ /dev/null @@ -1,127 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017. -# -# 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. - - -"""Provider for Basic Aer simulator backends.""" - -from collections import OrderedDict -import logging - -from qiskit.exceptions import QiskitError -from qiskit.providers.provider import ProviderV1 -from qiskit.providers.exceptions import QiskitBackendNotFoundError -from qiskit.providers.providerutils import resolve_backend_name, filter_backends - -from .qasm_simulator import QasmSimulatorPy -from .statevector_simulator import StatevectorSimulatorPy -from .unitary_simulator import UnitarySimulatorPy - - -logger = logging.getLogger(__name__) - -SIMULATORS = [QasmSimulatorPy, StatevectorSimulatorPy, UnitarySimulatorPy] - - -class BasicAerProvider(ProviderV1): - """Provider for Basic Aer backends.""" - - def __init__(self): - super().__init__() - - # Populate the list of Basic Aer backends. - self._backends = self._verify_backends() - - def get_backend(self, name=None, **kwargs): - backends = self._backends.values() - - # Special handling of the `name` parameter, to support alias resolution - # and deprecated names. - if name: - try: - resolved_name = resolve_backend_name( - name, backends, self._deprecated_backend_names(), {} - ) - name = resolved_name - except LookupError as ex: - raise QiskitBackendNotFoundError( - f"The '{name}' backend is not installed in your system." - ) from ex - - return super().get_backend(name=name, **kwargs) - - def backends(self, name=None, filters=None, **kwargs): - backends = self._backends.values() - - # Special handling of the `name` parameter, to support alias resolution - # and deprecated names. - if name: - try: - resolved_name = resolve_backend_name( - name, backends, self._deprecated_backend_names(), {} - ) - backends = [backend for backend in backends if backend.name() == resolved_name] - except LookupError: - return [] - - return filter_backends(backends, filters=filters, **kwargs) - - @staticmethod - def _deprecated_backend_names(): - """Returns deprecated backend names.""" - return { - "qasm_simulator_py": "qasm_simulator", - "statevector_simulator_py": "statevector_simulator", - "unitary_simulator_py": "unitary_simulator", - "local_qasm_simulator_py": "qasm_simulator", - "local_statevector_simulator_py": "statevector_simulator", - "local_unitary_simulator_py": "unitary_simulator", - "local_unitary_simulator": "unitary_simulator", - } - - def _verify_backends(self): - """ - Return the Basic Aer backends in `BACKENDS` that are - effectively available (as some of them might depend on the presence - of an optional dependency or on the existence of a binary). - - Returns: - dict[str:Backend]: a dict of Basic Aer backend instances for - the backends that could be instantiated, keyed by backend name. - """ - ret = OrderedDict() - for backend_cls in SIMULATORS: - backend_instance = self._get_backend_instance(backend_cls) - backend_name = backend_instance.name() - ret[backend_name] = backend_instance - return ret - - def _get_backend_instance(self, backend_cls): - """ - Return an instance of a backend from its class. - - Args: - backend_cls (class): backend class. - Returns: - Backend: a backend instance. - Raises: - QiskitError: if the backend could not be instantiated. - """ - # Verify that the backend can be instantiated. - try: - backend_instance = backend_cls(provider=self) - except Exception as err: - raise QiskitError(f"Backend {backend_cls} could not be instantiated: {err}") from err - - return backend_instance - - def __str__(self): - return "BasicAer" diff --git a/qiskit/providers/basicaer/statevector_simulator.py b/qiskit/providers/basicaer/statevector_simulator.py deleted file mode 100644 index 2939b8fd89d9..000000000000 --- a/qiskit/providers/basicaer/statevector_simulator.py +++ /dev/null @@ -1,117 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017. -# -# 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. - - -"""Contains a (slow) python statevector simulator. - -It simulates the statevector through a quantum circuit. It is exponential in -the number of qubits. - -We advise using the c++ simulator or online simulator for larger size systems. - -The input is a qobj dictionary and the output is a Result object. - -The input qobj to this simulator has no shots, no measures, no reset, no noise. -""" - -import logging -from qiskit.providers.basicaer.exceptions import BasicAerError -from qiskit.providers.models import QasmBackendConfiguration -from .qasm_simulator import QasmSimulatorPy - -logger = logging.getLogger(__name__) - - -class StatevectorSimulatorPy(QasmSimulatorPy): - """Python statevector simulator.""" - - DEFAULT_CONFIGURATION = { - "backend_name": "statevector_simulator", - "backend_version": "1.1.0", - "n_qubits": 24, - "url": "https://github.com/Qiskit/qiskit-terra", - "simulator": True, - "local": True, - "conditional": True, - "open_pulse": False, - "memory": True, - "max_shots": 0, - "coupling_map": None, - "description": "A Python statevector simulator for qobj files", - "basis_gates": ["u1", "u2", "u3", "rz", "sx", "x", "cx", "id", "unitary"], - "gates": [ - { - "name": "u1", - "parameters": ["lambda"], - "qasm_def": "gate u1(lambda) q { U(0,0,lambda) q; }", - }, - { - "name": "u2", - "parameters": ["phi", "lambda"], - "qasm_def": "gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }", - }, - { - "name": "u3", - "parameters": ["theta", "phi", "lambda"], - "qasm_def": "gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }", - }, - {"name": "rz", "parameters": ["phi"], "qasm_def": "gate rz(phi) q { U(0,0,phi) q; }"}, - { - "name": "sx", - "parameters": [], - "qasm_def": "gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }", - }, - {"name": "x", "parameters": [], "qasm_def": "gate x q { U(pi,7*pi/2,pi/2) q; }"}, - {"name": "cx", "parameters": [], "qasm_def": "gate cx c,t { CX c,t; }"}, - {"name": "id", "parameters": [], "qasm_def": "gate id a { U(0,0,0) a; }"}, - {"name": "unitary", "parameters": ["matrix"], "qasm_def": "unitary(matrix) q1, q2,..."}, - ], - } - - # Override base class value to return the final state vector - SHOW_FINAL_STATE = True - - def __init__(self, configuration=None, provider=None, **fields): - super().__init__( - configuration=( - configuration or QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION) - ), - provider=provider, - **fields, - ) - - def _validate(self, qobj): - """Semantic validations of the qobj which cannot be done via schemas. - Some of these may later move to backend schemas. - - 1. No shots - 2. No measurements in the middle - """ - num_qubits = qobj.config.n_qubits - max_qubits = self.configuration().n_qubits - if num_qubits > max_qubits: - raise BasicAerError( - f"Number of qubits {num_qubits} is greater than maximum ({max_qubits}) " - f'for "{self.name()}".' - ) - if qobj.config.shots != 1: - logger.info('"%s" only supports 1 shot. Setting shots=1.', self.name()) - qobj.config.shots = 1 - for experiment in qobj.experiments: - name = experiment.header.name - if getattr(experiment.config, "shots", 1) != 1: - logger.info( - '"%s" only supports 1 shot. Setting shots=1 for circuit "%s".', - self.name(), - name, - ) - experiment.config.shots = 1 diff --git a/qiskit/providers/basicaer/unitary_simulator.py b/qiskit/providers/basicaer/unitary_simulator.py deleted file mode 100644 index af101514adfb..000000000000 --- a/qiskit/providers/basicaer/unitary_simulator.py +++ /dev/null @@ -1,388 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017. -# -# 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. - -"""Contains a Python simulator that returns the unitary of the circuit. - -It simulates a unitary of a quantum circuit that has been compiled to run on -the simulator. It is exponential in the number of qubits. - -.. code-block:: python - - UnitarySimulator().run(run_input) - -Where the input is a either Qobj object (deprecated) or QuantumCircuit or a list of circuits and -the output is a BasicAerJob object, which can later be queried for the Result object. The result -will contain a 'unitary' data field, which is a 2**n x 2**n complex numpy array representing the -circuit's unitary matrix. -""" -import logging -import uuid -import time -import warnings - -import numpy as np - -from qiskit.providers.models import QasmBackendConfiguration -from qiskit.providers.backend import BackendV1 -from qiskit.providers.options import Options -from qiskit.providers.basicaer.basicaerjob import BasicAerJob -from qiskit.result import Result -from .exceptions import BasicAerError -from .basicaertools import single_gate_matrix -from .basicaertools import SINGLE_QUBIT_GATES -from .basicaertools import cx_gate_matrix -from .basicaertools import einsum_matmul_index - -logger = logging.getLogger(__name__) - - -# TODO add ["status"] = 'DONE', 'ERROR' especially for empty circuit error -# does not show up - - -class UnitarySimulatorPy(BackendV1): - """Python implementation of a unitary simulator.""" - - DEFAULT_CONFIGURATION = { - "backend_name": "unitary_simulator", - "backend_version": "1.1.0", - "n_qubits": 24, - "url": "https://github.com/Qiskit/qiskit-terra", - "simulator": True, - "local": True, - "conditional": False, - "open_pulse": False, - "memory": False, - "max_shots": 0, - "coupling_map": None, - "description": "A python simulator for unitary matrix corresponding to a circuit", - "basis_gates": ["u1", "u2", "u3", "rz", "sx", "x", "cx", "id", "unitary"], - "gates": [ - { - "name": "u1", - "parameters": ["lambda"], - "qasm_def": "gate u1(lambda) q { U(0,0,lambda) q; }", - }, - { - "name": "u2", - "parameters": ["phi", "lambda"], - "qasm_def": "gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }", - }, - { - "name": "u3", - "parameters": ["theta", "phi", "lambda"], - "qasm_def": "gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }", - }, - {"name": "rz", "parameters": ["phi"], "qasm_def": "gate rz(phi) q { U(0,0,phi) q; }"}, - { - "name": "sx", - "parameters": [], - "qasm_def": "gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }", - }, - {"name": "x", "parameters": [], "qasm_def": "gate x q { U(pi,7*pi/2,pi/2) q; }"}, - {"name": "cx", "parameters": [], "qasm_def": "gate cx c,t { CX c,t; }"}, - {"name": "id", "parameters": [], "qasm_def": "gate id a { U(0,0,0) a; }"}, - {"name": "unitary", "parameters": ["matrix"], "qasm_def": "unitary(matrix) q1, q2,..."}, - ], - } - - DEFAULT_OPTIONS = {"initial_unitary": None, "chop_threshold": 1e-15} - - def __init__(self, configuration=None, provider=None, **fields): - super().__init__( - configuration=( - configuration or QasmBackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION) - ), - provider=provider, - **fields, - ) - - # Define attributes inside __init__. - self._unitary = None - self._number_of_qubits = 0 - self._initial_unitary = None - self._global_phase = 0 - self._chop_threshold = self.options.get("chop_threshold") - - @classmethod - def _default_options(cls): - return Options(shots=1, initial_unitary=None, chop_threshold=1e-15, parameter_binds=None) - - def _add_unitary(self, gate, qubits): - """Apply an N-qubit unitary matrix. - - Args: - gate (matrix_like): an N-qubit unitary matrix - qubits (list): the list of N-qubits. - """ - # Get the number of qubits - num_qubits = len(qubits) - # Compute einsum index string for 1-qubit matrix multiplication - indexes = einsum_matmul_index(qubits, self._number_of_qubits) - # Convert to complex rank-2N tensor - gate_tensor = np.reshape(np.array(gate, dtype=complex), num_qubits * [2, 2]) - # Apply matrix multiplication - self._unitary = np.einsum(indexes, gate_tensor, self._unitary, dtype=complex, casting="no") - - def _validate_initial_unitary(self): - """Validate an initial unitary matrix""" - # If initial unitary isn't set we don't need to validate - if self._initial_unitary is None: - return - # Check unitary is correct length for number of qubits - shape = np.shape(self._initial_unitary) - required_shape = (2**self._number_of_qubits, 2**self._number_of_qubits) - if shape != required_shape: - raise BasicAerError( - f"initial unitary is incorrect shape: {shape} != 2 ** {required_shape}" - ) - - def _set_options(self, qobj_config=None, backend_options=None): - """Set the backend options for all experiments in a qobj""" - # Reset default options - self._initial_unitary = self.options.get("initial_unitary") - self._chop_threshold = self.options.get("chop_threshold") - if "backend_options" in backend_options: - backend_options = backend_options["backend_options"] - - # Check for custom initial statevector in backend_options first, - # then config second - if "initial_unitary" in backend_options and backend_options["initial_unitary"] is not None: - self._initial_unitary = np.array(backend_options["initial_unitary"], dtype=complex) - elif hasattr(qobj_config, "initial_unitary"): - self._initial_unitary = np.array(qobj_config.initial_unitary, dtype=complex) - if self._initial_unitary is not None: - # Check the initial unitary is actually unitary - shape = np.shape(self._initial_unitary) - if len(shape) != 2 or shape[0] != shape[1]: - raise BasicAerError("initial unitary is not a square matrix") - iden = np.eye(len(self._initial_unitary)) - u_dagger_u = np.dot(self._initial_unitary.T.conj(), self._initial_unitary) - norm = np.linalg.norm(u_dagger_u - iden) - if round(norm, 10) != 0: - raise BasicAerError("initial unitary is not unitary") - # Check the initial statevector is normalized - - # Check for custom chop threshold - # Replace with custom options - if "chop_threshold" in backend_options: - self._chop_threshold = backend_options["chop_threshold"] - elif hasattr(qobj_config, "chop_threshold"): - self._chop_threshold = qobj_config.chop_threshold - - def _initialize_unitary(self): - """Set the initial unitary for simulation""" - self._validate_initial_unitary() - if self._initial_unitary is None: - # Set to identity matrix - self._unitary = np.eye(2**self._number_of_qubits, dtype=complex) - else: - self._unitary = self._initial_unitary.copy() - # Reshape to rank-N tensor - self._unitary = np.reshape(self._unitary, self._number_of_qubits * [2, 2]) - - def _get_unitary(self): - """Return the current unitary""" - unitary = np.reshape(self._unitary, 2 * [2**self._number_of_qubits]) - if self._global_phase: - unitary *= np.exp(1j * float(self._global_phase)) - unitary[abs(unitary) < self._chop_threshold] = 0.0 - return unitary - - def run(self, run_input, **backend_options): - """Run experiments in run_input asynchronously. - - Args: - run_input (Qobj, QuantumCircuit, list): payload of the experiment - backend_options (dict): backend options - - Returns: - BasicAerJob: derived from BaseJob - - Additional Information:: - - backend_options: Is a dict of options for the backend. It may contain - * "initial_unitary": matrix_like - * "chop_threshold": double - - The "initial_unitary" option specifies a custom initial unitary - matrix for the simulator to be used instead of the identity - matrix. This size of this matrix must be correct for the number - of qubits in all experiments in the run_input. - - The "chop_threshold" option specifies a truncation value for - setting small values to zero in the output unitary. The default - value is 1e-15. - - Example:: - - backend_options = { - "initial_unitary": np.array([[1, 0, 0, 0], - [0, 0, 0, 1], - [0, 0, 1, 0], - [0, 1, 0, 0]]) - "chop_threshold": 1e-15 - } - """ - from qiskit.compiler import assemble - - out_options = {} - for key in backend_options: - if not hasattr(self.options, key): - warnings.warn( - "Option %s is not used by this backend" % key, UserWarning, stacklevel=2 - ) - else: - out_options[key] = backend_options[key] - qobj = assemble(run_input, self, **out_options) - qobj_options = qobj.config - - self._set_options(qobj_config=qobj_options, backend_options=backend_options) - job_id = str(uuid.uuid4()) - job = BasicAerJob(self, job_id, self._run_job(job_id, qobj)) - return job - - def _run_job(self, job_id, qobj): - """Run experiments in qobj. - - Args: - job_id (str): unique id for the job. - qobj (Qobj): job description - - Returns: - Result: Result object - """ - self._validate(qobj) - result_list = [] - start = time.time() - for experiment in qobj.experiments: - result_list.append(self.run_experiment(experiment)) - end = time.time() - result = { - "backend_name": self.name(), - "backend_version": self._configuration.backend_version, - "qobj_id": qobj.qobj_id, - "job_id": job_id, - "results": result_list, - "status": "COMPLETED", - "success": True, - "time_taken": (end - start), - "header": qobj.header.to_dict(), - } - - return Result.from_dict(result) - - def run_experiment(self, experiment): - """Run an experiment (circuit) and return a single experiment result. - - Args: - experiment (QasmQobjExperiment): experiment from qobj experiments list - - Returns: - dict: A result dictionary which looks something like:: - - { - "name": name of this experiment (obtained from qobj.experiment header) - "seed": random seed used for simulation - "shots": number of shots used in the simulation - "data": - { - "unitary": [[[0.0, 0.0], [1.0, 0.0]], - [[1.0, 0.0], [0.0, 0.0]]] - }, - "status": status string for the simulation - "success": boolean - "time taken": simulation time of this single experiment - } - - Raises: - BasicAerError: if the number of qubits in the circuit is greater than 24. Note that the - practical qubit limit is much lower than 24. - """ - start = time.time() - self._number_of_qubits = experiment.header.n_qubits - self._global_phase = experiment.header.global_phase - - # Validate the dimension of initial unitary if set - self._validate_initial_unitary() - self._initialize_unitary() - - for operation in experiment.instructions: - if operation.name == "unitary": - qubits = operation.qubits - gate = operation.params[0] - self._add_unitary(gate, qubits) - # Check if single gate - elif operation.name in SINGLE_QUBIT_GATES: - params = getattr(operation, "params", None) - qubit = operation.qubits[0] - gate = single_gate_matrix(operation.name, params) - self._add_unitary(gate, [qubit]) - elif operation.name in ("id", "u0"): - pass - # Check if CX gate - elif operation.name in ("CX", "cx"): - qubit0 = operation.qubits[0] - qubit1 = operation.qubits[1] - gate = cx_gate_matrix() - self._add_unitary(gate, [qubit0, qubit1]) - # Check if barrier - elif operation.name == "barrier": - pass - else: - backend = self.name() - err_msg = '{0} encountered unrecognized operation "{1}"' - raise BasicAerError(err_msg.format(backend, operation.name)) - # Add final state to data - data = {"unitary": self._get_unitary()} - end = time.time() - return { - "name": experiment.header.name, - "shots": 1, - "data": data, - "status": "DONE", - "success": True, - "time_taken": (end - start), - "header": experiment.header.to_dict(), - } - - def _validate(self, qobj): - """Semantic validations of the qobj which cannot be done via schemas. - Some of these may later move to backend schemas. - 1. No shots - 2. No measurements in the middle - """ - n_qubits = qobj.config.n_qubits - max_qubits = self.configuration().n_qubits - if n_qubits > max_qubits: - raise BasicAerError( - f"Number of qubits {n_qubits} is greater than maximum ({max_qubits}) " - f'for "{self.name()}".' - ) - if hasattr(qobj.config, "shots") and qobj.config.shots != 1: - logger.info('"%s" only supports 1 shot. Setting shots=1.', self.name()) - qobj.config.shots = 1 - for experiment in qobj.experiments: - name = experiment.header.name - if getattr(experiment.config, "shots", 1) != 1: - logger.info( - '"%s" only supports 1 shot. Setting shots=1 for circuit "%s".', - self.name(), - name, - ) - experiment.config.shots = 1 - for operation in experiment.instructions: - if operation.name in ["measure", "reset"]: - raise BasicAerError( - f'Unsupported "{self.name()}" instruction "{operation.name}"' - f' in circuit "{name}".' - ) diff --git a/qiskit/providers/fake_provider/fake_backend.py b/qiskit/providers/fake_provider/fake_backend.py index c228b947dd83..449ab20ae4dd 100644 --- a/qiskit/providers/fake_provider/fake_backend.py +++ b/qiskit/providers/fake_provider/fake_backend.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -30,7 +30,7 @@ from qiskit import pulse from qiskit.exceptions import QiskitError from qiskit.utils import optionals as _optionals -from qiskit.providers import basicaer +from qiskit.providers import basic_provider from qiskit.transpiler import Target from qiskit.providers.backend_compat import convert_to_target @@ -129,7 +129,7 @@ def _setup_sim(self): self.set_options(noise_model=noise_model) else: - self.sim = basicaer.QasmSimulatorPy() + self.sim = basic_provider.BasicSimulator() def _get_conf_dict_from_json(self): if not self.conf_filename: @@ -203,7 +203,7 @@ def _default_options(cls): return AerSimulator._default_options() else: - return basicaer.QasmSimulatorPy._default_options() + return basic_provider.BasicSimulator._default_options() @property def dtm(self) -> float: @@ -302,12 +302,12 @@ def run(self, run_input, **options): This method runs circuit jobs (an individual or a list of QuantumCircuit ) and pulse jobs (an individual or a list of Schedule or ScheduleBlock) - using BasicAer or Aer simulator and returns a + using a :class:`.BasicSimulator` or Aer simulator and returns a :class:`~qiskit.providers.Job` object. If qiskit-aer is installed, jobs will be run using AerSimulator with noise model of the fake backend. Otherwise, jobs will be run using - BasicAer simulator without noise. + :class:`.BasicSimulator` without noise. Currently noisy simulation of a pulse job is not supported yet in FakeBackendV2. @@ -351,7 +351,7 @@ def run(self, run_input, **options): raise QiskitError("Pulse simulation is currently not supported for fake backends.") # circuit job if not _optionals.HAS_AER: - warnings.warn("Aer not found using BasicAer and no noise", RuntimeWarning) + warnings.warn("Aer not found using BasicProvider and no noise", RuntimeWarning) if self.sim is None: self._setup_sim() self.sim._options = self._options @@ -469,7 +469,7 @@ def _setup_sim(self): # it when run() is called self.set_options(noise_model=noise_model) else: - self.sim = basicaer.QasmSimulatorPy() + self.sim = basic_provider.BasicSimulator() def properties(self): """Return backend properties""" @@ -530,7 +530,7 @@ def _default_options(cls): return QasmSimulator._default_options() else: - return basicaer.QasmSimulatorPy._default_options() + return basic_provider.BasicSimulator._default_options() def run(self, run_input, **kwargs): """Main job in simulator""" diff --git a/qiskit/providers/fake_provider/fake_backend_v2.py b/qiskit/providers/fake_provider/fake_backend_v2.py index 96cd6dff9d37..b14b87bc35a8 100644 --- a/qiskit/providers/fake_provider/fake_backend_v2.py +++ b/qiskit/providers/fake_provider/fake_backend_v2.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021. +# (C) Copyright IBM 2021, 2023. # # 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 @@ -31,7 +31,7 @@ from qiskit.providers.backend import BackendV2, QubitProperties from qiskit.providers.options import Options from qiskit.transpiler import Target, InstructionProperties -from qiskit.providers.basicaer.qasm_simulator import QasmSimulatorPy +from qiskit.providers.basic_provider.basic_simulator import BasicSimulator class FakeBackendV2(BackendV2): @@ -181,7 +181,7 @@ def run(self, run_input, **options): class FakeBackendSimple(BackendV2): - """A fake simple backend that wraps BasicAer to implement run().""" + """A fake simple backend that wraps BasicSimulator to implement run().""" def __init__(self): super().__init__( @@ -198,7 +198,7 @@ def __init__(self): self._target.add_instruction(RZGate(self._lam)) self._target.add_instruction(CXGate()) self._target.add_instruction(Measure()) - self._runner = QasmSimulatorPy() + self._runner = BasicSimulator() @property def target(self): @@ -210,7 +210,7 @@ def max_circuits(self): @classmethod def _default_options(cls): - return QasmSimulatorPy._default_options() + return BasicSimulator._default_options() def run(self, run_input, **options): self._runner._options = self._options diff --git a/qiskit/providers/fake_provider/generic_backend_v2.py b/qiskit/providers/fake_provider/generic_backend_v2.py index 33f69a2ddaba..ab038ecd0af7 100644 --- a/qiskit/providers/fake_provider/generic_backend_v2.py +++ b/qiskit/providers/fake_provider/generic_backend_v2.py @@ -33,7 +33,7 @@ from qiskit.exceptions import QiskitError from qiskit.transpiler import CouplingMap, Target, InstructionProperties, QubitProperties from qiskit.providers import Options -from qiskit.providers.basicaer import BasicAer +from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.backend import BackendV2 from qiskit.providers.models import ( PulseDefaults, @@ -441,12 +441,12 @@ def run(self, run_input, **options): This method runs circuit jobs (an individual or a list of :class:`~.QuantumCircuit` ) and pulse jobs (an individual or a list of :class:`~.Schedule` or - :class:`~.ScheduleBlock`) using :class:`~.BasicAer` or Aer simulator and returns a + :class:`~.ScheduleBlock`) using :class:`~.BasicSimulator` or Aer simulator and returns a :class:`~qiskit.providers.Job` object. If qiskit-aer is installed, jobs will be run using the ``AerSimulator`` with noise model of the backend. Otherwise, jobs will be run using the - ``BasicAer`` simulator without noise. + ``BasicSimulator`` simulator without noise. Noisy simulations of pulse jobs are not yet supported in :class:`~.GenericBackendV2`. @@ -489,7 +489,7 @@ def run(self, run_input, **options): raise QiskitError("Pulse simulation is currently not supported for V2 backends.") # circuit job if not _optionals.HAS_AER: - warnings.warn("Aer not found using BasicAer and no noise", RuntimeWarning) + warnings.warn("Aer not found using BasicSimulator and no noise", RuntimeWarning) if self._sim is None: self._setup_sim() self._sim._options = self._options @@ -508,7 +508,7 @@ def _setup_sim(self) -> None: # it when run() is called self.set_options(noise_model=noise_model) else: - self._sim = BasicAer.get_backend("qasm_simulator") + self._sim = BasicSimulator() @classmethod def _default_options(cls) -> Options: @@ -517,7 +517,7 @@ def _default_options(cls) -> Options: return AerSimulator._default_options() else: - return BasicAer.get_backend("qasm_simulator")._default_options() + return BasicSimulator._default_options() def drive_channel(self, qubit: int): drive_channels_map = getattr(self, "channels_map", {}).get("drive", {}) diff --git a/qiskit/providers/provider.py b/qiskit/providers/provider.py index 2bd4efa7081a..9bea69c1ea85 100644 --- a/qiskit/providers/provider.py +++ b/qiskit/providers/provider.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 diff --git a/qiskit/providers/providerutils.py b/qiskit/providers/providerutils.py index edd83c6dbe24..1e65499d756a 100644 --- a/qiskit/providers/providerutils.py +++ b/qiskit/providers/providerutils.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -11,13 +11,17 @@ # that they have been altered from the originals. """Utilities for providers.""" +from __future__ import annotations import logging +from collections.abc import Callable + +from qiskit.providers.backend import Backend logger = logging.getLogger(__name__) -def filter_backends(backends, filters=None, **kwargs): +def filter_backends(backends: list[Backend], filters: Callable = None, **kwargs) -> list[Backend]: """Return the backends matching the specified filtering. Filter the `backends` list by their `configuration` or `status` @@ -65,7 +69,9 @@ def _match_all(obj, criteria): return backends -def resolve_backend_name(name, backends, deprecated, aliased): +def resolve_backend_name( + name: str, backends: list[Backend], deprecated: dict[str, str], aliased: dict[str, list[str]] +) -> str: """Resolve backend name from a deprecated name or an alias. A group will be resolved in order of member priorities, depending on @@ -84,7 +90,10 @@ def resolve_backend_name(name, backends, deprecated, aliased): LookupError: if name cannot be resolved through regular available names, nor deprecated, nor alias names. """ - available = [backend.name() for backend in backends] + # account for BackendV2 + available = [] + for backend in backends: + available.append(backend.name() if backend.version == 1 else backend.name) resolved_name = deprecated.get(name, aliased.get(name, name)) if isinstance(resolved_name, list): diff --git a/qiskit/quantum_info/analysis/distance.py b/qiskit/quantum_info/analysis/distance.py index d24bb1f580df..1041bce2e157 100644 --- a/qiskit/quantum_info/analysis/distance.py +++ b/qiskit/quantum_info/analysis/distance.py @@ -76,8 +76,9 @@ def hellinger_fidelity(dist_p: dict, dist_q: dict) -> float: .. code-block:: - from qiskit import QuantumCircuit, BasicAer + from qiskit import QuantumCircuit from qiskit.quantum_info.analysis import hellinger_fidelity + from qiskit.providers.basic_provider import BasicSimulator qc = QuantumCircuit(5, 5) qc.h(2) @@ -87,7 +88,7 @@ def hellinger_fidelity(dist_p: dict, dist_q: dict) -> float: qc.cx(1, 0) qc.measure(range(5), range(5)) - sim = BasicAer.get_backend('qasm_simulator') + sim = BasicSimulator() res1 = sim.run(qc).result() res2 = sim.run(qc).result() diff --git a/qiskit/test/base.py b/qiskit/test/base.py index eae6c6de32c3..953d02b853f5 100644 --- a/qiskit/test/base.py +++ b/qiskit/test/base.py @@ -172,9 +172,9 @@ def tearDown(self): super().tearDown() # Reset the default providers, as in practice they acts as a singleton # due to importing the instances from the top-level qiskit namespace. - from qiskit.providers.basicaer import BasicAer + from qiskit.providers.basic_provider import BasicProvider - BasicAer._backends = BasicAer._verify_backends() + BasicProvider()._backends = BasicProvider()._verify_backends() @classmethod def setUpClass(cls): diff --git a/qiskit/transpiler/passes/layout/full_ancilla_allocation.py b/qiskit/transpiler/passes/layout/full_ancilla_allocation.py index 72d2c6f2c4d0..bdfced0d084b 100644 --- a/qiskit/transpiler/passes/layout/full_ancilla_allocation.py +++ b/qiskit/transpiler/passes/layout/full_ancilla_allocation.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -81,7 +81,7 @@ def run(self, dag): idle_physical_qubits = [q for q in layout_physical_qubits if q not in physical_bits] - if self.target: + if self.target is not None and self.target.num_qubits is not None: idle_physical_qubits = [ q for q in range(self.target.num_qubits) if q not in physical_bits ] diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index cafc0a5a7382..0cc8fee34aee 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -94,7 +94,8 @@ def __init__(self, basis=None, target=None): self.error_map = self._build_error_map() def _build_error_map(self): - if self._target is not None: + # include path for when target exists but target.num_qubits is None (BasicSimulator) + if self._target is not None and self._target.num_qubits is not None: error_map = euler_one_qubit_decomposer.OneQubitGateErrorMap(self._target.num_qubits) for qubit in range(self._target.num_qubits): gate_error = {} @@ -118,7 +119,8 @@ def _resynthesize_run(self, matrix, qubit=None): When multiple synthesis options are available, it prefers the one with the lowest error when the circuit is applied to `qubit`. """ - if self._target: + # include path for when target exists but target.num_qubits is None (BasicSimulator) + if self._target is not None and self._target.num_qubits is not None: if qubit is not None: qubits_tuple = (qubit,) else: @@ -128,9 +130,9 @@ def _resynthesize_run(self, matrix, qubit=None): else: available_1q_basis = set(self._target.operation_names_for_qargs(qubits_tuple)) decomposers = _possible_decomposers(available_1q_basis) - self._local_decomposers_cache[qubits_tuple] = decomposers else: decomposers = self._global_decomposers + best_synth_circuit = euler_one_qubit_decomposer.unitary_to_gate_sequence( matrix, decomposers, diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index da10a8102887..bb8023bba15e 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -216,7 +216,8 @@ def __init__( self._top_level_only = self._basis_gates is None and self._target is None - if not self._top_level_only and self._target is None: + # include path for when target exists but target.num_qubits is None (BasicSimulator) + if not self._top_level_only and (self._target is None or self._target.num_qubits is None): basic_insts = {"measure", "reset", "barrier", "snapshot", "delay"} self._device_insts = basic_insts | set(self._basis_gates) @@ -314,12 +315,13 @@ def _recursively_handle_op( controlled_gate_open_ctrl = isinstance(op, ControlledGate) and op._open_ctrl if not controlled_gate_open_ctrl: qargs = tuple(qubits) if qubits is not None else None + # include path for when target exists but target.num_qubits is None (BasicSimulator) inst_supported = ( self._target.instruction_supported( operation_name=op.name, qargs=qargs, ) - if self._target is not None + if self._target is not None and self._target.num_qubits is not None else op.name in self._device_insts ) if inst_supported or (self._equiv_lib is not None and self._equiv_lib.has_entry(op)): diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index b958fc7b404b..8d609ce3b8a3 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2021 +# (C) Copyright IBM 2021, 2023. # # 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 @@ -696,6 +696,9 @@ def operation_names_for_qargs(self, qargs): Raises: KeyError: If ``qargs`` is not in target """ + # if num_qubits == 0, we will return globally defined operations + if self.num_qubits == 0 or self.num_qubits is None: + qargs = None if qargs is not None and any(x not in range(0, self.num_qubits) for x in qargs): raise KeyError(f"{qargs} not in target.") res = self._qarg_gate_map.get(qargs, set()) @@ -778,6 +781,9 @@ def check_obj_params(parameters, obj): return False return True + # Handle case where num_qubits is None by always checking globally supported operations + if self.num_qubits is None: + qargs = None # Case a list if passed in by mistake if qargs is not None: qargs = tuple(qargs) @@ -1474,7 +1480,9 @@ def target_to_backend_properties(target: Target): } ) else: - qubit_props: dict[int, Any] = {x: None for x in range(target.num_qubits)} + qubit_props: dict[int, Any] = {} + if target.num_qubits is not None: + qubit_props = {x: None for x in range(target.num_qubits)} for qargs, props in qargs_list.items(): if qargs is None: continue diff --git a/releasenotes/notes/refactor-basicaer-to-basicprovider-e27aff9c8e81d26e.yaml b/releasenotes/notes/refactor-basicaer-to-basicprovider-e27aff9c8e81d26e.yaml new file mode 100644 index 000000000000..6c7643129473 --- /dev/null +++ b/releasenotes/notes/refactor-basicaer-to-basicprovider-e27aff9c8e81d26e.yaml @@ -0,0 +1,92 @@ +--- +upgrade: + - | + The ``qiskit.providers.basicaer`` module, exposed as ``qiskit.BasicAer``, + has been removed following it deprecation on the 0.46 release. Its + functionality has been replaced by the :mod:`qiskit.quantum_info` + module and the new :mod:`qiskit.providers.basic_provider` module. + + The migration from using ``qiskit.providers.basicaer`` (``qiskit.BasicAer``) + to :mod:`qiskit.providers.basic_provider` can be performed as follows:: + + Migrate from | Replace with + ------------------------------------------------------------------------------ + ``qiskit.BasicAer`` | # The new provider doesn't have a global instance, + | # imports should be from qiskit.providers.basic_provider + ``qiskit.providers.basicaer`` | :mod:`.basic_provider` + ``BasicAerProvider`` | :class:`.BasicProvider` + ``BasicAerJob`` | :class:`.BasicProviderJob` + ``QasmSimulatorPy`` | :class:`.BasicSimulator` + ``UnitarySimulatorPy`` | use :class:`~.quantum_info.Operator` + ``StatevectorSimulatorPy`` | use :class:`~.quantum_info.Statevector` + + A notable difference is that the new provider is no longer exposed through a global instance + (like ``BasicAer``), so it will not be valid to do ``from qiskit import BasicProvider``. + Instead, the provider class must be imported from its submodule and instantiated manually:: + + from qiskit.providers.basic_provider import BasicProvider + provider = BasicProvider() + backend = provider.get_backend("sim_name") + + The following examples show the migration paths of the three simulators in ``BasicAer``. + + 1. Statevector simulator:: + + from qiskit import QuantumCircuit + qc = QuantumCircuit(3) + qc.h(0) + qc.h(1) + qc.cx(1,2) + qc.measure_all() + + # Former path + from qiskit import BasicAer + backend = BasicAer.get_backend("statevector_simulator") + statevector = backend.run(qc).result().get_statevector() + + # New path + qc.remove_final_measurements() # no measurements allowed + from qiskit.quantum_info import Statevector + statevector = Statevector(qc) + + 2. Unitary simulator:: + + from qiskit import QuantumCircuit + qc = QuantumCircuit(3) + qc.h(0) + qc.h(1) + qc.cx(1,2) + qc.measure_all() + + # Former path + from qiskit import BasicAer + backend = BasicAer.get_backend("unitary_simulator") + result = backend.run(qc).result() + + # New path + qc.remove_final_measurements() # no measurements allowed + from qiskit.quantum_info import Operator + result = Operator(qc).data + + 3. Qasm simulator:: + + from qiskit import QuantumCircuit + qc = QuantumCircuit(3) + qc.h(0) + qc.h(1) + qc.cx(1,2) + qc.measure_all() + + # Former path + from qiskit import BasicAer + backend = BasicAer.get_backend("qasm_simulator") + result = backend.run(qc).result() + + # New path + from qiskit.providers.basic_provider import BasicProvider + backend = BasicProvider().get_backend("basic_simulator") + result = backend.run(qc).result() + # or, directly + from qiskit.providers.basic_provider import BasicSimulator + backend = BasicSimulator() + result = backend.run(qc).result() diff --git a/test/python/basicaer/test_basicaer_backends.py b/test/python/basicaer/test_basicaer_backends.py deleted file mode 100644 index fcb18ca6cb3a..000000000000 --- a/test/python/basicaer/test_basicaer_backends.py +++ /dev/null @@ -1,72 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2018. -# -# 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. - -"""BasicAer Backends Test.""" - -from qiskit import BasicAer -from qiskit.providers.basicaer import BasicAerProvider -from qiskit.providers.exceptions import QiskitBackendNotFoundError -from qiskit.test import QiskitTestCase - - -class TestBasicAerBackends(QiskitTestCase): - """Qiskit BasicAer Backends (Object) Tests.""" - - def setUp(self): - super().setUp() - self.provider = BasicAerProvider() - self.backend_name = "qasm_simulator" - - def test_backends(self): - """Test the provider has backends.""" - backends = self.provider.backends() - self.assertTrue(len(backends) > 0) - - def test_get_backend(self): - """Test getting a backend from the provider.""" - backend = self.provider.get_backend(name=self.backend_name) - self.assertEqual(backend.name(), self.backend_name) - - def test_deprecated(self): - """Test that deprecated names map the same backends as the new names.""" - - def _get_first_available_backend(provider, backend_names): - """Gets the first available backend.""" - if isinstance(backend_names, str): - backend_names = [backend_names] - for backend_name in backend_names: - try: - return provider.get_backend(backend_name).name() - except QiskitBackendNotFoundError: - pass - return None - - deprecated_names = BasicAer._deprecated_backend_names() - for oldname, newname in deprecated_names.items(): - expected = ( - "WARNING:qiskit.providers.providerutils:Backend '%s' is deprecated. " - "Use '%s'." % (oldname, newname) - ) - with self.subTest(oldname=oldname, newname=newname): - with self.assertLogs("qiskit.providers.providerutils", level="WARNING") as context: - resolved_newname = _get_first_available_backend(BasicAer, newname) - real_backend = BasicAer.get_backend(resolved_newname) - self.assertEqual(BasicAer.backends(oldname)[0], real_backend) - self.assertEqual(context.output, [expected]) - - def test_aliases_fail(self): - """Test a failing backend lookup.""" - self.assertRaises(QiskitBackendNotFoundError, BasicAer.get_backend, "bad_name") - - def test_aliases_return_empty_list(self): - """Test backends() return an empty list if name is unknown.""" - self.assertEqual(BasicAer.backends("bad_name"), []) diff --git a/test/python/basicaer/test_statevector_simulator.py b/test/python/basicaer/test_statevector_simulator.py deleted file mode 100644 index a819aa7bd3ae..000000000000 --- a/test/python/basicaer/test_statevector_simulator.py +++ /dev/null @@ -1,125 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2018. -# -# 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. -"""Test StateVectorSimulatorPy.""" - -import unittest - -import numpy as np - -from qiskit.providers.basicaer import StatevectorSimulatorPy -from qiskit import QuantumRegister, QuantumCircuit, transpile -from qiskit.quantum_info.random import random_unitary -from qiskit.quantum_info import state_fidelity -from qiskit.test import QiskitTestCase - -from . import BasicAerBackendTestMixin - - -class StatevectorSimulatorTest(QiskitTestCase, BasicAerBackendTestMixin): - """Test BasicAer statevector simulator.""" - - def setUp(self): - super().setUp() - self.backend = StatevectorSimulatorPy() - bell = QuantumCircuit(2, 2) - bell.h(0) - bell.cx(0, 1) - bell.measure([0, 1], [0, 1]) - self.circuit = bell - - def test_run_circuit(self): - """Test final state vector for single circuit run.""" - # Override base circuit with no measurement. - bell = QuantumCircuit(2) - bell.h(0) - bell.cx(0, 1) - self.circuit = bell - # Execute - result = super().test_run_circuit() - actual = result.get_statevector(self.circuit) - - # state is 1/sqrt(2)|00> + 1/sqrt(2)|11>, up to a global phase - self.assertAlmostEqual((abs(actual[0])) ** 2, 1 / 2) - self.assertEqual(actual[1], 0) - self.assertEqual(actual[2], 0) - self.assertAlmostEqual((abs(actual[3])) ** 2, 1 / 2) - - def test_measure_collapse(self): - """Test final measurement collapses statevector""" - result = super().test_run_circuit() - actual = result.get_statevector(self.circuit) - - # The final state should be EITHER |00> OR |11> - diff_00 = np.linalg.norm(np.array([1, 0, 0, 0]) - actual) ** 2 - diff_11 = np.linalg.norm(np.array([0, 0, 0, 1]) - actual) ** 2 - success = np.allclose([diff_00, diff_11], [0, 2]) or np.allclose([diff_00, diff_11], [2, 0]) - # state is 1/sqrt(2)|00> + 1/sqrt(2)|11>, up to a global phase - self.assertTrue(success) - - def test_unitary(self): - """Test unitary gate instruction""" - num_trials = 10 - max_qubits = 3 - # Test 1 to max_qubits for random n-qubit unitary gate - for i in range(max_qubits): - num_qubits = i + 1 - psi_init = np.zeros(2**num_qubits) - psi_init[0] = 1.0 - qr = QuantumRegister(num_qubits, "qr") - for _ in range(num_trials): - # Create random unitary - unitary = random_unitary(2**num_qubits) - # Compute expected output state - psi_target = unitary.data.dot(psi_init) - # Simulate output on circuit - circuit = QuantumCircuit(qr) - circuit.unitary(unitary, qr) - job = self.backend.run(transpile(circuit, self.backend)) - result = job.result() - psi_out = result.get_statevector(0) - fidelity = state_fidelity(psi_target, psi_out) - self.assertGreater(fidelity, 0.999) - - def test_global_phase(self): - """Test global_phase""" - n_qubits = 4 - qr = QuantumRegister(n_qubits) - circ = QuantumCircuit(qr) - circ.x(qr) - circ.global_phase = 0.5 - self.circuit = circ - result = super().test_run_circuit() - actual = result.get_statevector(self.circuit) - expected = np.exp(1j * circ.global_phase) * np.repeat([[0], [1]], [n_qubits**2 - 1, 1]) - self.assertTrue(np.allclose(actual, expected)) - - def test_global_phase_composite(self): - """Test global_phase""" - n_qubits = 4 - qr = QuantumRegister(n_qubits) - circ = QuantumCircuit(qr) - circ.x(qr) - circ.global_phase = 0.5 - gate = circ.to_gate() - - comp = QuantumCircuit(qr) - comp.append(gate, qr) - comp.global_phase = 0.1 - self.circuit = comp - result = super().test_run_circuit() - actual = result.get_statevector(self.circuit) - expected = np.exp(1j * 0.6) * np.repeat([[0], [1]], [n_qubits**2 - 1, 1]) - self.assertTrue(np.allclose(actual, expected)) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/python/basicaer/test_unitary_simulator.py b/test/python/basicaer/test_unitary_simulator.py deleted file mode 100644 index 673b3eef5bd4..000000000000 --- a/test/python/basicaer/test_unitary_simulator.py +++ /dev/null @@ -1,144 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017. -# -# 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. - -"""Tests for unitary simulator.""" - -import unittest - -import numpy as np - -from qiskit import transpile -from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister -from qiskit.test import QiskitTestCase -from qiskit.providers.basicaer import UnitarySimulatorPy -from qiskit.quantum_info.operators.predicates import matrix_equal -from qiskit.quantum_info.random import random_unitary -from qiskit.quantum_info import process_fidelity, Operator - -from . import BasicAerBackendTestMixin - - -class BasicAerUnitarySimulatorPyTest(QiskitTestCase, BasicAerBackendTestMixin): - """Test BasicAer unitary simulator.""" - - def setUp(self): - super().setUp() - self.backend = UnitarySimulatorPy() - bell = QuantumCircuit(2) - bell.h(0) - bell.cx(0, 1) - self.circuit = bell - - def test_basicaer_unitary_simulator_py(self): - """Test unitary simulator.""" - circuits = self._test_circuits() - job = self.backend.run(transpile(circuits, self.backend)) - sim_unitaries = [job.result().get_unitary(circ) for circ in circuits] - reference_unitaries = self._reference_unitaries() - for u_sim, u_ref in zip(sim_unitaries, reference_unitaries): - self.assertTrue(matrix_equal(u_sim, u_ref, ignore_phase=True)) - - def _test_circuits(self): - """Return test circuits for unitary simulator""" - qr = QuantumRegister(3) - cr = ClassicalRegister(3) - qc1 = QuantumCircuit(qr, cr) - qc2 = QuantumCircuit(qr, cr) - qc3 = QuantumCircuit(qr, cr) - qc4 = QuantumCircuit(qr, cr) - qc5 = QuantumCircuit(qr, cr) - # Test circuit 1: HxHxH - qc1.h(qr) - # Test circuit 2: IxCX - qc2.cx(qr[0], qr[1]) - # Test circuit 3: CXxY - qc3.y(qr[0]) - qc3.cx(qr[1], qr[2]) - # Test circuit 4: (CX.I).(IxCX).(IxIxX) - qc4.h(qr[0]) - qc4.cx(qr[0], qr[1]) - qc4.cx(qr[1], qr[2]) - # Test circuit 5 (X.Z)x(Z.Y)x(Y.X) - qc5.x(qr[0]) - qc5.y(qr[0]) - qc5.y(qr[1]) - qc5.z(qr[1]) - qc5.z(qr[2]) - qc5.x(qr[2]) - return [qc1, qc2, qc3, qc4, qc5] - - def _reference_unitaries(self): - """Return reference unitaries for test circuits""" - # Gate matrices - gate_h = np.array([[1, 1], [1, -1]]) / np.sqrt(2) - gate_x = np.array([[0, 1], [1, 0]]) - gate_y = np.array([[0, -1j], [1j, 0]]) - gate_z = np.array([[1, 0], [0, -1]]) - gate_cx = np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0.0, 0, 1, 0], [0, 1, 0, 0]]) - # Unitary matrices - target_unitary1 = np.kron(np.kron(gate_h, gate_h), gate_h) - target_unitary2 = np.kron(np.eye(2), gate_cx) - target_unitary3 = np.kron(gate_cx, gate_y) - target_unitary4 = np.dot( - np.kron(gate_cx, np.eye(2)), - np.dot(np.kron(np.eye(2), gate_cx), np.kron(np.eye(4), gate_h)), - ) - target_unitary5 = np.kron( - np.kron(np.dot(gate_x, gate_z), np.dot(gate_z, gate_y)), np.dot(gate_y, gate_x) - ) - return [target_unitary1, target_unitary2, target_unitary3, target_unitary4, target_unitary5] - - def test_unitary(self): - """Test unitary gate instruction""" - num_trials = 10 - max_qubits = 3 - # Test 1 to max_qubits for random n-qubit unitary gate - for i in range(max_qubits): - num_qubits = i + 1 - unitary_init = Operator(np.eye(2**num_qubits)) - qr = QuantumRegister(num_qubits, "qr") - for _ in range(num_trials): - # Create random unitary - unitary = random_unitary(2**num_qubits) - # Compute expected output state - unitary_target = unitary.dot(unitary_init) - # Simulate output on circuit - circuit = QuantumCircuit(qr) - circuit.unitary(unitary, qr) - job = self.backend.run(transpile(circuit, self.backend)) - result = job.result() - unitary_out = Operator(result.get_unitary(0)) - fidelity = process_fidelity(unitary_target, unitary_out) - self.assertGreater(fidelity, 0.999) - - def test_global_phase(self): - """Test global phase for XZH - See https://github.com/Qiskit/qiskit-terra/issues/3083""" - - q = QuantumRegister(1) - circuit = QuantumCircuit(q) - circuit.h(q[0]) - circuit.z(q[0]) - circuit.x(q[0]) - - job = self.backend.run(transpile(circuit, self.backend)) - result = job.result() - - unitary_out = result.get_unitary(circuit) - unitary_target = np.array( - [[-1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 1 / np.sqrt(2)]] - ) - self.assertTrue(np.allclose(unitary_out, unitary_target)) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/python/circuit/library/test_functional_pauli_rotations.py b/test/python/circuit/library/test_functional_pauli_rotations.py index 69cf5bcaa2ac..638608c95690 100644 --- a/test/python/circuit/library/test_functional_pauli_rotations.py +++ b/test/python/circuit/library/test_functional_pauli_rotations.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,13 +18,13 @@ from ddt import ddt, data, unpack from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import ( LinearPauliRotations, PolynomialPauliRotations, PiecewiseLinearPauliRotations, ) +from qiskit.quantum_info import Statevector @ddt @@ -38,10 +38,7 @@ def assertFunctionIsCorrect(self, function_circuit, reference): circuit = QuantumCircuit(num_state_qubits + 1 + num_ancilla_qubits) circuit.h(list(range(num_state_qubits))) circuit.append(function_circuit.to_instruction(), list(range(circuit.num_qubits))) - - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() - + statevector = Statevector(circuit) probabilities = defaultdict(float) for i, statevector_amplitude in enumerate(statevector): i = bin(i)[2:].zfill(circuit.num_qubits)[num_ancilla_qubits:] diff --git a/test/python/circuit/library/test_integer_comparator.py b/test/python/circuit/library/test_integer_comparator.py index 7491883c748e..7de451975d5f 100644 --- a/test/python/circuit/library/test_integer_comparator.py +++ b/test/python/circuit/library/test_integer_comparator.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -17,9 +17,9 @@ from ddt import ddt, data, unpack from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import IntegerComparator +from qiskit.quantum_info import Statevector @ddt @@ -33,8 +33,7 @@ def assertComparisonIsCorrect(self, comp, num_state_qubits, value, geq): qc.append(comp, list(range(comp.num_qubits))) # add comparator # run simulation - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(qc, backend)).result().get_statevector() + statevector = Statevector(qc) for i, amplitude in enumerate(statevector): prob = np.abs(amplitude) ** 2 if prob > 1e-6: diff --git a/test/python/circuit/library/test_linear_amplitude_function.py b/test/python/circuit/library/test_linear_amplitude_function.py index b7c15bab2d9e..24147e12377e 100644 --- a/test/python/circuit/library/test_linear_amplitude_function.py +++ b/test/python/circuit/library/test_linear_amplitude_function.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,10 +18,10 @@ from ddt import ddt, data, unpack import numpy as np -from qiskit import BasicAer, transpile from qiskit.test.base import QiskitTestCase from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import LinearAmplitudeFunction +from qiskit.quantum_info import Statevector @ddt @@ -36,10 +36,7 @@ def assertFunctionIsCorrect(self, function_circuit, reference): circuit = QuantumCircuit(function_circuit.num_qubits) circuit.h(list(range(num_state_qubits))) circuit.append(function_circuit.to_instruction(), list(range(circuit.num_qubits))) - - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() - + statevector = Statevector(circuit) probabilities = defaultdict(float) for i, statevector_amplitude in enumerate(statevector): i = bin(i)[2:].zfill(circuit.num_qubits)[num_ancillas:] diff --git a/test/python/circuit/library/test_phase_estimation.py b/test/python/circuit/library/test_phase_estimation.py index 8a423128ad2a..71b13e6f8c1e 100644 --- a/test/python/circuit/library/test_phase_estimation.py +++ b/test/python/circuit/library/test_phase_estimation.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -63,7 +63,7 @@ def assertPhaseEstimationIsCorrect( inplace=True, ) circuit.compose(pec, inplace=True) - actual = Statevector.from_instruction(circuit).data + actual = Statevector(circuit) np.testing.assert_almost_equal(reference, actual) def test_phase_estimation(self): diff --git a/test/python/circuit/library/test_piecewise_chebyshev.py b/test/python/circuit/library/test_piecewise_chebyshev.py index aaa87cde268c..f0d738ec9e29 100644 --- a/test/python/circuit/library/test_piecewise_chebyshev.py +++ b/test/python/circuit/library/test_piecewise_chebyshev.py @@ -18,9 +18,9 @@ from ddt import ddt, data, unpack from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile from qiskit.circuit import QuantumCircuit from qiskit.circuit.library.arithmetic.piecewise_chebyshev import PiecewiseChebyshev +from qiskit.quantum_info import Statevector @ddt @@ -35,10 +35,7 @@ def assertFunctionIsCorrect(self, function_circuit, reference): circuit = QuantumCircuit(num_state_qubits + 1 + num_ancilla_qubits) circuit.h(list(range(num_state_qubits))) circuit.append(function_circuit.to_instruction(), list(range(circuit.num_qubits))) - - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() - + statevector = Statevector(circuit) probabilities = defaultdict(float) for i, statevector_amplitude in enumerate(statevector): i = bin(i)[2:].zfill(circuit.num_qubits)[num_ancilla_qubits:] diff --git a/test/python/circuit/library/test_weighted_adder.py b/test/python/circuit/library/test_weighted_adder.py index afc824cbe5c4..4003588bbc0c 100644 --- a/test/python/circuit/library/test_weighted_adder.py +++ b/test/python/circuit/library/test_weighted_adder.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,9 +18,9 @@ import numpy as np from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile from qiskit.circuit import QuantumCircuit from qiskit.circuit.library import WeightedAdder +from qiskit.quantum_info import Statevector @ddt @@ -34,8 +34,7 @@ def assertSummationIsCorrect(self, adder): circuit.h(list(range(adder.num_state_qubits))) circuit.append(adder.to_instruction(), list(range(adder.num_qubits))) - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() + statevector = Statevector(circuit) probabilities = defaultdict(float) for i, statevector_amplitude in enumerate(statevector): diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 9002e0e08460..f368acbc2980 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -16,7 +16,7 @@ import numpy as np from ddt import data, ddt -from qiskit import BasicAer, ClassicalRegister, QuantumCircuit, QuantumRegister +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister from qiskit.circuit import Gate, Instruction, Measure, Parameter, Barrier from qiskit.circuit.bit import Bit from qiskit.circuit.classicalregister import Clbit @@ -27,6 +27,7 @@ from qiskit.circuit.quantumcircuit import BitLocations from qiskit.circuit.quantumcircuitdata import CircuitInstruction from qiskit.circuit.quantumregister import AncillaQubit, AncillaRegister, Qubit +from qiskit.providers.basic_provider import BasicSimulator from qiskit.pulse import DriveChannel, Gaussian, Play, Schedule from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase @@ -186,7 +187,7 @@ def test_compose_circuit(self): qc2.measure(qr[1], cr[1]) qc3 = qc1.compose(qc2) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc3, shots=shots, seed_simulator=78).result() counts = result.get_counts() @@ -208,7 +209,7 @@ def test_compose_circuit_and(self): qc2.measure(qr[1], cr[1]) qc3 = qc1 & qc2 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc3, shots=shots, seed_simulator=78).result() counts = result.get_counts() @@ -230,7 +231,7 @@ def test_compose_circuit_iand(self): qc2.measure(qr[1], cr[1]) qc1 &= qc2 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc1, shots=shots, seed_simulator=78).result() counts = result.get_counts() @@ -280,7 +281,7 @@ def test_tensor_circuit(self): qc1.measure(0, 0) qc3 = qc1.tensor(qc2) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc3, shots=shots, seed_simulator=78).result() counts = result.get_counts() @@ -301,7 +302,7 @@ def test_tensor_circuit_xor(self): qc1.measure(0, 0) qc3 = qc1 ^ qc2 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc3, shots=shots, seed_simulator=78).result() counts = result.get_counts() @@ -322,7 +323,7 @@ def test_tensor_circuit_ixor(self): qc1.measure(0, 0) qc1 ^= qc2 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() shots = 1024 result = backend.run(qc1, shots=shots, seed_simulator=78).result() counts = result.get_counts() diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 39042ae3d3ac..5f9a29e80242 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -19,7 +19,7 @@ from numpy import pi from ddt import ddt, data, unpack -from qiskit import QuantumRegister, QuantumCircuit, BasicAer, QiskitError, transpile +from qiskit import QuantumRegister, QuantumCircuit, QiskitError from qiskit.test import QiskitTestCase from qiskit.circuit import ControlledGate, Parameter, Gate from qiskit.circuit.singleton import SingletonControlledGate, _SingletonControlledGateOverrides @@ -424,21 +424,13 @@ def test_multi_control_u1(self): c_cu1 = cu1gate.control(1) qc_cu1.append(c_cu1, qr, []) - backend = BasicAer.get_backend("unitary_simulator") - job = backend.run( - transpile( - [qcnu1, qu1, qcu1, qc_cu1], backend, basis_gates=["u1", "u2", "u3", "id", "cx"] - ), - ) - result = job.result() - # Circuit unitaries - mat_cnu1 = result.get_unitary(0) + mat_cnu1 = Operator(qcnu1).data # trace out ancillae - mat_u1 = result.get_unitary(1) - mat_cu1 = result.get_unitary(2) - mat_c_cu1 = result.get_unitary(3) + mat_u1 = Operator(qu1).data + mat_cu1 = Operator(qcu1).data + mat_c_cu1 = Operator(qc_cu1).data # Target Controlled-U1 unitary target_cnu1 = _compute_control_matrix(mat_u1, num_ctrl) @@ -489,7 +481,6 @@ def test_multi_controlled_u1_matrix(self, num_controls): qc.x(q_controls[idx]) simulated = Operator(qc) - base = PhaseGate(lam).to_matrix() expected = _compute_control_matrix(base, num_controls, ctrl_state=ctrl_state) with self.subTest(msg=f"control state = {ctrl_state}"): @@ -518,9 +509,8 @@ def test_multi_control_toffoli_matrix_clean_ancillas(self, num_controls): # apply hadamard on control qubits and toffoli gate qc.mcx(q_controls, q_target[0], q_ancillas, mode="basic") - # execute the circuit and obtain statevector result - backend = BasicAer.get_backend("unitary_simulator") - simulated = backend.run(transpile(qc, backend)).result().get_unitary(qc) + # obtain unitary for circuit + simulated = Operator(qc).data # compare to expectation if num_ancillas > 0: @@ -551,8 +541,7 @@ def test_multi_control_toffoli_matrix_basic_dirty_ancillas(self, num_controls): qc.mcx(q_controls, q_target[0], q_ancillas, mode="basic-dirty-ancilla") - simulator = BasicAer.get_backend("unitary_simulator") - simulated = simulator.run(transpile(qc, simulator)).result().get_unitary(qc) + simulated = Operator(qc).data if num_ancillas > 0: simulated = simulated[: 2 ** (num_controls + 1), : 2 ** (num_controls + 1)] @@ -581,8 +570,7 @@ def test_multi_control_toffoli_matrix_advanced_dirty_ancillas(self, num_controls qc.mcx(q_controls, q_target[0], q_ancillas, mode="advanced") - simulator = BasicAer.get_backend("unitary_simulator") - simulated = simulator.run(transpile(qc, simulator)).result().get_unitary(qc) + simulated = Operator(qc).data if num_ancillas > 0: simulated = simulated[: 2 ** (num_controls + 1), : 2 ** (num_controls + 1)] @@ -603,8 +591,7 @@ def test_multi_control_toffoli_matrix_noancilla_dirty_ancillas(self, num_control qc.mcx(q_controls, q_target[0], None, mode="noancilla") - simulator = BasicAer.get_backend("unitary_simulator") - simulated = simulator.run(transpile(qc, simulator)).result().get_unitary(qc) + simulated = Operator(qc) base = XGate().to_matrix() expected = _compute_control_matrix(base, num_controls) @@ -665,8 +652,7 @@ def test_multi_controlled_rotation_gate_matrices( gates_used = set(qc.count_ops().keys()) self.assertTrue(gates_used.issubset({"x", "u", "p", "cx"})) - backend = BasicAer.get_backend("unitary_simulator") - simulated = backend.run(transpile(qc, backend)).result().get_unitary(qc) + simulated = Operator(qc) if base_gate_name == "x": rot_mat = RXGate(theta).to_matrix() @@ -724,9 +710,8 @@ def test_multi_controlled_y_rotation_matrix_basic_mode(self, num_controls, use_b qc.x(q_controls[idx]) rot_mat = RYGate(theta).to_matrix() + simulated = Operator(qc).data - backend = BasicAer.get_backend("unitary_simulator") - simulated = backend.run(transpile(qc, backend)).result().get_unitary(qc) if num_ancillas > 0: simulated = simulated[: 2 ** (num_controls + 1), : 2 ** (num_controls + 1)] @@ -766,7 +751,6 @@ def test_mcxgraycode_gates_yield_explicit_gates(self, num_ctrl_qubits): @data(3, 4, 5, 8) def test_mcx_gates(self, num_ctrl_qubits): """Test the mcx gates.""" - backend = BasicAer.get_backend("statevector_simulator") reference = np.zeros(2 ** (num_ctrl_qubits + 1)) reference[-1] = 1 @@ -781,7 +765,7 @@ def test_mcx_gates(self, num_ctrl_qubits): if num_ctrl_qubits > 0: circuit.x(list(range(num_ctrl_qubits))) circuit.append(gate, list(range(gate.num_qubits)), []) - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() + statevector = Statevector(circuit).data # account for ancillas if hasattr(gate, "num_ancilla_qubits") and gate.num_ancilla_qubits > 0: @@ -1083,8 +1067,8 @@ def test_relative_phase_toffoli_gates(self, num_ctrl_qubits): circuit.rccx(0, 1, 2) else: # num_ctrl_qubits == 3: circuit.rcccx(0, 1, 2, 3) - simulator = BasicAer.get_backend("unitary_simulator") - simulated_mat = simulator.run(transpile(circuit, simulator)).result().get_unitary() + + simulated_mat = Operator(circuit) # get the matrix representation from the class itself if num_ctrl_qubits == 2: diff --git a/test/python/circuit/test_diagonal_gate.py b/test/python/circuit/test_diagonal_gate.py index a7469c5325a1..983db8f64ad8 100644 --- a/test/python/circuit/test_diagonal_gate.py +++ b/test/python/circuit/test_diagonal_gate.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -16,11 +16,14 @@ import unittest import numpy as np -from qiskit import QuantumCircuit, BasicAer, assemble, QiskitError +from qiskit import QuantumCircuit, assemble + +from qiskit import QiskitError from qiskit.test import QiskitTestCase from qiskit.compiler import transpile from qiskit.circuit.library.generalized_gates import DiagonalGate from qiskit.quantum_info.operators.predicates import matrix_equal +from qiskit.quantum_info import Operator class TestDiagonalGate(QiskitTestCase): @@ -49,9 +52,7 @@ def test_diag_gate(self): # Decompose the gate qc = transpile(qc, basis_gates=["u1", "u3", "u2", "cx", "id"], optimization_level=0) # Simulate the decomposed gate - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(qc).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc) unitary_desired = _get_diag_gate_matrix(diag) self.assertTrue(matrix_equal(unitary, unitary_desired, ignore_phase=False)) diff --git a/test/python/circuit/test_extensions_standard.py b/test/python/circuit/test_extensions_standard.py index 9f69d13400d6..7fcc40d48525 100644 --- a/test/python/circuit/test_extensions_standard.py +++ b/test/python/circuit/test_extensions_standard.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -1408,10 +1408,11 @@ def test_to_matrix(self): # gate doesn't implement to_matrix method: skip self.log.info('to_matrix method FAILED for "%s" gate', gate.name) continue - definition_unitary = Operator(circ).data + definition_unitary = Operator(circ) with self.subTest(gate_class): - self.assertTrue(matrix_equal(definition_unitary, gate_matrix)) + # TODO check for exact equality + self.assertTrue(matrix_equal(definition_unitary, gate_matrix, ignore_phase=True)) self.assertTrue(is_unitary_matrix(gate_matrix)) @unittest.skipUnless(HAS_TWEEDLEDUM, "tweedledum required for this test") diff --git a/test/python/circuit/test_initializer.py b/test/python/circuit/test_initializer.py index 23666297a3e6..979401d3c9f7 100644 --- a/test/python/circuit/test_initializer.py +++ b/test/python/circuit/test_initializer.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -23,10 +23,10 @@ QuantumCircuit, QuantumRegister, ClassicalRegister, - BasicAer, transpile, assemble, ) +from qiskit.providers.basic_provider import BasicSimulator from qiskit.quantum_info import state_fidelity, Statevector, Operator from qiskit.exceptions import QiskitError from qiskit.test import QiskitTestCase @@ -45,10 +45,7 @@ def test_uniform_superposition(self): qr = QuantumRegister(2, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -62,11 +59,7 @@ def test_deterministic_state(self): qr = QuantumRegister(2, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1]]) - - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -89,11 +82,7 @@ def test_bell_state(self): qr = QuantumRegister(2, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1]]) - - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -107,11 +96,7 @@ def test_ghz_state(self): qr = QuantumRegister(3, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1], qr[2]]) - - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -126,11 +111,7 @@ def test_initialize_register(self): qr2 = QuantumRegister(2, "qr2") qc = QuantumCircuit(qr, qr2) qc.initialize(desired_vector, qr) - - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, np.kron([1, 0, 0, 0], desired_vector)) self.assertGreater( fidelity, @@ -150,11 +131,8 @@ def test_initialize_one_by_one(self): qc_b.initialize(qubit_0_state, [qr[0]]) qc_b.initialize(qubit_1_state, [qr[1]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile([qc_a, qc_b], backend)) - result = job.result() - statevector_a = result.get_statevector(0) - statevector_b = result.get_statevector(1) + statevector_a = Statevector(qc_a) + statevector_b = Statevector(qc_b) fidelity = state_fidelity(statevector_a, statevector_b) self.assertGreater( fidelity, @@ -168,10 +146,7 @@ def test_single_qubit(self): qr = QuantumRegister(1, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -194,10 +169,7 @@ def test_random_3qubit(self): qr = QuantumRegister(3, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1], qr[2]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -228,10 +200,7 @@ def test_random_4qubit(self): qr = QuantumRegister(4, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1], qr[2], qr[3]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -298,9 +267,8 @@ def test_initialize_middle_circuit(self): qc.measure(qr, cr) # statevector simulator does not support reset shots = 2000 - threshold = 0.005 * shots - - backend = BasicAer.get_backend("qasm_simulator") + threshold = 0.05 * shots + backend = BasicSimulator() job = backend.run(transpile(qc, backend), shots=shots, seed_simulator=42) result = job.result() counts = result.get_counts() @@ -330,10 +298,7 @@ def test_math_amplitudes(self): qr = QuantumRegister(4, "qr") qc = QuantumCircuit(qr) qc.initialize(desired_vector, [qr[0], qr[1], qr[2], qr[3]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc, backend)) - result = job.result() - statevector = result.get_statevector() + statevector = Statevector(qc) fidelity = state_fidelity(statevector, desired_vector) self.assertGreater( fidelity, @@ -353,11 +318,8 @@ def test_combiner(self): qc2 = QuantumCircuit(qr, cr) qc2.initialize(desired_vector_2, [qr[0]]) - backend = BasicAer.get_backend("statevector_simulator") - job = backend.run(transpile(qc1.compose(qc2), backend)) - result = job.result() - quantum_state = result.get_statevector() - fidelity = state_fidelity(quantum_state, desired_vector_2) + statevector = Statevector(qc1.compose(qc2)) + fidelity = state_fidelity(statevector, desired_vector_2) self.assertGreater( fidelity, self._desired_fidelity, diff --git a/test/python/circuit/test_isometry.py b/test/python/circuit/test_isometry.py index 032afeebe561..ca987df64e14 100644 --- a/test/python/circuit/test_isometry.py +++ b/test/python/circuit/test_isometry.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -18,7 +18,6 @@ from ddt import ddt, data from qiskit.quantum_info.random import random_unitary -from qiskit import BasicAer from qiskit import QuantumCircuit from qiskit import QuantumRegister from qiskit.test import QiskitTestCase @@ -63,9 +62,7 @@ def test_isometry(self, iso): qc = transpile(qc, basis_gates=["u1", "u3", "u2", "cx", "id"]) # Simulate the decomposed gate - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(qc).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc).data iso_from_circuit = unitary[::, 0 : 2**num_q_input] iso_desired = iso @@ -104,9 +101,7 @@ def test_isometry_tolerance(self, iso): qc = transpile(qc, basis_gates=["u1", "u3", "u2", "cx", "id"]) # Simulate the decomposed gate - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(qc).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc).data iso_from_circuit = unitary[::, 0 : 2**num_q_input] self.assertTrue(np.allclose(iso_from_circuit, iso)) diff --git a/test/python/circuit/test_parameters.py b/test/python/circuit/test_parameters.py index 88eed2a118af..d216fa67deec 100644 --- a/test/python/circuit/test_parameters.py +++ b/test/python/circuit/test_parameters.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -26,7 +26,7 @@ import qiskit import qiskit.circuit.library as circlib from qiskit.circuit.library.standard_gates.rz import RZGate -from qiskit import BasicAer, ClassicalRegister, QuantumCircuit, QuantumRegister +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister from qiskit.circuit import Gate, Instruction, Parameter, ParameterExpression, ParameterVector from qiskit.circuit.parametertable import ParameterReferences, ParameterTable, ParameterView from qiskit.circuit.exceptions import CircuitError @@ -34,6 +34,7 @@ from qiskit import pulse from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase +from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.fake_provider import FakeOurense from qiskit.utils import parallel_map @@ -130,7 +131,7 @@ def test_compile_quantum_circuit(self): qr = QuantumRegister(1) qc = QuantumCircuit(qr) qc.rx(theta, qr) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qc_aer = transpile(qc, backend) self.assertIn(theta, qc_aer.parameters) @@ -733,7 +734,7 @@ def test_circuit_generation(self): qr = QuantumRegister(1) qc = QuantumCircuit(qr) qc.rx(theta, qr) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qc_aer = transpile(qc, backend) # generate list of circuits @@ -827,7 +828,7 @@ def test_compile_vector(self): for i, q in enumerate(qc.qubits[:-1]): qc.cx(qc.qubits[i], qc.qubits[i + 1]) qc.barrier() - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qc_aer = transpile(qc, backend) for param in theta: self.assertIn(param, qc_aer.parameters) @@ -858,7 +859,7 @@ def test_instruction_ryrz_vector(self): qc.append(cxs, qargs=qc.qubits[:-1]) qc.barrier() - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qc_aer = transpile(qc, backend) for vec in paramvecs: for param in vec: @@ -951,7 +952,7 @@ def test_binding_parameterized_circuits_built_in_multiproc(self): qobj = assemble( circuit, - backend=BasicAer.get_backend("qasm_simulator"), + backend=BasicSimulator(), parameter_binds=parameter_values, ) @@ -981,7 +982,7 @@ def test_transpiling_multiple_parameterized_circuits(self): circuits = [qc1, qc2] - backend = BasicAer.get_backend("unitary_simulator") + backend = BasicSimulator() job = backend.run(transpile(circuits, backend), shots=512, parameter_binds=[{theta: 1}]) self.assertTrue(len(job.result().results), 2) @@ -1172,7 +1173,7 @@ def test_executing_parameterized_instruction_bound_early(self, target_type): bound_qc = unbound_qc.assign_parameters({theta: numpy.pi / 2}) shots = 1024 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() job = backend.run(transpile(bound_qc, backend), shots=shots) self.assertDictAlmostEqual(job.result().get_counts(), {"1": shots}, 0.05 * shots) @@ -1208,7 +1209,7 @@ def test_execute_result_names(self): qc.measure(0, 0) plist = [{theta: i} for i in range(reps)] - simulator = BasicAer.get_backend("qasm_simulator") + simulator = BasicSimulator() result = simulator.run(transpile(qc, simulator), parameter_binds=plist).result() result_names = {res.name for res in result.results} self.assertEqual(reps, len(result_names)) diff --git a/test/python/circuit/test_piecewise_polynomial.py b/test/python/circuit/test_piecewise_polynomial.py index 786a8cb9ce25..74b5387e56da 100644 --- a/test/python/circuit/test_piecewise_polynomial.py +++ b/test/python/circuit/test_piecewise_polynomial.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2020. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,11 +18,11 @@ from ddt import ddt, data, unpack from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile from qiskit.circuit import QuantumCircuit from qiskit.circuit.library.arithmetic.piecewise_polynomial_pauli_rotations import ( PiecewisePolynomialPauliRotations, ) +from qiskit.quantum_info import Statevector @ddt @@ -37,8 +37,7 @@ def assertFunctionIsCorrect(self, function_circuit, reference): circuit.h(list(range(num_state_qubits))) circuit.append(function_circuit.to_instruction(), list(range(circuit.num_qubits))) - backend = BasicAer.get_backend("statevector_simulator") - statevector = backend.run(transpile(circuit, backend)).result().get_statevector() + statevector = Statevector(circuit) probabilities = defaultdict(float) for i, statevector_amplitude in enumerate(statevector): diff --git a/test/python/circuit/test_scheduled_circuit.py b/test/python/circuit/test_scheduled_circuit.py index 872a79e3e0f6..8de46cfb4458 100644 --- a/test/python/circuit/test_scheduled_circuit.py +++ b/test/python/circuit/test_scheduled_circuit.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2020. +# (C) Copyright IBM 2020, 2023. # # 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 @@ -15,8 +15,9 @@ """Test scheduled circuit (quantum circuit with duration).""" from ddt import ddt, data from qiskit import QuantumCircuit, QiskitError -from qiskit import transpile, assemble, BasicAer +from qiskit import transpile, assemble from qiskit.circuit import Parameter +from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.fake_provider import FakeParis from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.instruction_durations import InstructionDurations @@ -34,7 +35,7 @@ def setUp(self): self.backend_without_dt = FakeParis() delattr(self.backend_without_dt.configuration(), "dt") self.dt = 2.2222222222222221e-10 - self.simulator_backend = BasicAer.get_backend("qasm_simulator") + self.simulator_backend = BasicSimulator() def test_schedule_circuit_when_backend_tells_dt(self): """dt is known to transpiler by backend""" diff --git a/test/python/circuit/test_uc.py b/test/python/circuit/test_uc.py index 88a9b43df1ec..af49743485ac 100644 --- a/test/python/circuit/test_uc.py +++ b/test/python/circuit/test_uc.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -25,7 +25,7 @@ from qiskit.circuit.library.generalized_gates import UCGate -from qiskit import QuantumCircuit, QuantumRegister, BasicAer +from qiskit import QuantumCircuit, QuantumRegister from qiskit.test import QiskitTestCase from qiskit.quantum_info.random import random_unitary from qiskit.compiler import transpile @@ -65,9 +65,7 @@ def test_ucg(self, squs, up_to_diagonal): # Decompose the gate qc = transpile(qc, basis_gates=["u1", "u3", "u2", "cx", "id"]) # Simulate the decomposed gate - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(qc).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc).data if up_to_diagonal: ucg = UCGate(squs, up_to_diagonal=up_to_diagonal) unitary = np.dot(np.diagflat(ucg._get_diagonal()), unitary) @@ -84,9 +82,7 @@ def test_global_phase_ucg(self): uc = UCGate(gates, up_to_diagonal=False) qc.append(uc, q) - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(transpile(qc, simulator)).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc).data unitary_desired = _get_ucg_matrix(gates) self.assertTrue(np.allclose(unitary_desired, unitary)) diff --git a/test/python/circuit/test_ucx_y_z.py b/test/python/circuit/test_ucx_y_z.py index d14f9928e7ca..af4e33c228ea 100644 --- a/test/python/circuit/test_ucx_y_z.py +++ b/test/python/circuit/test_ucx_y_z.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2023. # # 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 @@ -18,10 +18,11 @@ import numpy as np from scipy.linalg import block_diag -from qiskit import BasicAer, QuantumCircuit, QuantumRegister +from qiskit import QuantumCircuit, QuantumRegister from qiskit.test import QiskitTestCase from qiskit.quantum_info.operators.predicates import matrix_equal +from qiskit.quantum_info import Operator from qiskit.compiler import transpile from qiskit.circuit.library import UCRXGate, UCRYGate, UCRZGate @@ -58,9 +59,7 @@ def test_ucy(self): # Decompose the gate qc = transpile(qc, basis_gates=["u1", "u3", "u2", "cx", "id"]) # Simulate the decomposed gate - simulator = BasicAer.get_backend("unitary_simulator") - result = simulator.run(qc).result() - unitary = result.get_unitary(qc) + unitary = Operator(qc) unitary_desired = _get_ucr_matrix(angles, rot_axis) self.assertTrue(matrix_equal(unitary_desired, unitary, ignore_phase=True)) diff --git a/test/python/classical_function_compiler/test_boolean_expression.py b/test/python/classical_function_compiler/test_boolean_expression.py index 12d5eebc422b..b5445af29dce 100644 --- a/test/python/classical_function_compiler/test_boolean_expression.py +++ b/test/python/classical_function_compiler/test_boolean_expression.py @@ -17,7 +17,8 @@ from ddt import ddt, unpack, data from qiskit.test.base import QiskitTestCase -from qiskit import BasicAer, transpile +from qiskit import transpile +from qiskit.providers.basic_provider import BasicSimulator from qiskit.utils.optionals import HAS_TWEEDLEDUM if HAS_TWEEDLEDUM: @@ -58,7 +59,7 @@ def test_synth(self, expression, expected): expr_circ.add_register(new_creg) expr_circ.measure(expression.num_qubits - 1, new_creg) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() [result] = ( backend.run( transpile(expr_circ, backend), diff --git a/test/python/compiler/test_compiler.py b/test/python/compiler/test_compiler.py index cce7c480dd50..efa4b90b77a4 100644 --- a/test/python/compiler/test_compiler.py +++ b/test/python/compiler/test_compiler.py @@ -15,13 +15,13 @@ import os import unittest -from qiskit import BasicAer from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.transpiler import PassManager from qiskit.circuit.library import U1Gate, U2Gate from qiskit.compiler import transpile, assemble from qiskit.test import QiskitTestCase from qiskit.providers.fake_provider import FakeRueschlikon, FakeTenerife +from qiskit.providers.basic_provider import BasicSimulator from qiskit.qobj import QasmQobj from qiskit.qasm2 import dumps @@ -32,14 +32,14 @@ class TestCompiler(QiskitTestCase): def setUp(self): super().setUp() self.seed_simulator = 42 - self.backend = BasicAer.get_backend("qasm_simulator") + self.backend = BasicSimulator() def test_example_multiple_compile(self): """Test a toy example compiling multiple circuits. Pass if the results are correct. """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() coupling_map = [[0, 1], [0, 2], [1, 2], [3, 2], [3, 4], [4, 2]] qr = QuantumRegister(5) @@ -81,7 +81,7 @@ def test_compile_coupling_map(self): If all correct should return data with the same stats. The circuit may be different. """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qr = QuantumRegister(3, "qr") cr = ClassicalRegister(3, "cr") @@ -113,7 +113,7 @@ def test_example_swap_bits(self): Uses the mapper. Pass if results are correct. """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() coupling_map = [ [0, 1], [0, 8], @@ -202,7 +202,7 @@ def test_parallel_compile(self): def test_no_conflict_backend_passmanager(self): """See: https://github.com/Qiskit/qiskit-terra/issues/5037""" - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qc = QuantumCircuit(2) qc.append(U1Gate(0), [0]) qc.measure_all() @@ -257,7 +257,7 @@ def test_compile_pass_manager(self): qc.append(U2Gate(3.14, 1.57), [qr[0]]) qc.barrier(qr) qc.measure(qr, cr) - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qrtrue = transpile(qc, backend, seed_transpiler=8) rtrue = backend.run(qrtrue, seed_simulator=42).result() qrfalse = PassManager().run(qc) diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 181687fe6901..6e53ea091e47 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -27,7 +27,14 @@ import rustworkx as rx from ddt import data, ddt, unpack -from qiskit import BasicAer, ClassicalRegister, QuantumCircuit, QuantumRegister, pulse, qasm3, qpy +from qiskit import ( + ClassicalRegister, + QuantumCircuit, + QuantumRegister, + pulse, + qasm3, + qpy, +) from qiskit.circuit import ( Clbit, ControlFlowOp, @@ -78,6 +85,7 @@ FakeVigo, ) from qiskit.providers.options import Options +from qiskit.providers.basic_provider import BasicSimulator from qiskit.pulse import InstructionScheduleMap from qiskit.quantum_info import Operator, random_unitary from qiskit.test import QiskitTestCase, slow_test @@ -136,7 +144,7 @@ def test_pass_manager_none(self): coupling_map = [[1, 0]] basis_gates = ["u1", "u2", "u3", "cx", "id"] - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() circuit2 = transpile( circuit, backend=backend, @@ -508,7 +516,7 @@ def test_transpile_bell(self): If all correct some should exists. """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qubit_reg = QuantumRegister(2, name="q") clbit_reg = ClassicalRegister(2, name="c") @@ -547,7 +555,7 @@ def test_transpile_one(self): Check that the top-level `transpile` function returns a single circuit.""" - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qubit_reg = QuantumRegister(2) clbit_reg = ClassicalRegister(2) @@ -564,7 +572,7 @@ def test_transpile_two(self): Check that the transpiler returns a list of two circuits. """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qubit_reg = QuantumRegister(2) clbit_reg = ClassicalRegister(2) @@ -590,7 +598,7 @@ def test_transpile_singleton(self): See https://github.com/Qiskit/qiskit-terra/issues/5260 """ - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() qubit_reg = QuantumRegister(2) clbit_reg = ClassicalRegister(2) @@ -780,7 +788,7 @@ def test_parameterized_circuit_for_simulator(self): theta = Parameter("theta") qc.rz(theta, qr[0]) - transpiled_qc = transpile(qc, backend=BasicAer.get_backend("qasm_simulator")) + transpiled_qc = transpile(qc, backend=BasicSimulator()) expected_qc = QuantumCircuit(qr) expected_qc.append(RZGate(theta), [qr[0]]) @@ -817,7 +825,7 @@ def test_parameter_expression_circuit_for_simulator(self): square = theta * theta qc.rz(square, qr[0]) - transpiled_qc = transpile(qc, backend=BasicAer.get_backend("qasm_simulator")) + transpiled_qc = transpile(qc, backend=BasicSimulator()) expected_qc = QuantumCircuit(qr) expected_qc.append(RZGate(square), [qr[0]]) diff --git a/test/python/primitives/test_backend_sampler.py b/test/python/primitives/test_backend_sampler.py index 156f0b48fefc..e485c74b0b00 100644 --- a/test/python/primitives/test_backend_sampler.py +++ b/test/python/primitives/test_backend_sampler.py @@ -27,7 +27,7 @@ from qiskit.primitives import BackendSampler, SamplerResult from qiskit.providers import JobStatus from qiskit.providers.fake_provider import FakeNairobi, FakeNairobiV2 -from qiskit.providers.basicaer import QasmSimulatorPy +from qiskit.providers.basic_provider import BasicSimulator from qiskit.test import QiskitTestCase from qiskit.transpiler import PassManager from qiskit.utils import optionals @@ -386,7 +386,7 @@ def test_outcome_bitstring_size(self): # We need a noise-free backend here (shot noise is fine) to ensure that # the only bit string measured is "0001". With device noise, it could happen that # strings with a leading 1 are measured and then the truncation cannot be tested. - sampler = BackendSampler(backend=QasmSimulatorPy()) + sampler = BackendSampler(backend=BasicSimulator()) result = sampler.run(qc).result() probs = result.quasi_dists[0].binary_probabilities() diff --git a/test/python/basicaer/__init__.py b/test/python/providers/basic_provider/__init__.py similarity index 58% rename from test/python/basicaer/__init__.py rename to test/python/providers/basic_provider/__init__.py index 182415e6f4f5..0c8b92822219 100644 --- a/test/python/basicaer/__init__.py +++ b/test/python/providers/basic_provider/__init__.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -10,34 +10,23 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Qiskit BasicAer integration tests.""" +"""Qiskit BasicProvider integration tests.""" from qiskit import transpile -class BasicAerBackendTestMixin: - """Test mixins for BasicAer backend tests.""" +class BasicProviderBackendTestMixin: + """Test mixins for BasicProvider backend tests.""" def test_configuration(self): """Test backend.configuration().""" configuration = self.backend.configuration() return configuration - def test_properties(self): - """Test backend.properties().""" - properties = self.backend.properties() - if self.backend.configuration().simulator: - self.assertEqual(properties, None) - return properties - - def test_status(self): - """Test backend.status().""" - status = self.backend.status() - return status - def test_run_circuit(self): """Test running a single circuit.""" - job = self.backend.run(transpile(self.circuit, self.backend)) + transpiled_qc = transpile(self.circuit, self.backend) + job = self.backend.run(transpiled_qc) result = job.result() self.assertEqual(result.success, True) return result diff --git a/test/python/providers/basic_provider/test_basic_provider_backends.py b/test/python/providers/basic_provider/test_basic_provider_backends.py new file mode 100644 index 000000000000..4aa229515ef7 --- /dev/null +++ b/test/python/providers/basic_provider/test_basic_provider_backends.py @@ -0,0 +1,40 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 2023. +# +# 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. + +"""BasicProvider Backends Test.""" + +from qiskit.providers.basic_provider.basic_provider import BasicProvider +from qiskit.providers.exceptions import QiskitBackendNotFoundError +from qiskit.test import QiskitTestCase + + +class TestBasicProviderBackends(QiskitTestCase): + """Qiskit BasicProvider Backends (Object) Tests.""" + + def setUp(self): + super().setUp() + self.provider = BasicProvider() + self.backend_name = "basic_simulator" + + def test_backends(self): + """Test the provider has backends.""" + backends = self.provider.backends() + self.assertTrue(len(backends) > 0) + + def test_get_backend(self): + """Test getting a backend from the provider.""" + backend = self.provider.get_backend(name=self.backend_name) + self.assertEqual(backend.name, self.backend_name) + + def test_aliases_fail(self): + """Test a failing backend lookup.""" + self.assertRaises(QiskitBackendNotFoundError, BasicProvider().get_backend, "bad_name") diff --git a/test/python/basicaer/test_basicaer_integration.py b/test/python/providers/basic_provider/test_basic_provider_integration.py similarity index 75% rename from test/python/basicaer/test_basicaer_integration.py rename to test/python/providers/basic_provider/test_basic_provider_integration.py index 9dc00df843d1..191ff9fba22b 100644 --- a/test/python/basicaer/test_basicaer_integration.py +++ b/test/python/providers/basic_provider/test_basic_provider_integration.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -10,19 +10,18 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""BasicAer provider integration tests.""" +"""BasicProvider provider integration tests.""" import unittest -from qiskit import BasicAer -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, transpile from qiskit.result import Result -from qiskit.providers.basicaer import BasicAerError +from qiskit.providers.basic_provider import BasicProviderError, BasicSimulator from qiskit.test import QiskitTestCase -class TestBasicAerIntegration(QiskitTestCase): - """Qiskit BasicAer simulator integration tests.""" +class TestBasicProviderIntegration(QiskitTestCase): + """Qiskit BasicProvider simulator integration tests.""" def setUp(self): super().setUp() @@ -31,18 +30,18 @@ def setUp(self): self._qc1 = QuantumCircuit(qr, cr, name="qc1") self._qc2 = QuantumCircuit(qr, cr, name="qc2") self._qc1.measure(qr[0], cr[0]) - self.backend = BasicAer.get_backend("qasm_simulator") - self._result1 = self.backend.run(self._qc1).result() + self.backend = BasicSimulator() + self._result1 = self.backend.run(transpile(self._qc1)).result() def test_builtin_simulator_result_fields(self): """Test components of a result from a local simulator.""" - self.assertEqual("qasm_simulator", self._result1.backend_name) + self.assertEqual("basic_simulator", self._result1.backend_name) self.assertIsInstance(self._result1.job_id, str) self.assertEqual(self._result1.status, "COMPLETED") self.assertEqual(self._result1.results[0].status, "DONE") - def test_basicaer_execute(self): + def test_basicprovider_execute(self): """Test Compiler and run.""" qubit_reg = QuantumRegister(2, name="q") clbit_reg = ClassicalRegister(2, name="c") @@ -55,7 +54,7 @@ def test_basicaer_execute(self): result = job.result() self.assertIsInstance(result, Result) - def test_basicaer_execute_two(self): + def test_basicprovider_execute_two(self): """Test Compiler and run.""" qubit_reg = QuantumRegister(2, name="q") clbit_reg = ClassicalRegister(2, name="c") @@ -69,12 +68,12 @@ def test_basicaer_execute_two(self): result = job.result() self.assertIsInstance(result, Result) - def test_basicaer_num_qubits(self): - """Test BasicAerError is raised if num_qubits too large to simulate.""" + def test_basicprovider_num_qubits(self): + """Test BasicProviderError is raised if num_qubits too large to simulate.""" qc = QuantumCircuit(50, 1) qc.x(0) qc.measure(0, 0) - with self.assertRaises(BasicAerError): + with self.assertRaises(BasicProviderError): self.backend.run(qc) diff --git a/test/python/basicaer/test_qasm_simulator.py b/test/python/providers/basic_provider/test_basic_simulator.py similarity index 91% rename from test/python/basicaer/test_qasm_simulator.py rename to test/python/providers/basic_provider/test_basic_simulator.py index 2f632dda0813..a667005114ea 100644 --- a/test/python/basicaer/test_qasm_simulator.py +++ b/test/python/providers/basic_provider/test_basic_simulator.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -10,38 +10,28 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test QASM simulator.""" +"""Test basic simulator.""" import os import unittest -import io -from logging import StreamHandler, getLogger -import sys import numpy as np from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister -from qiskit.test import QiskitTestCase from qiskit.compiler import transpile, assemble -from qiskit.providers.basicaer import QasmSimulatorPy +from qiskit.providers.basic_provider import BasicSimulator +from qiskit.test import QiskitTestCase from qiskit.qasm2 import dumps -from . import BasicAerBackendTestMixin - - -class StreamHandlerRaiseException(StreamHandler): - """Handler class that will raise an exception on formatting errors.""" - - def handleError(self, record): - raise sys.exc_info() +from . import BasicProviderBackendTestMixin -class TestBasicAerQasmSimulator(QiskitTestCase, BasicAerBackendTestMixin): - """Test the Basic qasm_simulator.""" +class TestBasicSimulator(QiskitTestCase, BasicProviderBackendTestMixin): + """Test the basic provider simulator.""" def setUp(self): super().setUp() - self.backend = QasmSimulatorPy() + self.backend = BasicSimulator() bell = QuantumCircuit(2, 2) bell.h(0) bell.cx(0, 1) @@ -49,19 +39,17 @@ def setUp(self): self.circuit = bell self.seed = 88 - qasm_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "qasm") + self.backend = BasicSimulator() + qasm_dir = os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "qasm" + ) qasm_filename = os.path.join(qasm_dir, "example.qasm") qcirc = QuantumCircuit.from_qasm_file(qasm_filename) qcirc.name = "test" self.transpiled_circuit = transpile(qcirc, backend=self.backend) self.qobj = assemble(self.transpiled_circuit, shots=1000, seed_simulator=self.seed) - logger = getLogger() - self.addCleanup(logger.setLevel, logger.level) - logger.setLevel("DEBUG") - self.log_output = io.StringIO() - logger.addHandler(StreamHandlerRaiseException(self.log_output)) - def test_qasm_simulator_single_shot(self): + def test_basic_simulator_single_shot(self): """Test single shot run.""" shots = 1 result = self.backend.run( @@ -81,7 +69,9 @@ def test_measure_sampler_repeated_qubits(self): circuit.measure(qr[1], cr[2]) circuit.measure(qr[0], cr[3]) target = {"0110": shots} - job = self.backend.run(circuit, shots=shots, seed_simulator=self.seed) + job = self.backend.run( + transpile(circuit, self.backend), shots=shots, seed_simulator=self.seed + ) result = job.result() counts = result.get_counts(0) self.assertEqual(counts, target) @@ -98,7 +88,9 @@ def test_measure_sampler_single_qubit(self): circuit.x(qr[qubit]) circuit.measure(qr[qubit], cr[0]) target = {"1": shots} - job = self.backend.run(circuit, shots=shots, seed_simulator=self.seed) + job = self.backend.run( + transpile(circuit, self.backend), shots=shots, seed_simulator=self.seed + ) result = job.result() counts = result.get_counts(0) self.assertEqual(counts, target) @@ -135,12 +127,14 @@ def test_measure_sampler_partial_qubit(self): circuit.barrier(qr) circuit.measure(qr[3], cr[3]) target = {"1011": shots} - job = self.backend.run(circuit, shots=shots, seed_simulator=self.seed) + job = self.backend.run( + transpile(circuit, self.backend), shots=shots, seed_simulator=self.seed + ) result = job.result() counts = result.get_counts(0) self.assertEqual(counts, target) - def test_qasm_simulator(self): + def test_basic_simulator(self): """Test data counts output for single circuit run against reference.""" result = self.backend.run( self.transpiled_circuit, shots=1000, seed_simulator=self.seed @@ -205,11 +199,10 @@ def test_if_statement(self): circuit_if_false.measure(qr[1], cr[1]) circuit_if_false.measure(qr[2], cr[2]) job = self.backend.run( - [circuit_if_true, circuit_if_false], + transpile([circuit_if_true, circuit_if_false], self.backend), shots=shots, seed_simulator=self.seed, ) - result = job.result() counts_if_true = result.get_counts(circuit_if_true) counts_if_false = result.get_counts(circuit_if_false) @@ -263,7 +256,7 @@ def test_teleport(self): # 0 self.log.info("test_teleport") pi = np.pi - shots = 2000 + shots = 4000 qr = QuantumRegister(3, "qr") cr0 = ClassicalRegister(1, "cr0") cr1 = ClassicalRegister(1, "cr1") @@ -335,7 +328,9 @@ def test_memory(self): circ.measure(qr[3], cr1[1]) shots = 50 - job = self.backend.run(circ, shots=shots, memory=True) + job = self.backend.run( + transpile(circ, self.backend), shots=shots, seed_simulator=self.seed, memory=True + ) result = job.result() memory = result.get_memory() self.assertEqual(len(memory), shots) @@ -362,7 +357,7 @@ def test_unitary(self): circuit = QuantumCircuit(qr, cr) circuit.unitary(multi_x, qr) circuit.measure(qr, cr) - job = self.backend.run(transpile(circuit), shots=shots) + job = self.backend.run(transpile(circuit, self.backend), shots=shots) result = job.result() counts = result.get_counts(0) self.assertEqual(counts, target_counts) diff --git a/test/python/basicaer/test_multi_registers_convention.py b/test/python/providers/basic_provider/test_multi_registers_convention.py similarity index 61% rename from test/python/basicaer/test_multi_registers_convention.py rename to test/python/providers/basic_provider/test_multi_registers_convention.py index 45abcd5453cf..700ab8aec675 100644 --- a/test/python/basicaer/test_multi_registers_convention.py +++ b/test/python/providers/basic_provider/test_multi_registers_convention.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -10,11 +10,10 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test executing multiple-register circuits on BasicAer.""" +"""Test executing multiple-register circuits on BasicProvider.""" -from qiskit import BasicAer from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister -from qiskit.quantum_info import Operator, Statevector, process_fidelity, state_fidelity +from qiskit.providers.basic_provider import BasicProvider from qiskit.test import QiskitTestCase @@ -37,23 +36,10 @@ def test_circuit_multi(self): qc = circ.compose(meas) - backend_sim = BasicAer.get_backend("qasm_simulator") + backend_sim = BasicProvider().get_backend("basic_simulator") result = backend_sim.run(qc).result() counts = result.get_counts(qc) - target = {"01 10": 1024} - backend_sim = BasicAer.get_backend("statevector_simulator") - result = backend_sim.run(circ).result() - state = result.get_statevector(circ) - - backend_sim = BasicAer.get_backend("unitary_simulator") - result = backend_sim.run(circ).result() - unitary = Operator(result.get_unitary(circ)) - self.assertEqual(counts, target) - self.assertAlmostEqual(state_fidelity(Statevector.from_label("0110"), state), 1.0, places=7) - self.assertAlmostEqual( - process_fidelity(Operator.from_label("IXXI"), unitary), 1.0, places=7 - ) diff --git a/test/python/qobj/test_qobj_identifiers.py b/test/python/qobj/test_qobj_identifiers.py index c4624d17dd0e..0fd695c7e56b 100644 --- a/test/python/qobj/test_qobj_identifiers.py +++ b/test/python/qobj/test_qobj_identifiers.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -22,7 +22,7 @@ class TestQobjIdentifiers(QiskitTestCase): - """Check the Qobj compiled for different backends create names properly""" + """Check the Qobj create names properly""" def setUp(self): super().setUp() @@ -35,19 +35,7 @@ def setUp(self): self.cr_name = cr.name self.circuits = [qc] - def test_builtin_qasm_simulator_py(self): - qobj = assemble(self.circuits) - exp = qobj.experiments[0] - self.assertIn(self.qr_name, (x[0] for x in exp.header.qubit_labels)) - self.assertIn(self.cr_name, (x[0] for x in exp.header.clbit_labels)) - - def test_builtin_qasm_simulator(self): - qobj = assemble(self.circuits) - exp = qobj.experiments[0] - self.assertIn(self.qr_name, (x[0] for x in exp.header.qubit_labels)) - self.assertIn(self.cr_name, (x[0] for x in exp.header.clbit_labels)) - - def test_builtin_unitary_simulator_py(self): + def test_qobj_identifiers(self): qobj = assemble(self.circuits) exp = qobj.experiments[0] self.assertIn(self.qr_name, (x[0] for x in exp.header.qubit_labels)) diff --git a/test/python/quantum_info/states/test_statevector.py b/test/python/quantum_info/states/test_statevector.py index c1c6beed27cc..700d190346de 100644 --- a/test/python/quantum_info/states/test_statevector.py +++ b/test/python/quantum_info/states/test_statevector.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -25,7 +25,7 @@ from qiskit import QuantumRegister, QuantumCircuit from qiskit import transpile from qiskit.circuit.library import HGate, QFT, GlobalPhaseGate -from qiskit.providers.basicaer import QasmSimulatorPy +from qiskit.providers.basic_provider import BasicSimulator from qiskit.utils import optionals from qiskit.quantum_info.random import random_unitary, random_statevector, random_pauli @@ -1168,7 +1168,7 @@ def test_probabilities_qargs(self, qargs): probs = state.probabilities(qargs) # Estimate target probs from simulator measurement - sim = QasmSimulatorPy() + sim = BasicSimulator() shots = 5000 seed = 100 circ = transpile(state_circ, sim) diff --git a/test/python/quantum_info/test_analyzation.py b/test/python/quantum_info/test_analyzation.py index fe44862402cb..5da8b818a86f 100644 --- a/test/python/quantum_info/test_analyzation.py +++ b/test/python/quantum_info/test_analyzation.py @@ -14,7 +14,8 @@ import unittest -from qiskit import BasicAer, QuantumCircuit, ClassicalRegister, QuantumRegister, transpile +from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, transpile +from qiskit.providers.basic_provider import BasicSimulator from qiskit.quantum_info.analysis.average import average_data from qiskit.quantum_info.analysis.make_observable import make_dict_observable from qiskit.quantum_info.analysis import hellinger_fidelity @@ -34,7 +35,7 @@ def test_average_data_dict_observable(self): qc.measure(qr[0], cr[0]) qc.measure(qr[1], cr[1]) shots = 10000 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() result = backend.run(qc, shots=shots).result() counts = result.get_counts(qc) observable = {"00": 1, "11": 1, "01": -1, "10": -1} @@ -59,7 +60,7 @@ def test_average_data_list_observable(self): qc.measure(qr[1], cr[1]) qc.measure(qr[2], cr[2]) shots = 10000 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() result = backend.run(qc, shots=shots).result() counts = result.get_counts(qc) observable = [1, -1, -1, 1, -1, 1, 1, -1] @@ -85,7 +86,7 @@ def test_average_data_matrix_observable(self): qc.measure(qr[0], cr[0]) qc.measure(qr[1], cr[1]) shots = 10000 - backend = BasicAer.get_backend("qasm_simulator") + backend = BasicSimulator() result = backend.run(qc, shots=shots).result() counts = result.get_counts(qc) observable = [[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]] @@ -132,7 +133,7 @@ def test_hellinger_fidelity_same(self): qc.cx(1, 0) qc.measure(range(5), range(5)) - sim = BasicAer.get_backend("qasm_simulator") + sim = BasicSimulator() res = sim.run(qc).result() @@ -185,7 +186,7 @@ def test_hellinger_fidelity_no_overlap(self): qc2.cx(1, 0) qc2.measure(range(5), range(5)) - sim = BasicAer.get_backend("qasm_simulator") + sim = BasicSimulator() res1 = sim.run(qc).result() res2 = sim.run(transpile(qc2, sim)).result() diff --git a/test/python/synthesis/test_local_invariance.py b/test/python/synthesis/test_local_invariance.py index fa881ef8d157..badbf04040aa 100644 --- a/test/python/synthesis/test_local_invariance.py +++ b/test/python/synthesis/test_local_invariance.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -16,10 +16,10 @@ import unittest from numpy.testing import assert_allclose -from qiskit import QuantumCircuit, QuantumRegister, transpile +from qiskit import QuantumCircuit, QuantumRegister from qiskit.test import QiskitTestCase -from qiskit.providers.basicaer import UnitarySimulatorPy from qiskit.synthesis.two_qubit.local_invariance import two_qubit_local_invariants +from qiskit.quantum_info import Operator class TestLocalInvariance(QiskitTestCase): @@ -29,18 +29,17 @@ def test_2q_local_invariance_simple(self): """Check the local invariance parameters for known simple cases. """ - sim = UnitarySimulatorPy() qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) - U = sim.run(qc).result().get_unitary() + U = Operator(qc) vec = two_qubit_local_invariants(U) assert_allclose(vec, [1, 0, 3]) qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) qc.cx(qr[1], qr[0]) - U = sim.run(qc).result().get_unitary() + U = Operator(qc) vec = two_qubit_local_invariants(U) assert_allclose(vec, [0, 0, 1]) @@ -48,14 +47,14 @@ def test_2q_local_invariance_simple(self): qc = QuantumCircuit(qr) qc.cx(qr[1], qr[0]) qc.cx(qr[0], qr[1]) - U = sim.run(qc).result().get_unitary() + U = Operator(qc) vec = two_qubit_local_invariants(U) assert_allclose(vec, [0, 0, -1]) qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) qc.swap(qr[1], qr[0]) - U = sim.run(transpile(qc, sim)).result().get_unitary() + U = Operator(qc) vec = two_qubit_local_invariants(U) assert_allclose(vec, [-1, 0, -3]) diff --git a/test/python/synthesis/test_synthesis.py b/test/python/synthesis/test_synthesis.py index 875cac013d49..88e90b4bd63a 100644 --- a/test/python/synthesis/test_synthesis.py +++ b/test/python/synthesis/test_synthesis.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 diff --git a/test/python/transpiler/test_mappers.py b/test/python/transpiler/test_mappers.py index 60b4f6f3e72a..510ba30af635 100644 --- a/test/python/transpiler/test_mappers.py +++ b/test/python/transpiler/test_mappers.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2018. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -72,7 +72,8 @@ def test_a_common_test(self): import os import sys -from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit, BasicAer, transpile +from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit, transpile +from qiskit.providers.basic_provider import BasicSimulator from qiskit.qasm2 import dump from qiskit.transpiler import PassManager from qiskit.transpiler.passes import BasicSwap, LookaheadSwap, StochasticSwap, SabreSwap @@ -110,7 +111,7 @@ def create_passmanager(self, coupling_map, initial_layout=None): def create_backend(self): """Returns a Backend.""" - return BasicAer.get_backend("qasm_simulator") + return BasicSimulator() def generate_ground_truth(self, transpiled_result, filename): """Generates the expected result into a file. diff --git a/test/python/transpiler/test_naming_transpiled_circuits.py b/test/python/transpiler/test_naming_transpiled_circuits.py index ce6f6e6e50d9..6385e9fca180 100644 --- a/test/python/transpiler/test_naming_transpiled_circuits.py +++ b/test/python/transpiler/test_naming_transpiled_circuits.py @@ -15,7 +15,7 @@ import unittest from qiskit.circuit import QuantumCircuit from qiskit.compiler import transpile -from qiskit import BasicAer +from qiskit.providers.basic_provider import BasicSimulator from qiskit.transpiler.exceptions import TranspilerError from qiskit.test import QiskitTestCase @@ -26,7 +26,7 @@ class TestNamingTranspiledCircuits(QiskitTestCase): def setUp(self): super().setUp() self.basis_gates = ["u1", "u2", "u3", "cx"] - self.backend = BasicAer.get_backend("qasm_simulator") + self.backend = BasicSimulator() self.circuit0 = QuantumCircuit(name="circuit0") self.circuit1 = QuantumCircuit(name="circuit1") diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py index 96721e1884a3..ea51572cf4de 100644 --- a/test/python/transpiler/test_passmanager_config.py +++ b/test/python/transpiler/test_passmanager_config.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -16,7 +16,6 @@ from qiskit.providers.backend import Backend from qiskit.test import QiskitTestCase from qiskit.providers.fake_provider import FakeMelbourne, FakeArmonk, FakeHanoi, FakeHanoiV2 -from qiskit.providers.basicaer import QasmSimulatorPy from qiskit.transpiler.coupling import CouplingMap from qiskit.transpiler.passmanager_config import PassManagerConfig @@ -80,14 +79,6 @@ def test_from_backendv1_inst_map_is_none(self): self.assertIsInstance(config, PassManagerConfig) self.assertIsNone(config.inst_map) - def test_simulator_backend_v1(self): - """Test that from_backend() works with backendv1 simulator.""" - backend = QasmSimulatorPy() - config = PassManagerConfig.from_backend(backend) - self.assertIsInstance(config, PassManagerConfig) - self.assertIsNone(config.inst_map) - self.assertIsNone(config.coupling_map) - def test_invalid_user_option(self): """Test from_backend() with an invalid user option.""" with self.assertRaises(TypeError): diff --git a/test/python/transpiler/test_stage_plugin.py b/test/python/transpiler/test_stage_plugin.py index d11fcb1c8a62..2316e9b4c2b3 100644 --- a/test/python/transpiler/test_stage_plugin.py +++ b/test/python/transpiler/test_stage_plugin.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2022. +# (C) Copyright IBM 2022, 2023. # # 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 @@ -30,7 +30,7 @@ passmanager_stage_plugins, ) from qiskit.transpiler.exceptions import TranspilerError -from qiskit.providers.basicaer import QasmSimulatorPy +from qiskit.providers.basic_provider import BasicSimulator class TestStagePassManagerPlugin(QiskitTestCase): @@ -111,7 +111,7 @@ def test_routing_plugins(self, optimization_level, routing_method): optimization_level=optimization_level, routing_method=routing_method, ) - backend = QasmSimulatorPy() + backend = BasicSimulator() counts = backend.run(tqc, shots=1000).result().get_counts() self.assertDictAlmostEqual(counts, {"0000": 500, "1111": 500}, delta=100) @@ -120,7 +120,7 @@ def test_routing_plugins(self, optimization_level, routing_method): ) def test_unitary_synthesis_plugins(self, optimization_level): """Test unitary synthesis plugins""" - backend = QasmSimulatorPy() + backend = BasicSimulator() with self.assertRaises(TranspilerError): _ = generate_preset_pass_manager( optimization_level=optimization_level, diff --git a/test/randomized/test_synthesis.py b/test/randomized/test_synthesis.py index 6bc95204d1d1..9f0619a0c296 100644 --- a/test/randomized/test_synthesis.py +++ b/test/randomized/test_synthesis.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2023. # # 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 @@ -18,7 +18,7 @@ from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.circuit.library import UnitaryGate -from qiskit.providers.basicaer import UnitarySimulatorPy +from qiskit.quantum_info import Operator from qiskit.quantum_info.random import random_unitary from qiskit.synthesis.two_qubit.two_qubit_decompose import ( two_qubit_cnot_decompose, @@ -63,8 +63,8 @@ def test_exact_supercontrolled_decompose_random(self, seeds): decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer) - @given(strategies.tuples(*[rotation] * 6), seed) - def test_cx_equivalence_0cx_random(self, rnd, seed): + @given(strategies.tuples(*[rotation] * 6)) + def test_cx_equivalence_0cx_random(self, rnd): """Check random circuits with 0 cx gates locally equivalent to identity.""" qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) @@ -72,12 +72,11 @@ def test_cx_equivalence_0cx_random(self, rnd, seed): qc.u(rnd[0], rnd[1], rnd[2], qr[0]) qc.u(rnd[3], rnd[4], rnd[5], qr[1]) - sim = UnitarySimulatorPy() - unitary = sim.run(qc, seed_simulator=seed).result().get_unitary() + unitary = Operator(qc) self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0) - @given(strategies.tuples(*[rotation] * 12), seed) - def test_cx_equivalence_1cx_random(self, rnd, seed): + @given(strategies.tuples(*[rotation] * 12)) + def test_cx_equivalence_1cx_random(self, rnd): """Check random circuits with 1 cx gates locally equivalent to a cx.""" qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) @@ -90,12 +89,11 @@ def test_cx_equivalence_1cx_random(self, rnd, seed): qc.u(rnd[6], rnd[7], rnd[8], qr[0]) qc.u(rnd[9], rnd[10], rnd[11], qr[1]) - sim = UnitarySimulatorPy() - unitary = sim.run(qc, seed_simulator=seed).result().get_unitary() + unitary = Operator(qc) self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 1) - @given(strategies.tuples(*[rotation] * 18), seed) - def test_cx_equivalence_2cx_random(self, rnd, seed): + @given(strategies.tuples(*[rotation] * 18)) + def test_cx_equivalence_2cx_random(self, rnd): """Check random circuits with 2 cx gates locally equivalent to some circuit with 2 cx.""" qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) @@ -113,12 +111,11 @@ def test_cx_equivalence_2cx_random(self, rnd, seed): qc.u(rnd[12], rnd[13], rnd[14], qr[0]) qc.u(rnd[15], rnd[16], rnd[17], qr[1]) - sim = UnitarySimulatorPy() - unitary = sim.run(qc, seed_simulator=seed).result().get_unitary() + unitary = Operator(qc) self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2) - @given(strategies.tuples(*[rotation] * 24), seed) - def test_cx_equivalence_3cx_random(self, rnd, seed): + @given(strategies.tuples(*[rotation] * 24)) + def test_cx_equivalence_3cx_random(self, rnd): """Check random circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions.""" qr = QuantumRegister(2, name="q") qc = QuantumCircuit(qr) @@ -141,8 +138,7 @@ def test_cx_equivalence_3cx_random(self, rnd, seed): qc.u(rnd[18], rnd[19], rnd[20], qr[0]) qc.u(rnd[21], rnd[22], rnd[23], qr[1]) - sim = UnitarySimulatorPy() - unitary = sim.run(qc, seed_simulator=seed).result().get_unitary() + unitary = Operator(qc) self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3) diff --git a/test/visual/mpl/graph/test_graph_matplotlib_drawer.py b/test/visual/mpl/graph/test_graph_matplotlib_drawer.py index fe3a6260d83f..9bc87457bb41 100644 --- a/test/visual/mpl/graph/test_graph_matplotlib_drawer.py +++ b/test/visual/mpl/graph/test_graph_matplotlib_drawer.py @@ -18,7 +18,6 @@ from contextlib import contextmanager from pathlib import Path -from qiskit import BasicAer, transpile from qiskit.test import QiskitTestCase from qiskit import QuantumCircuit from qiskit.utils import optionals @@ -33,6 +32,7 @@ FakeMumbai, FakeManhattan, ) +from qiskit.quantum_info import Statevector if optionals.HAS_MATPLOTLIB: from matplotlib.pyplot import close as mpl_close @@ -100,10 +100,8 @@ def test_plot_bloch_multivector(self): circuit = QuantumCircuit(1) circuit.h(0) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(circuit).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "bloch_multivector.png" self.graph_state_drawer(state=state, output="bloch", filename=fname) @@ -122,10 +120,8 @@ def test_plot_state_hinton(self): circuit = QuantumCircuit(1) circuit.x(0) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(circuit).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "hinton.png" self.graph_state_drawer(state=state, output="hinton", filename=fname) @@ -144,10 +140,8 @@ def test_plot_state_qsphere(self): circuit = QuantumCircuit(1) circuit.x(0) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(circuit).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "qsphere.png" self.graph_state_drawer(state=state, output="qsphere", filename=fname) @@ -166,10 +160,8 @@ def test_plot_state_city(self): circuit = QuantumCircuit(1) circuit.x(0) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(circuit).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "state_city.png" self.graph_state_drawer(state=state, output="city", filename=fname) @@ -188,10 +180,8 @@ def test_plot_state_paulivec(self): circuit = QuantumCircuit(1) circuit.x(0) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(circuit).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "paulivec.png" self.graph_state_drawer(state=state, output="paulivec", filename=fname) @@ -646,10 +636,8 @@ def test_plot_bloch_multivector_figsize_improvements(self): circuit.h(1) circuit.sxdg(2) - # getting the state using backend - backend = BasicAer.get_backend("statevector_simulator") - result = backend.run(transpile(circuit, backend)).result() - state = result.get_statevector(circuit) + # getting the state using quantum_info + state = Statevector(circuit) fname = "bloch_multivector_figsize_improvements.png" self.graph_state_drawer(