From bdbdc7e7ac21c14ef42f141d098a2af1d81a7e33 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 9 Sep 2024 22:52:30 +0800 Subject: [PATCH 01/59] GlobalBackend -> _Global --- doc/source/code-examples/advancedexamples.rst | 4 +- src/qibo/backends/__init__.py | 93 +++++++++++++------ src/qibo/models/circuit.py | 11 ++- src/qibo/models/error_mitigation.py | 4 +- tests/test_backends_clifford.py | 8 +- tests/test_backends_global.py | 8 +- tests/test_backends_qibotn.py | 4 +- tests/test_backends_qulacs.py | 4 +- 8 files changed, 86 insertions(+), 50 deletions(-) diff --git a/doc/source/code-examples/advancedexamples.rst b/doc/source/code-examples/advancedexamples.rst index 50ebdef539..7a508b83f7 100644 --- a/doc/source/code-examples/advancedexamples.rst +++ b/doc/source/code-examples/advancedexamples.rst @@ -1261,9 +1261,9 @@ As observable we can simply take :math:`Z_0 Z_1 Z_2` : from qibo.symbols import Z from qibo.hamiltonians import SymbolicHamiltonian - from qibo.backends import GlobalBackend + from qibo.backends import _Global - backend = GlobalBackend() + backend = _Global.backend() # Define the observable obs = np.prod([Z(i) for i in range(nqubits)]) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 77aaab3442..e237940140 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -65,10 +65,11 @@ def list_available(self) -> dict: return available_backends -class GlobalBackend(NumpyBackend): - """The global backend will be used as default by ``circuit.execute()``.""" +class _Global: + _backend = None + _transpiler = None - _instance = None + # _instance = None _dtypes = {"double": "complex128", "single": "complex64"} _default_order = [ {"backend": "qibojit", "platform": "cupy"}, @@ -78,39 +79,71 @@ class GlobalBackend(NumpyBackend): {"backend": "pytorch"}, ] - def __new__(cls): - if cls._instance is not None: - return cls._instance + @classmethod + def backend(cls): # pragma: no cover + if cls._backend is not None: + return cls._backend backend = os.environ.get("QIBO_BACKEND") - if backend: # pragma: no cover + if backend: # Create backend specified by user platform = os.environ.get("QIBO_PLATFORM") - cls._instance = construct_backend(backend, platform=platform) + cls._backend = construct_backend(backend, platform=platform) else: # Create backend according to default order for kwargs in cls._default_order: try: - cls._instance = construct_backend(**kwargs) + cls._backend = construct_backend(**kwargs) break - except (ImportError, MissingBackend): + except (ModuleNotFoundError, ImportError): pass - if cls._instance is None: # pragma: no cover + if cls._backend is None: raise_error(RuntimeError, "No backends available.") - log.info(f"Using {cls._instance} backend on {cls._instance.device}") - return cls._instance - + log.info(f"Using {cls._backend} backend on {cls._backend.device}") + return cls._backend + @classmethod - def set_backend(cls, backend, **kwargs): # pragma: no cover + def set_backend(cls, backend, **kwargs): # pragma: no cover if ( - cls._instance is None - or cls._instance.name != backend - or cls._instance.platform != kwargs.get("platform") + cls._backend is None + or cls._backend.name != backend + or cls._backend.platform != kwargs.get("platform") ): - cls._instance = construct_backend(backend, **kwargs) - log.info(f"Using {cls._instance} backend on {cls._instance.device}") + cls._backend = construct_backend(backend, **kwargs) + log.info(f"Using {cls._backend} backend on {cls._backend.device}") + + @classmethod + def get_backend(cls): + return cls._backend + + @classmethod + def transpiler(cls): # pragma: no cover + from qibo.transpiler.pipeline import Passes + + if cls._transpiler is not None: + return cls._transpiler + + cls._transpiler = Passes() + # TODO: Add default passes + return cls._transpiler + + @classmethod + def set_transpiler(cls, transpiler): # pragma: no cover + cls._transpiler = transpiler + # TODO: check if transpiler is valid on the backend + + @classmethod + def get_transpiler(cls): + return cls._transpiler + + @classmethod + def resolve_global(cls): + if cls._backend is None: + cls._backend = cls.backend() + if cls._transpiler is None: + cls._transpiler = cls.transpiler() class QiboMatrices: @@ -147,24 +180,24 @@ def create(self, dtype): def get_backend(): - return str(GlobalBackend()) + return str(_Global.get_backend()) def set_backend(backend, **kwargs): - GlobalBackend.set_backend(backend, **kwargs) + _Global.set_backend(backend, **kwargs) def get_precision(): - return GlobalBackend().precision + return _Global.get_backend().precision def set_precision(precision): - GlobalBackend().set_precision(precision) - matrices.create(GlobalBackend().dtype) + _Global.get_backend().set_precision(precision) + matrices.create(_Global.get_backend().dtype) def get_device(): - return GlobalBackend().device + return _Global.get_backend().device def set_device(device): @@ -174,13 +207,13 @@ def set_device(device): ValueError, "Device name should follow the pattern: /{device type}:{device number}.", ) - backend = GlobalBackend() + backend = _Global.get_backend() backend.set_device(device) log.info(f"Using {backend} backend on {backend.device}") def get_threads(): - return GlobalBackend().nthreads + return _Global.get_backend().nthreads def set_threads(nthreads): @@ -188,12 +221,12 @@ def set_threads(nthreads): raise_error(TypeError, "Number of threads must be integer.") if nthreads < 1: raise_error(ValueError, "Number of threads must be positive.") - GlobalBackend().set_threads(nthreads) + _Global.get_backend().set_threads(nthreads) def _check_backend(backend): if backend is None: - return GlobalBackend() + return _Global.backend() return backend diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index c4586c5ae2..68190b60f5 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1099,14 +1099,17 @@ def execute(self, initial_state=None, nshots=1000): self._final_state = self.compiled.result(state, nshots) return self._final_state else: - from qibo.backends import GlobalBackend + from qibo.backends import _Global + + _Global.resolve_global() + transpiled_circuit = _Global.get_transpiler()(self) if self.accelerators: # pragma: no cover - return GlobalBackend().execute_distributed_circuit( - self, initial_state, nshots + return _Global.get_backend().execute_distributed_circuit( + transpiled_circuit, initial_state, nshots ) else: - return GlobalBackend().execute_circuit(self, initial_state, nshots) + return _Global.get_backend().execute_circuit(transpiled_circuit, initial_state, nshots) def __call__(self, initial_state=None, nshots=1000): """Equivalent to ``circuit.execute``.""" diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index eea1071399..d30d043441 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -7,7 +7,7 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import GlobalBackend, _check_backend, _check_backend_and_local_state +from qibo.backends import _Global, _check_backend, _check_backend_and_local_state from qibo.config import raise_error @@ -1095,7 +1095,7 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend from qibo.transpiler.placer import Custom if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = _Global.backend() elif backend.name == "qibolab": # pragma: no cover backend.transpiler.passes[1] = Custom( initial_map=qubit_map, connectivity=backend.platform.topology diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 5e4bae9d64..29c429f549 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -8,7 +8,7 @@ from qibo import Circuit, gates, set_backend from qibo.backends import ( CliffordBackend, - GlobalBackend, + _Global, NumpyBackend, PyTorchBackend, TensorflowBackend, @@ -36,8 +36,8 @@ def test_set_backend(backend): clifford_bkd = construct_clifford_backend(backend) platform = _get_engine_name(backend) set_backend("clifford", platform=platform) - assert isinstance(GlobalBackend(), CliffordBackend) - global_platform = GlobalBackend().platform + assert isinstance(_Global.get_backend(), CliffordBackend) + global_platform = _Global.get_backend().platform assert global_platform == platform @@ -46,7 +46,7 @@ def test_global_backend(backend): set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() target = ( - GlobalBackend().name if backend.name == "numpy" else GlobalBackend().platform + _Global.get_backend().name if backend.name == "numpy" else _Global.get_backend().platform ) assert clifford_bkd.platform == target set_backend("numpy") diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 9ad3a4b2f4..ca64d40e38 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -5,12 +5,12 @@ def test_set_backend(): - from qibo.backends import GlobalBackend + from qibo.backends import _Global - backend = GlobalBackend() + backend = _Global.backend() qibo.set_backend("numpy") assert qibo.get_backend() == "numpy" - assert GlobalBackend().name == "numpy" + assert _Global.get_backend().name == "numpy" def test_set_precision(): @@ -104,7 +104,7 @@ def test_check_backend(backend): test = None test = qibo.backends._check_backend(test) - target = qibo.backends.GlobalBackend() + target = qibo.backends._Global.backend() assert test.name == target.name assert test.__class__ == target.__class__ diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index ae850afefa..73ed4c6488 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -6,11 +6,11 @@ os.environ["NUMBA_NUM_THREADS"] = f"{qibo.get_threads()}" from qibotn.backends.quimb import QuimbBackend -from qibo.backends import GlobalBackend +from qibo.backends import _Global def test_backend_qibotn(): qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=None) - assert isinstance(GlobalBackend(), QuimbBackend) + assert isinstance(_Global.get_backend(), QuimbBackend) qibo.set_backend("numpy") diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 48f7c6d65c..9518ad25e2 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates -from qibo.backends import GlobalBackend, MetaBackend, NumpyBackend, set_backend +from qibo.backends import _Global, MetaBackend, NumpyBackend, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() @@ -40,4 +40,4 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") - assert GlobalBackend().name == "qulacs" + assert _Global.get_backend().name == "qulacs" From 98d07ffa50ed66cb996313c9722a7da2d63da893 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 10 Sep 2024 00:08:38 +0800 Subject: [PATCH 02/59] GlobalBackend -> _Global --- src/qibo/backends/__init__.py | 5 ++--- src/qibo/models/circuit.py | 2 +- src/qibo/models/error_mitigation.py | 1 + tests/test_backends_qibotn.py | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index e237940140..744f2892d5 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -69,7 +69,6 @@ class _Global: _backend = None _transpiler = None - # _instance = None _dtypes = {"double": "complex128", "single": "complex64"} _default_order = [ {"backend": "qibojit", "platform": "cupy"}, @@ -125,8 +124,8 @@ def transpiler(cls): # pragma: no cover if cls._transpiler is not None: return cls._transpiler - cls._transpiler = Passes() - # TODO: Add default passes + cls._transpiler = Passes(passes=[]) + # TODO: add default passes or use Passes.default() return cls._transpiler @classmethod diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 68190b60f5..3c93c78507 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1102,7 +1102,7 @@ def execute(self, initial_state=None, nshots=1000): from qibo.backends import _Global _Global.resolve_global() - transpiled_circuit = _Global.get_transpiler()(self) + transpiled_circuit, _ = _Global.get_transpiler()(self) if self.accelerators: # pragma: no cover return _Global.get_backend().execute_distributed_circuit( diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index d30d043441..bf4c1a1da1 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -1097,6 +1097,7 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend if backend is None: # pragma: no cover backend = _Global.backend() elif backend.name == "qibolab": # pragma: no cover + # TODO: Use _Global.set_transpiler backend.transpiler.passes[1] = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index 73ed4c6488..2949175d63 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -1,8 +1,10 @@ import os import qibo +from qibo.backends import _Global # Force quimb to use qibojit default number of threads. +_Global.backend() os.environ["NUMBA_NUM_THREADS"] = f"{qibo.get_threads()}" from qibotn.backends.quimb import QuimbBackend From b3fcc2ac8d562cd1d58788367dfecc87a2fe0f73 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:27:58 +0000 Subject: [PATCH 03/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 16 ++++++++-------- src/qibo/models/circuit.py | 4 +++- src/qibo/models/error_mitigation.py | 2 +- tests/test_backends_clifford.py | 6 ++++-- tests/test_backends_qulacs.py | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 744f2892d5..4bfbb2f3b4 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -78,8 +78,8 @@ class _Global: {"backend": "pytorch"}, ] - @classmethod - def backend(cls): # pragma: no cover + @classmethod + def backend(cls): # pragma: no cover if cls._backend is not None: return cls._backend @@ -102,9 +102,9 @@ def backend(cls): # pragma: no cover log.info(f"Using {cls._backend} backend on {cls._backend.device}") return cls._backend - + @classmethod - def set_backend(cls, backend, **kwargs): # pragma: no cover + def set_backend(cls, backend, **kwargs): # pragma: no cover if ( cls._backend is None or cls._backend.name != backend @@ -116,9 +116,9 @@ def set_backend(cls, backend, **kwargs): # pragma: no cover @classmethod def get_backend(cls): return cls._backend - + @classmethod - def transpiler(cls): # pragma: no cover + def transpiler(cls): # pragma: no cover from qibo.transpiler.pipeline import Passes if cls._transpiler is not None: @@ -127,7 +127,7 @@ def transpiler(cls): # pragma: no cover cls._transpiler = Passes(passes=[]) # TODO: add default passes or use Passes.default() return cls._transpiler - + @classmethod def set_transpiler(cls, transpiler): # pragma: no cover cls._transpiler = transpiler @@ -136,7 +136,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover @classmethod def get_transpiler(cls): return cls._transpiler - + @classmethod def resolve_global(cls): if cls._backend is None: diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 3c93c78507..718fbeae48 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1109,7 +1109,9 @@ def execute(self, initial_state=None, nshots=1000): transpiled_circuit, initial_state, nshots ) else: - return _Global.get_backend().execute_circuit(transpiled_circuit, initial_state, nshots) + return _Global.get_backend().execute_circuit( + transpiled_circuit, initial_state, nshots + ) def __call__(self, initial_state=None, nshots=1000): """Equivalent to ``circuit.execute``.""" diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index bf4c1a1da1..a813264c24 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -7,7 +7,7 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import _Global, _check_backend, _check_backend_and_local_state +from qibo.backends import _check_backend, _check_backend_and_local_state, _Global from qibo.config import raise_error diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 29c429f549..2c8b0e50d1 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -8,10 +8,10 @@ from qibo import Circuit, gates, set_backend from qibo.backends import ( CliffordBackend, - _Global, NumpyBackend, PyTorchBackend, TensorflowBackend, + _Global, ) from qibo.backends.clifford import _get_engine_name from qibo.noise import DepolarizingError, NoiseModel, PauliError @@ -46,7 +46,9 @@ def test_global_backend(backend): set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() target = ( - _Global.get_backend().name if backend.name == "numpy" else _Global.get_backend().platform + _Global.get_backend().name + if backend.name == "numpy" + else _Global.get_backend().platform ) assert clifford_bkd.platform == target set_backend("numpy") diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 9518ad25e2..822657844a 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates -from qibo.backends import _Global, MetaBackend, NumpyBackend, set_backend +from qibo.backends import MetaBackend, NumpyBackend, _Global, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() From f8a3cfcdddf288255dff81e3dbd885c0f16e40f2 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 10 Sep 2024 00:40:35 +0800 Subject: [PATCH 04/59] disable not callable error --- src/qibo/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 4bfbb2f3b4..277cb7bd04 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -134,7 +134,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): + def get_transpiler(cls): # pylint: disable=E1102 return cls._transpiler @classmethod From 5b312bf45cdbb8d23bd679d516cafa81ee7c29b0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:41:11 +0000 Subject: [PATCH 05/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 277cb7bd04..dd5493a43e 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -134,7 +134,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): # pylint: disable=E1102 + def get_transpiler(cls): # pylint: disable=E1102 return cls._transpiler @classmethod From 4697a9ff4da5287e5d0c243ac8c3cf9bac65e926 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 10 Sep 2024 00:46:29 +0800 Subject: [PATCH 06/59] disable not callable error --- src/qibo/backends/__init__.py | 2 +- src/qibo/models/circuit.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index dd5493a43e..0231e5708e 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -134,7 +134,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): # pylint: disable=E1102 + def get_transpiler(cls): return cls._transpiler @classmethod diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 718fbeae48..f636cd89cc 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1102,7 +1102,7 @@ def execute(self, initial_state=None, nshots=1000): from qibo.backends import _Global _Global.resolve_global() - transpiled_circuit, _ = _Global.get_transpiler()(self) + transpiled_circuit, _ = _Global.get_transpiler()(self) # pylint: disable=E1102 if self.accelerators: # pragma: no cover return _Global.get_backend().execute_distributed_circuit( From e58157bb917fc3e957e72fde4221692d065567ec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:47:02 +0000 Subject: [PATCH 07/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 2 +- src/qibo/models/circuit.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 0231e5708e..4bfbb2f3b4 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -134,7 +134,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): + def get_transpiler(cls): return cls._transpiler @classmethod diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index f636cd89cc..26b68a9135 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1102,7 +1102,9 @@ def execute(self, initial_state=None, nshots=1000): from qibo.backends import _Global _Global.resolve_global() - transpiled_circuit, _ = _Global.get_transpiler()(self) # pylint: disable=E1102 + transpiled_circuit, _ = _Global.get_transpiler()( + self + ) # pylint: disable=E1102 if self.accelerators: # pragma: no cover return _Global.get_backend().execute_distributed_circuit( From 583d26b1ef5e9fb6da3863ab79c3d6710ab9ae74 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 10 Sep 2024 14:51:17 +0800 Subject: [PATCH 08/59] fix bug --- src/qibo/backends/__init__.py | 4 +++- src/qibo/models/circuit.py | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 4bfbb2f3b4..d027590b04 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -111,7 +111,9 @@ def set_backend(cls, backend, **kwargs): # pragma: no cover or cls._backend.platform != kwargs.get("platform") ): cls._backend = construct_backend(backend, **kwargs) - log.info(f"Using {cls._backend} backend on {cls._backend.device}") + log.info(f"Using {cls._backend} backend on {cls._backend.device}") + else: + log.info(f"Backend {backend} is already loaded.") @classmethod def get_backend(cls): diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 26b68a9135..546bab3f59 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1102,9 +1102,8 @@ def execute(self, initial_state=None, nshots=1000): from qibo.backends import _Global _Global.resolve_global() - transpiled_circuit, _ = _Global.get_transpiler()( - self - ) # pylint: disable=E1102 + transpiler = _Global.get_transpiler() + transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102 if self.accelerators: # pragma: no cover return _Global.get_backend().execute_distributed_circuit( From 2419d7d22dd516d931ca99c4015d1e40435dd29a Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 10 Sep 2024 15:37:11 +0800 Subject: [PATCH 09/59] add funcs --- src/qibo/backends/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index d027590b04..94c5400363 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -127,7 +127,6 @@ def transpiler(cls): # pragma: no cover return cls._transpiler cls._transpiler = Passes(passes=[]) - # TODO: add default passes or use Passes.default() return cls._transpiler @classmethod @@ -144,6 +143,7 @@ def resolve_global(cls): if cls._backend is None: cls._backend = cls.backend() if cls._transpiler is None: + # TODO: add default transpiler for hardware backends cls._transpiler = cls.transpiler() @@ -188,6 +188,14 @@ def set_backend(backend, **kwargs): _Global.set_backend(backend, **kwargs) +def get_transpiler(): + return str(_Global.get_transpiler()) + + +def set_transpiler(transpiler): + _Global.set_transpiler(transpiler) + + def get_precision(): return _Global.get_backend().precision From 32ed23aca0f889697f8756fe826be9e1655bb6ea Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 16 Sep 2024 20:06:32 +0900 Subject: [PATCH 10/59] update test funcs --- src/qibo/backends/__init__.py | 2 +- tests/test_backends_global.py | 47 +++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 94c5400363..109152c926 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -135,7 +135,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): + def get_transpiler(cls): # pragma: no cover return cls._transpiler @classmethod diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index ca64d40e38..3c60431524 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -2,9 +2,9 @@ import qibo from qibo import matrices +import networkx as nx - -def test_set_backend(): +def test_set_get_backend(): from qibo.backends import _Global backend = _Global.backend() @@ -108,3 +108,46 @@ def test_check_backend(backend): assert test.name == target.name assert test.__class__ == target.__class__ + +def test_resolve_global(): + from qibo.backends import _Global + + _Global._backend = None + _Global._transpiler = None + + assert _Global._backend is None + assert _Global._transpiler is None + _Global.resolve_global() + assert issubclass(_Global._backend.__class__, qibo.backends.Backend) + assert _Global._transpiler is not None + +def _star_connectivity(): + Q = [i for i in range(5)] + chip = nx.Graph() + chip.add_nodes_from(Q) + graph_list = [(Q[i], Q[2]) for i in range(5) if i != 2] + chip.add_edges_from(graph_list) + return chip + +def test_set_get_transpiler(): + from qibo.backends import _Global + from qibo.transpiler.pipeline import Passes + from qibo.transpiler.optimizer import Preprocessing + from qibo.transpiler.placer import Random + from qibo.transpiler.router import Sabre + from qibo.transpiler.unroller import NativeGates, Unroller + + connectivity = _star_connectivity() + transpiler = Passes( + connectivity=connectivity, + passes=[ + Preprocessing(connectivity), + Random(connectivity, seed=0), + Sabre(connectivity), + Unroller(NativeGates.default()), + ] + ) + + _Global.set_transpiler(transpiler) + assert _Global.get_transpiler() == transpiler + From 435c5f52063d4074de356251bc4739612016c7fa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:07:08 +0000 Subject: [PATCH 11/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 2 +- tests/test_backends_global.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 109152c926..92303569f1 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -135,7 +135,7 @@ def set_transpiler(cls, transpiler): # pragma: no cover # TODO: check if transpiler is valid on the backend @classmethod - def get_transpiler(cls): # pragma: no cover + def get_transpiler(cls): # pragma: no cover return cls._transpiler @classmethod diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 3c60431524..aeac33c6ea 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -1,8 +1,9 @@ +import networkx as nx import pytest import qibo from qibo import matrices -import networkx as nx + def test_set_get_backend(): from qibo.backends import _Global @@ -109,6 +110,7 @@ def test_check_backend(backend): assert test.name == target.name assert test.__class__ == target.__class__ + def test_resolve_global(): from qibo.backends import _Global @@ -121,6 +123,7 @@ def test_resolve_global(): assert issubclass(_Global._backend.__class__, qibo.backends.Backend) assert _Global._transpiler is not None + def _star_connectivity(): Q = [i for i in range(5)] chip = nx.Graph() @@ -129,10 +132,11 @@ def _star_connectivity(): chip.add_edges_from(graph_list) return chip + def test_set_get_transpiler(): from qibo.backends import _Global - from qibo.transpiler.pipeline import Passes from qibo.transpiler.optimizer import Preprocessing + from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Random from qibo.transpiler.router import Sabre from qibo.transpiler.unroller import NativeGates, Unroller @@ -145,9 +149,8 @@ def test_set_get_transpiler(): Random(connectivity, seed=0), Sabre(connectivity), Unroller(NativeGates.default()), - ] + ], ) _Global.set_transpiler(transpiler) assert _Global.get_transpiler() == transpiler - From 94cb879a27a5204b9dcd8296eeecb0cc2db976e5 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 18 Sep 2024 23:06:58 +0900 Subject: [PATCH 12/59] update review --- doc/source/code-examples/advancedexamples.rst | 3 +- src/qibo/backends/__init__.py | 115 +++++++++++------- src/qibo/models/circuit.py | 26 ++-- tests/test_backends_clifford.py | 10 +- tests/test_backends_global.py | 6 +- tests/test_backends_qibotn.py | 16 ++- tests/test_backends_qulacs.py | 5 +- 7 files changed, 103 insertions(+), 78 deletions(-) diff --git a/doc/source/code-examples/advancedexamples.rst b/doc/source/code-examples/advancedexamples.rst index 7a508b83f7..581d1c3525 100644 --- a/doc/source/code-examples/advancedexamples.rst +++ b/doc/source/code-examples/advancedexamples.rst @@ -1261,9 +1261,8 @@ As observable we can simply take :math:`Z_0 Z_1 Z_2` : from qibo.symbols import Z from qibo.hamiltonians import SymbolicHamiltonian - from qibo.backends import _Global - backend = _Global.backend() + backend = qibo.get_backend() # Define the observable obs = np.prod([Z(i) for i in range(nqubits)]) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 92303569f1..d789b37552 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -79,48 +79,39 @@ class _Global: ] @classmethod - def backend(cls): # pragma: no cover + def backend(cls): if cls._backend is not None: return cls._backend - - backend = os.environ.get("QIBO_BACKEND") - if backend: + cls._backend = cls._create_backend() + return cls._backend + + @classmethod + def _create_backend(cls): + backend_env = os.environ.get("QIBO_BACKEND") + if backend_env: # Create backend specified by user platform = os.environ.get("QIBO_PLATFORM") - cls._backend = construct_backend(backend, platform=platform) + backend = construct_backend(backend_env, platform=platform) else: # Create backend according to default order for kwargs in cls._default_order: try: - cls._backend = construct_backend(**kwargs) + backend = construct_backend(**kwargs) break except (ModuleNotFoundError, ImportError): pass - - if cls._backend is None: + + if backend is None: raise_error(RuntimeError, "No backends available.") - - log.info(f"Using {cls._backend} backend on {cls._backend.device}") - return cls._backend - - @classmethod - def set_backend(cls, backend, **kwargs): # pragma: no cover - if ( - cls._backend is None - or cls._backend.name != backend - or cls._backend.platform != kwargs.get("platform") - ): - cls._backend = construct_backend(backend, **kwargs) - log.info(f"Using {cls._backend} backend on {cls._backend.device}") - else: - log.info(f"Backend {backend} is already loaded.") + return backend @classmethod - def get_backend(cls): - return cls._backend + def set_backend(cls, backend, **kwargs): + cls._backend = construct_backend(backend, **kwargs) + log.info(f"Using {cls._backend} backend on {cls._backend.device}") @classmethod - def transpiler(cls): # pragma: no cover + def transpiler(cls): from qibo.transpiler.pipeline import Passes if cls._transpiler is not None: @@ -130,14 +121,10 @@ def transpiler(cls): # pragma: no cover return cls._transpiler @classmethod - def set_transpiler(cls, transpiler): # pragma: no cover + def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend - @classmethod - def get_transpiler(cls): # pragma: no cover - return cls._transpiler - @classmethod def resolve_global(cls): if cls._backend is None: @@ -180,62 +167,102 @@ def create(self, dtype): matrices = QiboMatrices() -def get_backend(): - return str(_Global.get_backend()) +def get_backend(as_string=False): + """Get the current backend. + Args: + as_string (bool): If True return the name of the backend as a string. + """ + if as_string: + return str(_Global.backend()) + return _Global.backend() def set_backend(backend, **kwargs): - _Global.set_backend(backend, **kwargs) + """Set the current backend. + Args: + backend (str): Name of the backend to use. + kwargs (dict): Additional arguments for the backend. + """ + _Global.set_backend(backend, **kwargs) -def get_transpiler(): - return str(_Global.get_transpiler()) +def get_transpiler(as_string=False): + """Get the current transpiler. + Args: + as_string (bool): If True return the transpiler as a string. + """ + if as_string: + return str(_Global.get_transpiler()) + return _Global.get_transpiler() def set_transpiler(transpiler): + """Set the current transpiler. + + Args: + transpiler (Passes): The transpiler to use. + """ _Global.set_transpiler(transpiler) def get_precision(): - return _Global.get_backend().precision + """Get the precision of the backend.""" + return get_backend().precision def set_precision(precision): - _Global.get_backend().set_precision(precision) - matrices.create(_Global.get_backend().dtype) + """Set the precision of the backend. + + Args: + precision (str): Precision to use. + """ + get_backend().set_precision(precision) + matrices.create(get_backend().dtype) def get_device(): - return _Global.get_backend().device + """Get the device of the backend.""" + return get_backend().device def set_device(device): + """Set the device of the backend. + + Args: + device (str): Device to use. + """ parts = device[1:].split(":") if device[0] != "/" or len(parts) < 2 or len(parts) > 3: raise_error( ValueError, "Device name should follow the pattern: /{device type}:{device number}.", ) - backend = _Global.get_backend() + backend = get_backend() backend.set_device(device) log.info(f"Using {backend} backend on {backend.device}") def get_threads(): - return _Global.get_backend().nthreads + """Get the number of threads used by the backend.""" + return get_backend().nthreads def set_threads(nthreads): + """Set the number of threads used by the backend. + + Args: + nthreads (int): Number of threads to use. + """ if not isinstance(nthreads, int): raise_error(TypeError, "Number of threads must be integer.") if nthreads < 1: raise_error(ValueError, "Number of threads must be positive.") - _Global.get_backend().set_threads(nthreads) + get_backend().set_threads(nthreads) def _check_backend(backend): if backend is None: - return _Global.backend() + return get_backend() return backend diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 546bab3f59..372f620a9c 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -9,6 +9,7 @@ from qibo.config import raise_error from qibo.gates.abstract import Gate from qibo.models._openqasm import QASMParser +from qibo.backends import _Global NoiseMapType = Union[Tuple[int, int, int], Dict[int, Tuple[int, int, int]]] @@ -1098,21 +1099,20 @@ def execute(self, initial_state=None, nshots=1000): state = self.compiled.executor(initial_state, nshots) self._final_state = self.compiled.result(state, nshots) return self._final_state - else: - from qibo.backends import _Global - _Global.resolve_global() - transpiler = _Global.get_transpiler() - transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102 + _Global.resolve_global() + transpiler = _Global.transpiler() + transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102 - if self.accelerators: # pragma: no cover - return _Global.get_backend().execute_distributed_circuit( - transpiled_circuit, initial_state, nshots - ) - else: - return _Global.get_backend().execute_circuit( - transpiled_circuit, initial_state, nshots - ) + backend = qibo.get_backend() + if self.accelerators: # pragma: no cover + return backend.execute_distributed_circuit( + transpiled_circuit, initial_state, nshots + ) + else: + return backend.execute_circuit( + transpiled_circuit, initial_state, nshots + ) def __call__(self, initial_state=None, nshots=1000): """Equivalent to ``circuit.execute``.""" diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 2c8b0e50d1..1592930b3f 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from qibo import Circuit, gates, set_backend +from qibo import Circuit, gates, set_backend, get_backend from qibo.backends import ( CliffordBackend, NumpyBackend, @@ -36,8 +36,8 @@ def test_set_backend(backend): clifford_bkd = construct_clifford_backend(backend) platform = _get_engine_name(backend) set_backend("clifford", platform=platform) - assert isinstance(_Global.get_backend(), CliffordBackend) - global_platform = _Global.get_backend().platform + assert isinstance(get_backend(), CliffordBackend) + global_platform = get_backend().platform assert global_platform == platform @@ -46,9 +46,9 @@ def test_global_backend(backend): set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() target = ( - _Global.get_backend().name + _Global._backend.name if backend.name == "numpy" - else _Global.get_backend().platform + else _Global._backend.platform ) assert clifford_bkd.platform == target set_backend("numpy") diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index aeac33c6ea..a7233f48e1 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -10,8 +10,8 @@ def test_set_get_backend(): backend = _Global.backend() qibo.set_backend("numpy") - assert qibo.get_backend() == "numpy" - assert _Global.get_backend().name == "numpy" + assert qibo.get_backend(as_string=True) == "numpy" + assert qibo.get_backend().name == "numpy" def test_set_precision(): @@ -153,4 +153,4 @@ def test_set_get_transpiler(): ) _Global.set_transpiler(transpiler) - assert _Global.get_transpiler() == transpiler + assert _Global.transpiler() == transpiler diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index 2949175d63..45da8d8ae2 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -1,18 +1,16 @@ import os -import qibo +# import qibo +from qibo import get_threads, set_backend, get_backend from qibo.backends import _Global # Force quimb to use qibojit default number of threads. _Global.backend() -os.environ["NUMBA_NUM_THREADS"] = f"{qibo.get_threads()}" +os.environ["NUMBA_NUM_THREADS"] = f"{get_threads()}" from qibotn.backends.quimb import QuimbBackend -from qibo.backends import _Global - - def test_backend_qibotn(): - qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=None) - assert isinstance(_Global.get_backend(), QuimbBackend) - - qibo.set_backend("numpy") + set_backend(backend="qibotn", platform="qutensornet", runcard=None) + assert isinstance(get_backend(), QuimbBackend) + set_backend("numpy") + assert get_backend().name == "numpy" diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 822657844a..d1c89e98ea 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from qibo import Circuit, gates +from qibo import Circuit, gates, get_backend from qibo.backends import MetaBackend, NumpyBackend, _Global, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector @@ -40,4 +40,5 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") - assert _Global.get_backend().name == "qulacs" + # assert _Global.get_backend().name == "qulacs" + assert get_backend().name == "qulacs" From efb22c56dff355338f4885e0ab9d699a68d0ff77 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 07:06:15 +0000 Subject: [PATCH 13/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 9 ++++++--- src/qibo/models/circuit.py | 6 ++---- tests/test_backends_clifford.py | 6 ++---- tests/test_backends_qibotn.py | 3 ++- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index d789b37552..16b33bdcdc 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -84,7 +84,7 @@ def backend(cls): return cls._backend cls._backend = cls._create_backend() return cls._backend - + @classmethod def _create_backend(cls): backend_env = os.environ.get("QIBO_BACKEND") @@ -100,7 +100,7 @@ def _create_backend(cls): break except (ModuleNotFoundError, ImportError): pass - + if backend is None: raise_error(RuntimeError, "No backends available.") return backend @@ -121,7 +121,7 @@ def transpiler(cls): return cls._transpiler @classmethod - def set_transpiler(cls, transpiler): + def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend @@ -177,6 +177,7 @@ def get_backend(as_string=False): return str(_Global.backend()) return _Global.backend() + def set_backend(backend, **kwargs): """Set the current backend. @@ -186,6 +187,7 @@ def set_backend(backend, **kwargs): """ _Global.set_backend(backend, **kwargs) + def get_transpiler(as_string=False): """Get the current transpiler. @@ -196,6 +198,7 @@ def get_transpiler(as_string=False): return str(_Global.get_transpiler()) return _Global.get_transpiler() + def set_transpiler(transpiler): """Set the current transpiler. diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index b03f798aca..9b193da4cf 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -7,10 +7,10 @@ import qibo from qibo import gates +from qibo.backends import _Global from qibo.config import raise_error from qibo.gates.abstract import Gate from qibo.models._openqasm import QASMParser -from qibo.backends import _Global NoiseMapType = Union[Tuple[int, int, int], Dict[int, Tuple[int, int, int]]] @@ -1111,9 +1111,7 @@ def execute(self, initial_state=None, nshots=1000): transpiled_circuit, initial_state, nshots ) else: - return backend.execute_circuit( - transpiled_circuit, initial_state, nshots - ) + return backend.execute_circuit(transpiled_circuit, initial_state, nshots) def __call__(self, initial_state=None, nshots=1000): """Equivalent to ``circuit.execute``.""" diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 1592930b3f..6e133a4cef 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -5,7 +5,7 @@ import numpy as np import pytest -from qibo import Circuit, gates, set_backend, get_backend +from qibo import Circuit, gates, get_backend, set_backend from qibo.backends import ( CliffordBackend, NumpyBackend, @@ -46,9 +46,7 @@ def test_global_backend(backend): set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() target = ( - _Global._backend.name - if backend.name == "numpy" - else _Global._backend.platform + _Global._backend.name if backend.name == "numpy" else _Global._backend.platform ) assert clifford_bkd.platform == target set_backend("numpy") diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index 45da8d8ae2..e5b4c87b35 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -1,7 +1,7 @@ import os # import qibo -from qibo import get_threads, set_backend, get_backend +from qibo import get_backend, get_threads, set_backend from qibo.backends import _Global # Force quimb to use qibojit default number of threads. @@ -9,6 +9,7 @@ os.environ["NUMBA_NUM_THREADS"] = f"{get_threads()}" from qibotn.backends.quimb import QuimbBackend + def test_backend_qibotn(): set_backend(backend="qibotn", platform="qutensornet", runcard=None) assert isinstance(get_backend(), QuimbBackend) From b2f82d50d0de48f4c4c3c048c707613c27f4c230 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 11:00:04 +0400 Subject: [PATCH 14/59] update test files --- src/qibo/backends/__init__.py | 29 ++++++++++++----------------- tests/test_backends_qibotn.py | 2 -- tests/test_backends_qulacs.py | 3 +-- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 16b33bdcdc..ad8ef9703c 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -166,17 +166,14 @@ def create(self, dtype): matrices = QiboMatrices() - -def get_backend(as_string=False): - """Get the current backend. - - Args: - as_string (bool): If True return the name of the backend as a string. - """ - if as_string: - return str(_Global.backend()) +def get_backend(): + """Get the current backend.""" return _Global.backend() +def get_backend_name(): + """Get the name of the current backend""" + return str(_Global.backend()) + def set_backend(backend, **kwargs): """Set the current backend. @@ -188,15 +185,13 @@ def set_backend(backend, **kwargs): _Global.set_backend(backend, **kwargs) -def get_transpiler(as_string=False): - """Get the current transpiler. +def get_transpiler(): + """Get the current transpiler.""" + return _Global.transpiler() - Args: - as_string (bool): If True return the transpiler as a string. - """ - if as_string: - return str(_Global.get_transpiler()) - return _Global.get_transpiler() +def get_transpiler_name(): + """Get the name of the current transpiler as a string.""" + return str(_Global.transpiler()) def set_transpiler(transpiler): diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index e5b4c87b35..ca7035016e 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -2,10 +2,8 @@ # import qibo from qibo import get_backend, get_threads, set_backend -from qibo.backends import _Global # Force quimb to use qibojit default number of threads. -_Global.backend() os.environ["NUMBA_NUM_THREADS"] = f"{get_threads()}" from qibotn.backends.quimb import QuimbBackend diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index d1c89e98ea..9ef0d8a9bd 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates, get_backend -from qibo.backends import MetaBackend, NumpyBackend, _Global, set_backend +from qibo.backends import MetaBackend, NumpyBackend, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() @@ -40,5 +40,4 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") - # assert _Global.get_backend().name == "qulacs" assert get_backend().name == "qulacs" From 8b3a95acf71af2fd644ffa9000f531ffc7ddb6ae Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 07:01:15 +0000 Subject: [PATCH 15/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index ad8ef9703c..20e812ba36 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -166,10 +166,12 @@ def create(self, dtype): matrices = QiboMatrices() + def get_backend(): """Get the current backend.""" return _Global.backend() + def get_backend_name(): """Get the name of the current backend""" return str(_Global.backend()) @@ -189,6 +191,7 @@ def get_transpiler(): """Get the current transpiler.""" return _Global.transpiler() + def get_transpiler_name(): """Get the name of the current transpiler as a string.""" return str(_Global.transpiler()) From 352015b44733c85f3ecaebaa45b6124fd892c4a0 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 11:28:29 +0400 Subject: [PATCH 16/59] fix test --- src/qibo/__init__.py | 3 +++ tests/test_backends_global.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qibo/__init__.py b/src/qibo/__init__.py index bcd912f1cc..bf8f084d6b 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -16,6 +16,9 @@ from qibo.backends import ( construct_backend, get_backend, + get_backend_name, + get_transpiler, + get_transpiler_name, get_device, get_precision, get_threads, diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index a7233f48e1..5d78cf3116 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -10,7 +10,7 @@ def test_set_get_backend(): backend = _Global.backend() qibo.set_backend("numpy") - assert qibo.get_backend(as_string=True) == "numpy" + assert qibo.get_backend_name() == "numpy" assert qibo.get_backend().name == "numpy" From 59b0c71ae2e104debdb160f21bc7b761bad98fa3 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 11:35:10 +0400 Subject: [PATCH 17/59] qcnn.py get_backend -> get_backend_name --- src/qibo/models/qcnn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 1066971fa6..5a99c172c8 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -5,7 +5,7 @@ import numpy as np -from qibo import gates, get_backend +from qibo import gates, get_backend_name from qibo.models import Circuit @@ -80,7 +80,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if "qibojit" in get_backend(): + if "qibojit" in get_backend_name(): self.copy_init_state = True else: self.copy_init_state = False From 907bebbc4740a94a2426fcb3a198784fe8fa7c7c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 07:37:53 +0000 Subject: [PATCH 18/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/__init__.py b/src/qibo/__init__.py index bf8f084d6b..44b46e0a45 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -17,11 +17,11 @@ construct_backend, get_backend, get_backend_name, - get_transpiler, - get_transpiler_name, get_device, get_precision, get_threads, + get_transpiler, + get_transpiler_name, list_available_backends, matrices, set_backend, From 7cd16a413314b2ce507c176a6e1c0beb3949714e Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 12:14:47 +0400 Subject: [PATCH 19/59] remove resolve_global --- src/qibo/backends/__init__.py | 14 +++++--------- src/qibo/models/circuit.py | 3 +-- src/qibo/models/error_mitigation.py | 22 ++++++++++------------ 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 20e812ba36..e4c2f35923 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -80,6 +80,7 @@ class _Global: @classmethod def backend(cls): + """Get the current backend. If no backend is set, it will create one.""" if cls._backend is not None: return cls._backend cls._backend = cls._create_backend() @@ -112,10 +113,14 @@ def set_backend(cls, backend, **kwargs): @classmethod def transpiler(cls): + """Get the current transpiler. If no transpiler is set, it will create one.""" from qibo.transpiler.pipeline import Passes if cls._transpiler is not None: return cls._transpiler + + # TODO: add default transpiler for hardware backends + # depends on cls._backend cls._transpiler = Passes(passes=[]) return cls._transpiler @@ -125,15 +130,6 @@ def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend - @classmethod - def resolve_global(cls): - if cls._backend is None: - cls._backend = cls.backend() - if cls._transpiler is None: - # TODO: add default transpiler for hardware backends - cls._transpiler = cls.transpiler() - - class QiboMatrices: def __init__(self, dtype="complex128"): self.create(dtype) diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index 9b193da4cf..e98d74b05d 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1101,11 +1101,10 @@ def execute(self, initial_state=None, nshots=1000): self._final_state = self.compiled.result(state, nshots) return self._final_state - _Global.resolve_global() + backend = _Global.backend() transpiler = _Global.transpiler() transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102 - backend = qibo.get_backend() if self.accelerators: # pragma: no cover return backend.execute_distributed_circuit( transpiled_circuit, initial_state, nshots diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 40dfba5ddb..02fa59203f 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -8,7 +8,7 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import _check_backend, _check_backend_and_local_state, _Global +from qibo.backends import _check_backend, _check_backend_and_local_state, _Global, get_backend, get_backend_name from qibo.config import raise_error @@ -1164,16 +1164,14 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend """ from qibo.transpiler.placer import Custom - if backend is None: # pragma: no cover - backend = _Global.backend() - elif backend.name == "qibolab": # pragma: no cover - # TODO: Use _Global.set_transpiler - backend.transpiler.passes[1] = Custom( - initial_map=qubit_map, connectivity=backend.platform.topology - ) - elif noise_model is not None: - circuit = noise_model.apply(circuit) - - circuit_result = backend.execute_circuit(circuit, nshots=nshots) + # TODO: remove backend.platform.topology and pragma: no cover + backend = get_backend() + if get_backend_name() == "qibolab": # pragma: no cover + transpiler = Custom(initial_map=qubit_map, connectivity=backend.platform.topology) + transpiled_circuit, _ = transpiler(circuit) + + if noise_model is not None: # pragma: no cover + transpiled_circuit = noise_model.apply(transpiled_circuit) + circuit_result = backend.execute_circuit(transpiled_circuit, nshots=nshots) return circuit_result From a3c993d322c18028217888ca62d648624da0607d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:20:28 +0000 Subject: [PATCH 20/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 3 ++- src/qibo/models/error_mitigation.py | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index e4c2f35923..2efa3c40bd 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -118,7 +118,7 @@ def transpiler(cls): if cls._transpiler is not None: return cls._transpiler - + # TODO: add default transpiler for hardware backends # depends on cls._backend @@ -130,6 +130,7 @@ def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend + class QiboMatrices: def __init__(self, dtype="complex128"): self.create(dtype) diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 02fa59203f..d3af653d55 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -8,7 +8,13 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import _check_backend, _check_backend_and_local_state, _Global, get_backend, get_backend_name +from qibo.backends import ( + _check_backend, + _check_backend_and_local_state, + _Global, + get_backend, + get_backend_name, +) from qibo.config import raise_error @@ -1166,12 +1172,14 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend # TODO: remove backend.platform.topology and pragma: no cover backend = get_backend() - if get_backend_name() == "qibolab": # pragma: no cover - transpiler = Custom(initial_map=qubit_map, connectivity=backend.platform.topology) + if get_backend_name() == "qibolab": # pragma: no cover + transpiler = Custom( + initial_map=qubit_map, connectivity=backend.platform.topology + ) transpiled_circuit, _ = transpiler(circuit) - - if noise_model is not None: # pragma: no cover - transpiled_circuit = noise_model.apply(transpiled_circuit) + + if noise_model is not None: # pragma: no cover + transpiled_circuit = noise_model.apply(transpiled_circuit) circuit_result = backend.execute_circuit(transpiled_circuit, nshots=nshots) return circuit_result From 79ef360ac7b3e97dbf113dba78c1e24c0d968ab3 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 12:25:45 +0400 Subject: [PATCH 21/59] remove resolve_global --- tests/test_backends_global.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 5d78cf3116..b99cee0ae9 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -110,20 +110,6 @@ def test_check_backend(backend): assert test.name == target.name assert test.__class__ == target.__class__ - -def test_resolve_global(): - from qibo.backends import _Global - - _Global._backend = None - _Global._transpiler = None - - assert _Global._backend is None - assert _Global._transpiler is None - _Global.resolve_global() - assert issubclass(_Global._backend.__class__, qibo.backends.Backend) - assert _Global._transpiler is not None - - def _star_connectivity(): Q = [i for i in range(5)] chip = nx.Graph() From b3614a4de088fd8de4f252f32dbb38f14cb68f9c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:26:15 +0000 Subject: [PATCH 22/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_backends_global.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index b99cee0ae9..6e1af4b72a 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -110,6 +110,7 @@ def test_check_backend(backend): assert test.name == target.name assert test.__class__ == target.__class__ + def _star_connectivity(): Q = [i for i in range(5)] chip = nx.Graph() From 69189f41151b2fe89eac4e35c089cf86e0006879 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 13:01:41 +0400 Subject: [PATCH 23/59] remove resolve_global --- src/qibo/models/error_mitigation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index d3af653d55..9dabb06a49 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -1176,10 +1176,10 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend transpiler = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) - transpiled_circuit, _ = transpiler(circuit) + circuit, _ = transpiler(circuit) if noise_model is not None: # pragma: no cover - transpiled_circuit = noise_model.apply(transpiled_circuit) + circuit = noise_model.apply(circuit) - circuit_result = backend.execute_circuit(transpiled_circuit, nshots=nshots) + circuit_result = backend.execute_circuit(circuit, nshots=nshots) return circuit_result From 0f68533097a20e8ad160530e7cf1e7649357c896 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 14:31:44 +0400 Subject: [PATCH 24/59] fix test_backends_global --- tests/test_backends_global.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 6e1af4b72a..8c65d7d0aa 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,3 +141,4 @@ def test_set_get_transpiler(): _Global.set_transpiler(transpiler) assert _Global.transpiler() == transpiler + _Global.set_transpiler(Passes(passes=[])) # reset the transpiler From b9b10d70a0d47eb0a238e90523c719eb15ffc0d2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:32:16 +0000 Subject: [PATCH 25/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_backends_global.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 8c65d7d0aa..bd3ec10a6e 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,4 +141,4 @@ def test_set_get_transpiler(): _Global.set_transpiler(transpiler) assert _Global.transpiler() == transpiler - _Global.set_transpiler(Passes(passes=[])) # reset the transpiler + _Global.set_transpiler(Passes(passes=[])) # reset the transpiler From 2dc6797753151cf2a97a5377f139d7227fe09587 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 15:50:36 +0400 Subject: [PATCH 26/59] add reset_global --- src/qibo/backends/__init__.py | 7 +++++++ tests/test_backends_clifford.py | 3 ++- tests/test_backends_global.py | 3 ++- tests/test_backends_qibotn.py | 3 +++ tests/test_backends_qulacs.py | 4 +++- tests/test_models_qcnn.py | 5 ++++- 6 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 2efa3c40bd..694fb6c402 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -130,6 +130,13 @@ def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend + @classmethod + def _reset_global(cls): + cls._backend = None + cls._transpiler = None + cls.backend() + cls.transpiler() + class QiboMatrices: def __init__(self, dtype="complex128"): diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 6e133a4cef..b93f055671 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -49,7 +49,8 @@ def test_global_backend(backend): _Global._backend.name if backend.name == "numpy" else _Global._backend.platform ) assert clifford_bkd.platform == target - set_backend("numpy") + + _Global._reset_global() THETAS_1Q = [ diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index bd3ec10a6e..92e92a7a17 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,4 +141,5 @@ def test_set_get_transpiler(): _Global.set_transpiler(transpiler) assert _Global.transpiler() == transpiler - _Global.set_transpiler(Passes(passes=[])) # reset the transpiler + + _Global._reset_global() \ No newline at end of file diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index ca7035016e..da1431053e 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -2,6 +2,7 @@ # import qibo from qibo import get_backend, get_threads, set_backend +from qibo.backends import _Global # Force quimb to use qibojit default number of threads. os.environ["NUMBA_NUM_THREADS"] = f"{get_threads()}" @@ -13,3 +14,5 @@ def test_backend_qibotn(): assert isinstance(get_backend(), QuimbBackend) set_backend("numpy") assert get_backend().name == "numpy" + + _Global._reset_global() \ No newline at end of file diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 9ef0d8a9bd..16250fb465 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates, get_backend -from qibo.backends import MetaBackend, NumpyBackend, set_backend +from qibo.backends import _Global, MetaBackend, NumpyBackend, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() @@ -41,3 +41,5 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") assert get_backend().name == "qulacs" + + _Global._reset_global() diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 45dfe9292e..29f277203b 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -4,6 +4,7 @@ import qibo from qibo import gates, set_backend +from qibo.backends import _Global from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -320,7 +321,7 @@ def test_two_qubit_ansatz(): def test_two_qubit_ansatz_training(): # test qibojit case (copy initial state as quick-fix for in-place update) - qibo.set_backend("qibojit") + set_backend("qibojit") c = Circuit(2) c.add(gates.H(0)) @@ -352,3 +353,5 @@ def test_two_qubit_ansatz_training(): predictions.append(1) labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) + + _Global._reset_global() From cf392101157bc00815670d435b7221e29e65a4d0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:51:09 +0000 Subject: [PATCH 27/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_backends_global.py | 4 ++-- tests/test_backends_qibotn.py | 2 +- tests/test_backends_qulacs.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 92e92a7a17..1d5d584ec3 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,5 +141,5 @@ def test_set_get_transpiler(): _Global.set_transpiler(transpiler) assert _Global.transpiler() == transpiler - - _Global._reset_global() \ No newline at end of file + + _Global._reset_global() diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index da1431053e..a40132f44e 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -15,4 +15,4 @@ def test_backend_qibotn(): set_backend("numpy") assert get_backend().name == "numpy" - _Global._reset_global() \ No newline at end of file + _Global._reset_global() diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 16250fb465..f8d17b0ccf 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates, get_backend -from qibo.backends import _Global, MetaBackend, NumpyBackend, set_backend +from qibo.backends import MetaBackend, NumpyBackend, _Global, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() From b7209ad2d1500dc8e29940440350dba612d01c35 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 7 Oct 2024 17:28:49 +0400 Subject: [PATCH 28/59] add reset global --- tests/test_models_error_mitigation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_models_error_mitigation.py b/tests/test_models_error_mitigation.py index 8e003993cf..67f1951a14 100644 --- a/tests/test_models_error_mitigation.py +++ b/tests/test_models_error_mitigation.py @@ -2,7 +2,7 @@ import pytest from qibo import Circuit, gates -from qibo.backends import construct_backend +from qibo.backends import _Global, construct_backend from qibo.hamiltonians import SymbolicHamiltonian from qibo.models.error_mitigation import ( CDR, @@ -51,7 +51,7 @@ def get_circuit(nqubits, nmeas=None): return c - +_Global._reset_global() backend = construct_backend("numpy") # # Generate random response matrices resp_matrix_1q = random_stochastic_matrix( @@ -341,6 +341,8 @@ def test_readout_mitigation(backend, nqubits, nmeas, method, ibu_iters): ], ) def test_ics(backend, nqubits, noise, full_output, readout): + print(backend) + print(backend.name) if backend.name == "tensorflow": import tensorflow as tf From c6391b612bd2989355fd068177d80125d1dce9e2 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 8 Oct 2024 12:13:11 +0400 Subject: [PATCH 29/59] fix error mitigation --- src/qibo/__init__.py | 1 + src/qibo/backends/__init__.py | 9 +++++++-- src/qibo/models/error_mitigation.py | 9 ++++----- tests/test_backends_clifford.py | 2 -- tests/test_backends_global.py | 3 +-- tests/test_backends_qibotn.py | 3 +-- tests/test_backends_qulacs.py | 3 +-- tests/test_models_error_mitigation.py | 3 --- tests/test_models_qcnn.py | 2 -- 9 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/qibo/__init__.py b/src/qibo/__init__.py index 44b46e0a45..38e0abc066 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -20,6 +20,7 @@ get_device, get_precision, get_threads, + set_transpiler, get_transpiler, get_transpiler_name, list_available_backends, diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 694fb6c402..ca194d00bf 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -68,6 +68,7 @@ def list_available(self) -> dict: class _Global: _backend = None _transpiler = None + # TODO: resolve circular import with qibo.transpiler.pipeline.Passes _dtypes = {"double": "complex128", "single": "complex64"} _default_order = [ @@ -84,6 +85,7 @@ def backend(cls): if cls._backend is not None: return cls._backend cls._backend = cls._create_backend() + log.info(f"Using {cls._backend} backend on {cls._backend.device}") return cls._backend @classmethod @@ -131,11 +133,14 @@ def set_transpiler(cls, transpiler): # TODO: check if transpiler is valid on the backend @classmethod - def _reset_global(cls): + def _clear_global(cls): + """Clear the global state of the backend and transpiler. Used for test files.""" + from qibo.transpiler.pipeline import Passes + cls._backend = None cls._transpiler = None cls.backend() - cls.transpiler() + cls._transpiler = Passes(passes=[]) class QiboMatrices: diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 9dabb06a49..735d42b7e3 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -11,7 +11,6 @@ from qibo.backends import ( _check_backend, _check_backend_and_local_state, - _Global, get_backend, get_backend_name, ) @@ -1171,14 +1170,14 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend from qibo.transpiler.placer import Custom # TODO: remove backend.platform.topology and pragma: no cover - backend = get_backend() - if get_backend_name() == "qibolab": # pragma: no cover + if backend is None: + backend = get_backend() + elif get_backend_name() == "qibolab": # pragma: no cover transpiler = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) circuit, _ = transpiler(circuit) - - if noise_model is not None: # pragma: no cover + elif noise_model is not None: # pragma: no cover circuit = noise_model.apply(circuit) circuit_result = backend.execute_circuit(circuit, nshots=nshots) diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index b93f055671..8ed626a747 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -50,8 +50,6 @@ def test_global_backend(backend): ) assert clifford_bkd.platform == target - _Global._reset_global() - THETAS_1Q = [ th + 2 * i * np.pi for i in range(2) for th in [0, np.pi / 2, np.pi, 3 * np.pi / 2] diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 1d5d584ec3..e1c5c2d70e 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,5 +141,4 @@ def test_set_get_transpiler(): _Global.set_transpiler(transpiler) assert _Global.transpiler() == transpiler - - _Global._reset_global() + _Global._clear_global() diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index a40132f44e..0d335d56cb 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -14,5 +14,4 @@ def test_backend_qibotn(): assert isinstance(get_backend(), QuimbBackend) set_backend("numpy") assert get_backend().name == "numpy" - - _Global._reset_global() + _Global._clear_global() diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index f8d17b0ccf..f97a4ac29d 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -41,5 +41,4 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") assert get_backend().name == "qulacs" - - _Global._reset_global() + _Global._clear_global() diff --git a/tests/test_models_error_mitigation.py b/tests/test_models_error_mitigation.py index 67f1951a14..e1ddbe3b37 100644 --- a/tests/test_models_error_mitigation.py +++ b/tests/test_models_error_mitigation.py @@ -51,7 +51,6 @@ def get_circuit(nqubits, nmeas=None): return c -_Global._reset_global() backend = construct_backend("numpy") # # Generate random response matrices resp_matrix_1q = random_stochastic_matrix( @@ -341,8 +340,6 @@ def test_readout_mitigation(backend, nqubits, nmeas, method, ibu_iters): ], ) def test_ics(backend, nqubits, noise, full_output, readout): - print(backend) - print(backend.name) if backend.name == "tensorflow": import tensorflow as tf diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 29f277203b..9758e005fc 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -353,5 +353,3 @@ def test_two_qubit_ansatz_training(): predictions.append(1) labels = np.array([[1], [-1], [1]]) test_qcnn.Accuracy(labels, predictions) - - _Global._reset_global() From 23f6054103e476c04c7413d9994975539770b80e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 08:13:45 +0000 Subject: [PATCH 30/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/__init__.py | 2 +- tests/test_models_error_mitigation.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qibo/__init__.py b/src/qibo/__init__.py index 38e0abc066..9d3682a385 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -20,7 +20,6 @@ get_device, get_precision, get_threads, - set_transpiler, get_transpiler, get_transpiler_name, list_available_backends, @@ -29,6 +28,7 @@ set_device, set_precision, set_threads, + set_transpiler, ) from qibo.config import ( get_batch_size, diff --git a/tests/test_models_error_mitigation.py b/tests/test_models_error_mitigation.py index e1ddbe3b37..ca74e7e882 100644 --- a/tests/test_models_error_mitigation.py +++ b/tests/test_models_error_mitigation.py @@ -51,6 +51,7 @@ def get_circuit(nqubits, nmeas=None): return c + backend = construct_backend("numpy") # # Generate random response matrices resp_matrix_1q = random_stochastic_matrix( From a63fbe99f651ca8909a293d9493475a311e1bc24 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 8 Oct 2024 12:48:01 +0400 Subject: [PATCH 31/59] update docs (replace 'GlobalBackend') --- doc/source/api-reference/qibo.rst | 2 +- src/qibo/gates/abstract.py | 2 +- src/qibo/gates/channels.py | 6 +- src/qibo/gates/special.py | 2 +- src/qibo/hamiltonians/hamiltonians.py | 6 +- src/qibo/hamiltonians/models.py | 10 +-- src/qibo/models/error_mitigation.py | 16 ++-- src/qibo/noise_model.py | 2 +- src/qibo/quantum_info/basis.py | 6 +- src/qibo/quantum_info/clifford.py | 4 +- src/qibo/quantum_info/entanglement.py | 10 +-- src/qibo/quantum_info/entropies.py | 28 +++---- src/qibo/quantum_info/linalg_operations.py | 6 +- src/qibo/quantum_info/metrics.py | 28 +++---- src/qibo/quantum_info/quantum_networks.py | 16 ++-- src/qibo/quantum_info/random_ensembles.py | 24 +++--- .../superoperator_transformations.py | 76 +++++++++---------- src/qibo/quantum_info/utils.py | 14 ++-- src/qibo/result.py | 6 +- src/qibo/tomography/gate_set_tomography.py | 4 +- 20 files changed, 134 insertions(+), 134 deletions(-) diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index e21f0cc19f..1ea0432c90 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -2631,7 +2631,7 @@ As for the other backends, the Clifford backend can be set with import qibo qibo.set_backend("clifford", platform="numpy") -by specifying the engine used for calculation, if not provided the current :class:`qibo.backends.GlobalBackend` is used +by specifying the engine used for calculation, if not provided the current backend is used .. testcode:: python diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 3429cb3c8a..db5c4e946e 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -397,7 +397,7 @@ def matrix(self, backend=None): Args: backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Matrix representation of gate. diff --git a/src/qibo/gates/channels.py b/src/qibo/gates/channels.py index be43678318..12cf732620 100644 --- a/src/qibo/gates/channels.py +++ b/src/qibo/gates/channels.py @@ -65,7 +65,7 @@ def to_choi(self, nqubits: Optional[int] = None, order: str = "row", backend=Non vectorization is done block-wise. Defaut is ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, - it uses :class:`qibo.backends.GlobalBackend`. + it uses the current backend. Defaults to ``None``. Returns: @@ -121,7 +121,7 @@ def to_liouville(self, nqubits: int = None, order: str = "row", backend=None): it raises ``NotImplementedError``. Defaut is ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, - it uses :class:`qibo.backends.GlobalBackend`. + it uses the current backend. Defaults to ``None``. Returns: @@ -160,7 +160,7 @@ def to_pauli_liouville( Pauli elements in the basis. Default is "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. + the current backend. Defaults to ``None``. Returns: diff --git a/src/qibo/gates/special.py b/src/qibo/gates/special.py index 3824f3672c..b4d6d48dcf 100644 --- a/src/qibo/gates/special.py +++ b/src/qibo/gates/special.py @@ -99,7 +99,7 @@ def matrix(self, backend=None): """Returns matrix representation of special gate. Args: - backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: ndarray: Matrix representation of special gate. diff --git a/src/qibo/hamiltonians/hamiltonians.py b/src/qibo/hamiltonians/hamiltonians.py index 75fd10c7ba..015de265d7 100644 --- a/src/qibo/hamiltonians/hamiltonians.py +++ b/src/qibo/hamiltonians/hamiltonians.py @@ -22,7 +22,7 @@ class Hamiltonian(AbstractHamiltonian): Sparse matrices based on ``scipy.sparse`` for ``numpy`` / ``qibojit`` backends (or on ``tf.sparse`` for the ``tensorflow`` backend) are also supported. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ @@ -80,7 +80,7 @@ def from_symbolic(cls, symbolic_hamiltonian, symbol_map, backend=None): symbol_map (dict): Dictionary that maps each symbol that appears in the Hamiltonian to a pair ``(target, matrix)``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -315,7 +315,7 @@ class SymbolicHamiltonian(AbstractHamiltonian): to the symbolic Hamiltonian, such as the parameters in the :meth:`qibo.hamiltonians.models.MaxCut` Hamiltonian. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ diff --git a/src/qibo/hamiltonians/models.py b/src/qibo/hamiltonians/models.py index f6413b9848..a268c26da2 100644 --- a/src/qibo/hamiltonians/models.py +++ b/src/qibo/hamiltonians/models.py @@ -45,7 +45,7 @@ def XXZ(nqubits, delta=0.5, dense: bool = True, backend=None): a :class:`qibo.core.hamiltonians.SymbolicHamiltonian`. Defaults to ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Example: @@ -102,7 +102,7 @@ def X(nqubits, dense: bool = True, backend=None): a :class:`qibo.core.hamiltonians.SymbolicHamiltonian`. Defaults to ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ return _OneBodyPauli(nqubits, matrices.X, dense, backend=backend) @@ -120,7 +120,7 @@ def Y(nqubits, dense: bool = True, backend=None): :class:`qibo.core.hamiltonians.Hamiltonian`, otherwise it creates a :class:`qibo.core.hamiltonians.SymbolicHamiltonian`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ return _OneBodyPauli(nqubits, matrices.Y, dense, backend=backend) @@ -138,7 +138,7 @@ def Z(nqubits, dense: bool = True, backend=None): :class:`qibo.core.hamiltonians.Hamiltonian`, otherwise it creates a :class:`qibo.core.hamiltonians.SymbolicHamiltonian`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ return _OneBodyPauli(nqubits, matrices.Z, dense, backend=backend) @@ -190,7 +190,7 @@ def MaxCut(nqubits, dense: bool = True, backend=None): :class:`qibo.core.hamiltonians.Hamiltonian`, otherwise it creates a :class:`qibo.core.hamiltonians.SymbolicHamiltonian`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ import sympy as sp diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 735d42b7e3..82e6b7badb 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -178,7 +178,7 @@ def ZNE( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -242,7 +242,7 @@ def sample_training_circuit_cdr( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -392,7 +392,7 @@ def CDR( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -507,7 +507,7 @@ def vnCDR( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -635,7 +635,7 @@ def get_response_matrix( `qibo.noise.ReadoutError`. nshots (int, optional): number of shots. Defaults to :math:`10000`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -739,7 +739,7 @@ def apply_randomized_readout_mitigation( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -881,7 +881,7 @@ def sample_clifford_training_circuit( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -945,7 +945,7 @@ def error_sensitive_circuit(circuit, observable, seed=None, backend=None): numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. if ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. if ``None``, it uses the current backend. Defaults to ``None``. Returns: diff --git a/src/qibo/noise_model.py b/src/qibo/noise_model.py index 79ae249be0..3dee0432ca 100644 --- a/src/qibo/noise_model.py +++ b/src/qibo/noise_model.py @@ -314,7 +314,7 @@ def fit( vol_tol (float): Stop the optimization process when the volume of the hyperrectangle that contains the lowest function value becomes smaller than vol_tol. len_tol (float): When "locally_biased" is set to True, stop the optimization process if the length of the longest side of the hyperrectangle containing the lowest function value, normalized by the maximal side length, is less than half of "len_tol". If "locally_biased" is False, terminate the optimization process when half of the normalized diagonal of the hyperrectangle containing the lowest function value is smaller than "len_tol". callback (callable): This function takes one parameter, `xk`, which represents the current best function value found by the algorithm. - backend: you can specify your backend. If None qibo.backends.GlobalBackend is used. + backend: you can specify your backend. If None, the current backend is used. """ from scipy.optimize import Bounds, direct diff --git a/src/qibo/quantum_info/basis.py b/src/qibo/quantum_info/basis.py index e3bf042a60..3db349d8ee 100644 --- a/src/qibo/quantum_info/basis.py +++ b/src/qibo/quantum_info/basis.py @@ -39,7 +39,7 @@ def pauli_basis( Pauli elements. Defaults to ``"IXYZ"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray or tuple: all Pauli matrices forming the basis. If ``sparse=True`` @@ -180,7 +180,7 @@ def comp_basis_to_pauli( Pauli elements. Defaults to ``"IXYZ"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray or tuple: Unitary matrix :math:`U`. If ``sparse=True``, @@ -255,7 +255,7 @@ def pauli_to_comp_basis( Pauli elements. Defaults to ``"IXYZ"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray or tuple: Unitary matrix :math:`U`. If ``sparse=True``, diff --git a/src/qibo/quantum_info/clifford.py b/src/qibo/quantum_info/clifford.py index e8decd7444..f636991a2f 100644 --- a/src/qibo/quantum_info/clifford.py +++ b/src/qibo/quantum_info/clifford.py @@ -34,7 +34,7 @@ class Clifford: :class:`qibo.backends.CliffordBackend`. It accepts ``"numpy"``, ``"numba"``, ``"cupy"``, and ``"stim"`` (see `stim `_). If ``None``, defaults to the corresponding engine - from :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + from the current backend. Defaults to ``None``. """ symplectic_matrix: np.ndarray = field(init=False) @@ -92,7 +92,7 @@ def from_circuit( :class:`qibo.backends.CliffordBackend`. It accepts ``"numpy"``, ``"numba"``, ``"cupy"``, and ``"stim"`` (see `stim `_). If ``None``, defaults to the corresponding engine - from :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + from the current backend. Defaults to ``None``. Returns: (:class:`qibo.quantum_info.clifford.Clifford`): Object storing the result of the circuit execution. diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index 23c2f7d3f2..d3142dcc5e 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -24,7 +24,7 @@ def concurrence(state, bipartition, check_purity: bool = True, backend=None): check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, it assumes ``state`` is pure . Defaults to ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -94,7 +94,7 @@ def entanglement_of_formation( check_purity (bool, optional): if ``True``, checks if ``state`` is pure. If ``False``, it assumes ``state`` is pure . Default: ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. @@ -142,7 +142,7 @@ def entanglement_fidelity( :math:`\\rho_{f}` is Hermitian. If ``False``, it assumes it is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -203,7 +203,7 @@ def meyer_wallach_entanglement(circuit, backend=None): Args: circuit (:class:`qibo.models.Circuit`): Parametrized circuit. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -249,7 +249,7 @@ def entangling_capability(circuit, samples: int, seed=None, backend=None): numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: diff --git a/src/qibo/quantum_info/entropies.py b/src/qibo/quantum_info/entropies.py index 204884c6ef..25bb34db13 100644 --- a/src/qibo/quantum_info/entropies.py +++ b/src/qibo/quantum_info/entropies.py @@ -24,7 +24,7 @@ def shannon_entropy(prob_dist, base: float = 2, backend=None): prob_dist (ndarray or list): a probability array :math:`\\mathbf{p}`. base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -89,7 +89,7 @@ def classical_relative_entropy(prob_dist_p, prob_dist_q, base: float = 2, backen base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Classical relative entropy between :math:`\\mathbf{p}` and :math:`\\mathbf{q}`. @@ -162,7 +162,7 @@ def classical_mutual_information( prob_dist_q (ndarray): marginal probability distribution :math:`q(y)`. base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -206,7 +206,7 @@ def classical_renyi_entropy( base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Classical Rényi entropy :math:`H_{\\alpha}`. @@ -295,7 +295,7 @@ def classical_relative_renyi_entropy( base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Classical relative Rényi entropy :math:`H_{\\alpha}(\\mathbf{p} \\, \\| \\, \\mathbf{q})`. @@ -380,7 +380,7 @@ def classical_tsallis_entropy(prob_dist, alpha: float, base: float = 2, backend= Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Classical Tsallis entropy :math:`S_{\\alpha}(\\mathbf{p})`. @@ -457,7 +457,7 @@ def classical_relative_tsallis_entropy( base (float): the base of the log used when :math:`\\alpha = 1`. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Tsallis relative entropy :math:`D_{\\alpha}^{\\text{ts}}`. @@ -506,7 +506,7 @@ def von_neumann_entropy( If ``False``, returns only ``entropy``. Default is ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: The von-Neumann entropy :math:`S` of ``state`` :math:`\\rho`. @@ -580,7 +580,7 @@ def relative_von_neumann_entropy( Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Relative (von-Neumann) entropy :math:`S(\\rho \\, \\| \\, \\sigma)`. @@ -678,7 +678,7 @@ def mutual_information( If ``False``, it assumes ``state`` is Hermitian . Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Mutual information :math:`I(\\rho)` of ``state`` :math:`\\rho`. @@ -728,7 +728,7 @@ def renyi_entropy(state, alpha: Union[float, int], base: float = 2, backend=None base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Rényi entropy :math:`H_{\\alpha}`. @@ -812,7 +812,7 @@ def relative_renyi_entropy( base (float): the base of the log. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Relative Rényi entropy :math:`H_{\\alpha}(\\rho \\, \\| \\, \\sigma)`. @@ -904,7 +904,7 @@ def tsallis_entropy(state, alpha: float, base: float = 2, backend=None): Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Tsallis entropy :math:`S_{\\alpha}(\\rho)`. @@ -970,7 +970,7 @@ def entanglement_entropy( If ``False``, returns only ``entropy``. Default is ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Entanglement entropy :math:`S` of ``state`` :math:`\\rho`. diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 6fc48e6e74..bd9cd9b1e8 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -107,7 +107,7 @@ def partial_trace(state, traced_qubits: Union[List[int], Tuple[int]], backend=No traced_qubits (Union[List[int], Tuple[int]]): indices of qubits to be traced out. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Density matrix of the remaining qubit(s). @@ -188,7 +188,7 @@ def matrix_exponentiation( Must be used together with ``eigenvectors``. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: matrix exponential of :math:`-i \\, \\theta \\, H`. @@ -206,7 +206,7 @@ def matrix_power(matrix, power: Union[float, int], backend=None): power (float or int): power to raise ``matrix`` to. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: matrix power :math:`A^{\\alpha}`. diff --git a/src/qibo/quantum_info/metrics.py b/src/qibo/quantum_info/metrics.py index b40789831a..2b56fc7ef8 100644 --- a/src/qibo/quantum_info/metrics.py +++ b/src/qibo/quantum_info/metrics.py @@ -74,7 +74,7 @@ def trace_distance(state, target, check_hermitian: bool = False, backend=None): it assumes the difference is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -145,7 +145,7 @@ def hilbert_schmidt_distance(state, target, backend=None): state (ndarray): statevector or density matrix. target (ndarray): statevector or density matrix. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -196,7 +196,7 @@ def fidelity(state, target, check_hermitian: bool = False, backend=None): check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -302,7 +302,7 @@ def infidelity(state, target, check_hermitian: bool = False, backend=None): check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -327,7 +327,7 @@ def bures_angle(state, target, check_hermitian: bool = False, backend=None): check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -358,7 +358,7 @@ def bures_distance(state, target, check_hermitian: bool = False, backend=None): check_hermitian (bool, optional): if ``True``, checks if ``state`` is Hermitian. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -388,7 +388,7 @@ def process_fidelity(channel, target=None, check_unitary: bool = False, backend= check_unitary (bool, optional): if ``True``, checks if one of the input channels is unitary. Default: ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -459,7 +459,7 @@ def process_infidelity(channel, target=None, check_unitary: bool = False, backen check_unitary (bool, optional): if ``True``, checks if one of the input channels is unitary. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. @@ -496,7 +496,7 @@ def average_gate_fidelity( check_unitary (bool, optional): if ``True``, checks if one of the input channels is unitary. Default: ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -531,7 +531,7 @@ def gate_error(channel, target=None, check_unitary: bool = False, backend=None): check_unitary (bool, optional): if ``True``, checks if one of the input channels is unitary. Default: ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -579,7 +579,7 @@ def diamond_norm(channel, target=None, backend=None, **kwargs): # pragma: no co target (ndarray, optional): row-vectorized Choi representation of a target quantum channel. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. kwargs: optional arguments to pass to CVXPY solver. For more information, please visit `CVXPY's API documentation @@ -701,7 +701,7 @@ def expressibility( For specifications, see :meth:`qibo.backends.abstract.calculate_norm`. Defaults to :math:`2`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -765,7 +765,7 @@ def frame_potential( power_t (int): power that defines the :math:`t`-design. samples (int): number of samples to estimate the integral. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -818,7 +818,7 @@ def _check_hermitian(matrix, backend=None): Args: matrix: input array. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: diff --git a/src/qibo/quantum_info/quantum_networks.py b/src/qibo/quantum_info/quantum_networks.py index 691f40a515..0976094978 100644 --- a/src/qibo/quantum_info/quantum_networks.py +++ b/src/qibo/quantum_info/quantum_networks.py @@ -38,7 +38,7 @@ class QuantumNetwork: pure (bool, optional): ``True`` when ``tensor`` is a "pure" representation (e.g. a pure state, a unitary operator, etc.), ``False`` otherwise. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. """ @@ -144,7 +144,7 @@ def from_operator( pure (bool, optional): ``True`` when ``arr`` is a "pure" representation (e.g. a pure state, a unitary operator, etc.), ``False`` otherwise. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. Returns: @@ -662,7 +662,7 @@ def full(self, update: bool = False, backend=None): update (bool, optional): If ``True``, updates the internal representation of the network to the full tensor. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. Returns: @@ -713,7 +713,7 @@ class QuantumComb(QuantumNetwork): pure (bool, optional): ``True`` when ``tensor`` is a "pure" representation (e.g. a pure state, a unitary operator, etc.), ``False`` otherwise. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. """ @@ -835,7 +835,7 @@ class QuantumChannel(QuantumComb): pure (bool, optional): ``True`` when ``tensor`` is a "pure" representation (e.g. a pure state, a unitary operator, etc.), ``False`` otherwise. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. """ @@ -1006,7 +1006,7 @@ def link_product( operands (:class:`qibo.quantum_info.quantum_networks.QuantumNetwork`): Quantum networks to be contracted. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. surpress_warning (bool, optional): If ``True``, surpresses the warning regarding if the same index connects two input or two output @@ -1090,7 +1090,7 @@ class IdentityChannel(QuantumChannel): Args: dim (int): Dimension of the Identity operator. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. """ @@ -1107,7 +1107,7 @@ class TraceOperation(QuantumNetwork): Args: dim (int): Dimension of the Trace operator. backend (:class:`qibo.backends.abstract.Backend`, optional): Backend to be used in - calculations. If ``None``, defaults to :class:`qibo.backends.GlobalBackend`. + calculations. If ``None``, defaults to the current backend. Defaults to ``None``. """ diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 59efb49b79..df2810693c 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -54,7 +54,7 @@ def uniform_sampling_U3(ngates: int, seed=None, backend=None): numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -110,7 +110,7 @@ def random_gaussian_matrix( numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Default: ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -166,7 +166,7 @@ def random_hermitian( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -208,7 +208,7 @@ def random_unitary(dims: int, measure: Optional[str] = None, seed=None, backend= random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -310,7 +310,7 @@ def random_quantum_channel( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -415,7 +415,7 @@ def random_statevector(dims: int, seed=None, backend=None): random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -492,7 +492,7 @@ def random_density_matrix( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -604,7 +604,7 @@ def random_clifford( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -756,7 +756,7 @@ def random_pauli( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -877,7 +877,7 @@ def random_pauli_hamiltonian( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -984,7 +984,7 @@ def random_stochastic_matrix( random numbers or a fixed seed to initialize a generator. If ``None``, initializes a statevectorgenerator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -1193,7 +1193,7 @@ def _super_op_from_bcsz_measure(dims: int, rank: int, order: str, seed, backend) random numbers or a fixed seed to initialize a generator. If ``None``, initializes a generator with a random seed. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. """ nqubits = int(np.log2(dims)) diff --git a/src/qibo/quantum_info/superoperator_transformations.py b/src/qibo/quantum_info/superoperator_transformations.py index 158dd73ac4..a9a174a6a8 100644 --- a/src/qibo/quantum_info/superoperator_transformations.py +++ b/src/qibo/quantum_info/superoperator_transformations.py @@ -34,7 +34,7 @@ def vectorization(state, order: str = "row", backend=None): performed. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Liouville representation of ``state``. @@ -104,7 +104,7 @@ def unvectorization(state, order: str = "row", backend=None): performed. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Density matrix of ``state``. @@ -164,7 +164,7 @@ def to_choi(channel, order: str = "row", backend=None): performed. Default is ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: quantum channel in its Choi representation. @@ -190,7 +190,7 @@ def to_liouville(channel, order: str = "row", backend=None): performed. Default is ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: quantum channel in its Liouville representation. @@ -227,7 +227,7 @@ def to_pauli_liouville( Pauli elements. Default is "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: quantum channel in its Pauli-Liouville representation. @@ -271,7 +271,7 @@ def to_chi( Pauli elements. Default is "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: quantum channel in its :math:`\\chi`-representation. @@ -317,7 +317,7 @@ def choi_to_liouville(choi_super_op, order: str = "row", backend=None): respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Liouville representation of quantum channel. @@ -348,7 +348,7 @@ def choi_to_pauli( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: superoperator in the Pauli-Liouville representation. @@ -421,7 +421,7 @@ def choi_to_kraus( Defaults to ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: tuple(ndarray, ndarray): The set @@ -545,7 +545,7 @@ def choi_to_chi( single-qubit Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Chi-matrix representation of the quantum channel. """ @@ -601,7 +601,7 @@ def choi_to_stinespring( environment in its ground state. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of quantum channel. @@ -658,7 +658,7 @@ def kraus_to_choi(kraus_ops, order: str = "row", backend=None): respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of the Kraus channel. @@ -704,7 +704,7 @@ def kraus_to_liouville(kraus_ops, order: str = "row", backend=None): respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Liouville representation of quantum channel. @@ -740,7 +740,7 @@ def kraus_to_pauli( single-qubit Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: superoperator in the Pauli-Liouville representation. @@ -786,7 +786,7 @@ def kraus_to_chi( Pauli elements in the Pauli basis. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Chi-matrix representation of the Kraus channel. @@ -850,7 +850,7 @@ def kraus_to_stinespring( environment in its ground state. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Stinespring representation (restricted unitary) of the Kraus channel. @@ -934,7 +934,7 @@ def liouville_to_choi(super_op, order: str = "row", backend=None): respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of quantum channel. @@ -965,7 +965,7 @@ def liouville_to_pauli( Pauli elements in the basis. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: superoperator in the Pauli-Liouville representation. @@ -1022,7 +1022,7 @@ def liouville_to_kraus( respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: (ndarray, ndarray): Kraus operators of quantum channel and their respective coefficients. @@ -1065,7 +1065,7 @@ def liouville_to_chi( Pauli elements in the basis. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Chi-matrix representation of quantum channel. @@ -1124,7 +1124,7 @@ def liouville_to_stinespring( environment in its ground state. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Stinespring representation of quantum channel. @@ -1166,7 +1166,7 @@ def pauli_to_liouville( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: superoperator in the Liouville representation. @@ -1218,7 +1218,7 @@ def pauli_to_choi( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of the superoperator. @@ -1260,7 +1260,7 @@ def pauli_to_kraus( ``qibo.config.PRECISION_TOL=1e-8``. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: (ndarray, ndarray): Kraus operators and their coefficients. @@ -1295,7 +1295,7 @@ def pauli_to_chi( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Chi-matrix representation of the quantum channel. @@ -1355,7 +1355,7 @@ def pauli_to_stinespring( environment in its ground state. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Stinestring representation of quantum channel. @@ -1410,7 +1410,7 @@ def chi_to_choi( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of quantum channel. @@ -1455,7 +1455,7 @@ def chi_to_liouville( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Liouville representation of quantum channel. @@ -1501,7 +1501,7 @@ def chi_to_pauli( Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: superoperator in the Pauli-Liouville representation. @@ -1564,7 +1564,7 @@ def chi_to_kraus( Defaults to ``True``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: (ndarray, ndarray): Kraus operators and their coefficients. @@ -1642,7 +1642,7 @@ def chi_to_stinespring( environment in its ground state. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Stinespring representation of quantum channel. @@ -1698,7 +1698,7 @@ def stinespring_to_choi( respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi representation of quantum channel. @@ -1754,7 +1754,7 @@ def stinespring_to_liouville( respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Liouville representation of quantum channel. @@ -1814,7 +1814,7 @@ def stinespring_to_pauli( single-qubit Pauli elements. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Pauli-Liouville representation of quantum channel. @@ -1875,7 +1875,7 @@ def stinespring_to_kraus( nqubits (int, optional): number of qubits in the system. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Kraus operators. @@ -1972,7 +1972,7 @@ def stinespring_to_chi( Pauli elements in the Pauli basis. Defaults to "IXYZ". backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: :math:`\\chi`-representation of quantum channel. @@ -2027,7 +2027,7 @@ def kraus_to_unitaries( defaults to ``1e-7``. Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: (ndarray, ndarray): Unitary operators and their associated probabilities. @@ -2131,7 +2131,7 @@ def _reshuffling(super_op, order: str = "row", backend=None): respect to system-wise vectorization. Defaults to ``"row"``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Choi (Liouville) representation of the quantum channel. diff --git a/src/qibo/quantum_info/utils.py b/src/qibo/quantum_info/utils.py index 845b6ac153..273e9af9dc 100644 --- a/src/qibo/quantum_info/utils.py +++ b/src/qibo/quantum_info/utils.py @@ -136,7 +136,7 @@ def hadamard_transform(array, implementation: str = "fast", backend=None): for matrices. If ``"fast"``, computational complexity is :math:`\\mathcal{O}(n \\, 2^{n})` in both cases. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: @@ -214,7 +214,7 @@ def hellinger_distance(prob_dist_p, prob_dist_q, validate: bool = False, backend probability distributions. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: (float): Hellinger distance :math:`H(p, q)`. @@ -277,7 +277,7 @@ def hellinger_fidelity(prob_dist_p, prob_dist_q, validate: bool = False, backend probability distributions. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Hellinger fidelity. @@ -314,7 +314,7 @@ def hellinger_shot_error( probability distributions. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Hellinger fidelity error. @@ -359,7 +359,7 @@ def total_variation_distance( probability distributions. Defaults to ``False``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: float: Total variation distance measure. @@ -411,7 +411,7 @@ def haar_integral( Defaults to ``None``. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: array: Estimation of the Haar integral. @@ -500,7 +500,7 @@ def pqc_integral(circuit, power_t: int, samples: int, backend=None): samples (int): number of samples to estimate the integral. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: Estimation of the integral. diff --git a/src/qibo/result.py b/src/qibo/result.py index e92707c3b2..b2cdf2fe9f 100644 --- a/src/qibo/result.py +++ b/src/qibo/result.py @@ -27,7 +27,7 @@ class QuantumState: Args: state (np.ndarray): Input quantum state as np.ndarray. - backend (qibo.backends.AbstractBackend): Backend used for the calculations. If not provided the :class:`qibo.backends.GlobalBackend` is going to be used. + backend (qibo.backends.AbstractBackend): Backend used for the calculations. If not provided, the current backend is going to be used. """ def __init__(self, state, backend=None): @@ -158,7 +158,7 @@ class MeasurementOutcomes: Args: measurements (:class:`qibo.gates.M`): Measurement gates. backend (:class:`qibo.backends.AbstractBackend`): Backend used for the calculations. - If ``None``, then :class:`qibo.backends.GlobalBackend` is used. Defaults to ``None``. + If ``None``, then the current backend is used. Defaults to ``None``. probabilities (np.ndarray): Use these probabilities to generate samples and frequencies. samples (np.darray): Use these samples to generate probabilities and frequencies. nshots (int): Number of shots used for samples, probabilities and frequencies generation. @@ -479,7 +479,7 @@ class CircuitResult(QuantumState, MeasurementOutcomes): Args: final_state (np.ndarray): Input quantum state as np.ndarray. measurements (qibo.gates.M): The measurement gates containing the measurements. - backend (qibo.backends.AbstractBackend): Backend used for the calculations. If not provided the :class:`qibo.backends.GlobalBackend` is going to be used. + backend (qibo.backends.AbstractBackend): Backend used for the calculations. If not provided, then the current backend is going to be used. probabilities (np.ndarray): Use these probabilities to generate samples and frequencies. samples (np.darray): Use these samples to generate probabilities and frequencies. nshots (int): Number of shots used for samples, probabilities and frequencies generation. diff --git a/src/qibo/tomography/gate_set_tomography.py b/src/qibo/tomography/gate_set_tomography.py index 127350953e..d3b4286f32 100644 --- a/src/qibo/tomography/gate_set_tomography.py +++ b/src/qibo/tomography/gate_set_tomography.py @@ -168,7 +168,7 @@ def _gate_tomography( noisy computations. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray: matrix approximating the input gate. @@ -251,7 +251,7 @@ def GST( backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: From 15be594844a221ddc9cf9820a8be3cc038adb3d5 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 8 Oct 2024 14:00:59 +0400 Subject: [PATCH 32/59] coverage --- src/qibo/backends/__init__.py | 4 ++-- src/qibo/models/error_mitigation.py | 6 +++--- tests/test_backends_global.py | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index ca194d00bf..1e63e13633 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -91,7 +91,7 @@ def backend(cls): @classmethod def _create_backend(cls): backend_env = os.environ.get("QIBO_BACKEND") - if backend_env: + if backend_env: # pragma: no cover # Create backend specified by user platform = os.environ.get("QIBO_PLATFORM") backend = construct_backend(backend_env, platform=platform) @@ -104,7 +104,7 @@ def _create_backend(cls): except (ModuleNotFoundError, ImportError): pass - if backend is None: + if backend is None: # pragma: no cover raise_error(RuntimeError, "No backends available.") return backend diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 82e6b7badb..69eb69a6ea 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -1170,14 +1170,14 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend from qibo.transpiler.placer import Custom # TODO: remove backend.platform.topology and pragma: no cover - if backend is None: + if backend is None: # pragma: no cover backend = get_backend() - elif get_backend_name() == "qibolab": # pragma: no cover + elif get_backend_name() == "qibolab": # pragma: no cover transpiler = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) circuit, _ = transpiler(circuit) - elif noise_model is not None: # pragma: no cover + elif noise_model is not None: # pragma: no cover circuit = noise_model.apply(circuit) circuit_result = backend.execute_circuit(circuit, nshots=nshots) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index e1c5c2d70e..cd6a507185 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -139,6 +139,7 @@ def test_set_get_transpiler(): ], ) - _Global.set_transpiler(transpiler) - assert _Global.transpiler() == transpiler + qibo.set_transpiler(transpiler) + assert qibo.get_transpiler == transpiler + assert qibo.get_transpiler_name() == str(transpiler) _Global._clear_global() From 6a1c9216837551ec7393e311622f44ad3489d9a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:02:37 +0000 Subject: [PATCH 33/59] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/backends/__init__.py | 4 ++-- src/qibo/models/error_mitigation.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 1e63e13633..1b40ada945 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -91,7 +91,7 @@ def backend(cls): @classmethod def _create_backend(cls): backend_env = os.environ.get("QIBO_BACKEND") - if backend_env: # pragma: no cover + if backend_env: # pragma: no cover # Create backend specified by user platform = os.environ.get("QIBO_PLATFORM") backend = construct_backend(backend_env, platform=platform) @@ -104,7 +104,7 @@ def _create_backend(cls): except (ModuleNotFoundError, ImportError): pass - if backend is None: # pragma: no cover + if backend is None: # pragma: no cover raise_error(RuntimeError, "No backends available.") return backend diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 69eb69a6ea..e0fdd78dc3 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -1170,14 +1170,14 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend from qibo.transpiler.placer import Custom # TODO: remove backend.platform.topology and pragma: no cover - if backend is None: # pragma: no cover + if backend is None: # pragma: no cover backend = get_backend() - elif get_backend_name() == "qibolab": # pragma: no cover + elif get_backend_name() == "qibolab": # pragma: no cover transpiler = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) circuit, _ = transpiler(circuit) - elif noise_model is not None: # pragma: no cover + elif noise_model is not None: # pragma: no cover circuit = noise_model.apply(circuit) circuit_result = backend.execute_circuit(circuit, nshots=nshots) From d4670f645cbd2569f47e2c164001583e80d8712b Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 8 Oct 2024 14:27:12 +0400 Subject: [PATCH 34/59] fix test_set_get_transpiler --- tests/test_backends_global.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index cd6a507185..d5c2aac1b5 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -140,6 +140,6 @@ def test_set_get_transpiler(): ) qibo.set_transpiler(transpiler) - assert qibo.get_transpiler == transpiler + assert qibo.get_transpiler() == transpiler assert qibo.get_transpiler_name() == str(transpiler) _Global._clear_global() From dcd318a99f599f896f79f6ca1e30cae360176536 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 9 Oct 2024 09:42:29 +0400 Subject: [PATCH 35/59] add clear in conftest.py --- src/qibo/backends/__init__.py | 10 ---------- tests/conftest.py | 14 +++++++++++++- tests/test_backends_global.py | 4 +--- tests/test_backends_qibotn.py | 4 +--- tests/test_backends_qulacs.py | 5 ++--- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 1b40ada945..a62b0d4003 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -132,16 +132,6 @@ def set_transpiler(cls, transpiler): cls._transpiler = transpiler # TODO: check if transpiler is valid on the backend - @classmethod - def _clear_global(cls): - """Clear the global state of the backend and transpiler. Used for test files.""" - from qibo.transpiler.pipeline import Passes - - cls._backend = None - cls._transpiler = None - cls.backend() - cls._transpiler = Passes(passes=[]) - class QiboMatrices: def __init__(self, dtype="complex128"): diff --git a/tests/conftest.py b/tests/conftest.py index 538ed7a1e5..6d34b5c612 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,7 +7,7 @@ import pytest -from qibo.backends import construct_backend +from qibo.backends import _Global, construct_backend # backends to be tested BACKENDS = [ @@ -74,6 +74,18 @@ def backend(backend_name): yield get_backend(backend_name) +@pytest.fixture +def clear(): + yield + + from qibo.transpiler.pipeline import Passes + + _Global._backend = None + _Global._transpiler = None + _Global.backend() + _Global._transpiler = Passes(passes=[]) + + def pytest_generate_tests(metafunc): module_name = metafunc.module.__name__ diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index d5c2aac1b5..86c210f90f 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -120,8 +120,7 @@ def _star_connectivity(): return chip -def test_set_get_transpiler(): - from qibo.backends import _Global +def test_set_get_transpiler(clear): from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Random @@ -142,4 +141,3 @@ def test_set_get_transpiler(): qibo.set_transpiler(transpiler) assert qibo.get_transpiler() == transpiler assert qibo.get_transpiler_name() == str(transpiler) - _Global._clear_global() diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index 0d335d56cb..e10e25d951 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -2,16 +2,14 @@ # import qibo from qibo import get_backend, get_threads, set_backend -from qibo.backends import _Global # Force quimb to use qibojit default number of threads. os.environ["NUMBA_NUM_THREADS"] = f"{get_threads()}" from qibotn.backends.quimb import QuimbBackend -def test_backend_qibotn(): +def test_backend_qibotn(clear): set_backend(backend="qibotn", platform="qutensornet", runcard=None) assert isinstance(get_backend(), QuimbBackend) set_backend("numpy") assert get_backend().name == "numpy" - _Global._clear_global() diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index f97a4ac29d..34beb8c178 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -4,7 +4,7 @@ import pytest from qibo import Circuit, gates, get_backend -from qibo.backends import MetaBackend, NumpyBackend, _Global, set_backend +from qibo.backends import MetaBackend, NumpyBackend, set_backend from qibo.quantum_info import random_clifford, random_density_matrix, random_statevector numpy_bkd = NumpyBackend() @@ -38,7 +38,6 @@ def test_initial_state_error(): qulacs_bkd.execute_circuit(c, initial_state=initial_state) -def test_set_backend(): +def test_set_backend(clear): set_backend("qulacs") assert get_backend().name == "qulacs" - _Global._clear_global() From 3e99140be158dc38d01825f50ea765b05420a143 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 9 Oct 2024 11:24:34 +0400 Subject: [PATCH 36/59] pytest autouse & default transpiler prototype --- src/qibo/backends/__init__.py | 25 +++++++++++++++++++++---- tests/conftest.py | 2 +- tests/test_backends_global.py | 2 +- tests/test_backends_qibotn.py | 2 +- tests/test_backends_qulacs.py | 2 +- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index a62b0d4003..31de38838d 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -1,5 +1,6 @@ import os from importlib import import_module +from random import Random import numpy as np @@ -116,15 +117,31 @@ def set_backend(cls, backend, **kwargs): @classmethod def transpiler(cls): """Get the current transpiler. If no transpiler is set, it will create one.""" + from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import Passes + from qibo.transpiler.placer import Trivial + from qibo.transpiler.router import Sabre + from qibo.transpiler.unroller import Unroller if cls._transpiler is not None: return cls._transpiler - # TODO: add default transpiler for hardware backends - # depends on cls._backend - - cls._transpiler = Passes(passes=[]) + if cls._backend.name == "qibolab": # pragma: no cover + platform = cls._backend.platform + natives = platform.natives # qibolab 0.2.0 + connectivity = platform.topology # qibolab 0.1.9 + + cls._transpiler = Passes( + connectivity=connectivity, + passes=[ + Preprocessing(connectivity), + Trivial(connectivity), + Sabre(connectivity), + Unroller(natives), + ], + ) + else: + cls._transpiler = Passes(passes=[]) return cls._transpiler @classmethod diff --git a/tests/conftest.py b/tests/conftest.py index 6d34b5c612..d28af6d2cc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,7 +74,7 @@ def backend(backend_name): yield get_backend(backend_name) -@pytest.fixture +@pytest.fixture(autouse=True) def clear(): yield diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 86c210f90f..2fe18819bd 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -120,7 +120,7 @@ def _star_connectivity(): return chip -def test_set_get_transpiler(clear): +def test_set_get_transpiler(): from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Random diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index e10e25d951..ca7035016e 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -8,7 +8,7 @@ from qibotn.backends.quimb import QuimbBackend -def test_backend_qibotn(clear): +def test_backend_qibotn(): set_backend(backend="qibotn", platform="qutensornet", runcard=None) assert isinstance(get_backend(), QuimbBackend) set_backend("numpy") diff --git a/tests/test_backends_qulacs.py b/tests/test_backends_qulacs.py index 34beb8c178..9ef0d8a9bd 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -38,6 +38,6 @@ def test_initial_state_error(): qulacs_bkd.execute_circuit(c, initial_state=initial_state) -def test_set_backend(clear): +def test_set_backend(): set_backend("qulacs") assert get_backend().name == "qulacs" From 535c5a4108b2d3789cd357a03eba6ceb42fc8a14 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Thu, 10 Oct 2024 15:48:06 +0400 Subject: [PATCH 37/59] hw backend prototype --- src/qibo/backends/__init__.py | 50 ++++++++++++++++++++++++----------- src/qibo/backends/abstract.py | 20 +++++++++++++- src/qibo/backends/numpy.py | 14 +++++++++- tests/test_backends_global.py | 7 +++++ 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 31de38838d..f44fbc8011 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -1,6 +1,5 @@ import os from importlib import import_module -from random import Random import numpy as np @@ -117,19 +116,46 @@ def set_backend(cls, backend, **kwargs): @classmethod def transpiler(cls): """Get the current transpiler. If no transpiler is set, it will create one.""" + if cls._transpiler is not None: + return cls._transpiler + + cls._transpiler = cls._default_transpiler() + return cls._transpiler + + @classmethod + def set_transpiler(cls, transpiler): + cls._transpiler = transpiler + # TODO: check if transpiler is valid on the backend + + @classmethod + def _default_transpiler(cls): + import networkx as nx + from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Trivial from qibo.transpiler.router import Sabre - from qibo.transpiler.unroller import Unroller + from qibo.transpiler.unroller import NativeGates, Unroller - if cls._transpiler is not None: - return cls._transpiler + qubits: list[str] = cls._backend.qubits # list of qubit names + natives: list[str] = cls._backend.natives + connectivity_edges: list[tuple[str, str]] = ( + cls._backend.connectivity + ) # list of edges + if qubits and natives and connectivity: + + # code is needed in unroll.py to convert str -> enum + natives_enum = NativeGates.from_gatelist(natives) - if cls._backend.name == "qibolab": # pragma: no cover - platform = cls._backend.platform - natives = platform.natives # qibolab 0.2.0 - connectivity = platform.topology # qibolab 0.1.9 + connectivity = nx.Graph() + + # q{i} naming + node_mapping = {qubits[i]: i for i in range(len(qubits))} + for e in connectivity_edges: + connectivity.add_edge(node_mapping[e[0]], node_mapping[e[1]]) + + # str naming + # connectivity.add_edges_from(connectivity_edges) cls._transpiler = Passes( connectivity=connectivity, @@ -137,17 +163,11 @@ def transpiler(cls): Preprocessing(connectivity), Trivial(connectivity), Sabre(connectivity), - Unroller(natives), + Unroller(natives_enum), ], ) else: cls._transpiler = Passes(passes=[]) - return cls._transpiler - - @classmethod - def set_transpiler(cls, transpiler): - cls._transpiler = transpiler - # TODO: check if transpiler is valid on the backend class QiboMatrices: diff --git a/src/qibo/backends/abstract.py b/src/qibo/backends/abstract.py index 468fa89008..8348eba445 100644 --- a/src/qibo/backends/abstract.py +++ b/src/qibo/backends/abstract.py @@ -1,5 +1,5 @@ import abc -from typing import Union +from typing import Optional, Union from qibo.config import raise_error @@ -29,6 +29,24 @@ def __repr__(self): else: return f"{self.name} ({self.platform})" + @property + @abc.abstractmethod + def qubits(self) -> Optional[list[str]]: # pragma: no cover + """Return the qubit names of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + + @property + @abc.abstractmethod + def connectivity(self) -> Optional[list[tuple[str, str]]]: # pragma: no cover + """Return the available qubit pairs of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + + @property + @abc.abstractmethod + def natives(self) -> Optional[list[str]]: # pragma: no cover + """Return the native gates of the backend. If :class:`SimulationBackend`, return None.""" + raise_error(NotImplementedError) + @abc.abstractmethod def set_precision(self, precision): # pragma: no cover """Set complex number precision. diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index fe1441b7c6..032157be87 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -1,6 +1,6 @@ import collections import math -from typing import Union +from typing import Optional, Union import numpy as np from scipy import sparse @@ -34,6 +34,18 @@ def __init__(self): np.complex128, ) + @property + def qubits(self) -> Optional[list[str]]: # pragma: no cover + return None + + @property + def connectivity(self) -> Optional[list[tuple[str, str]]]: # pragma: no cover + return None + + @property + def natives(self) -> Optional[list[str]]: # pragma: no cover + return None + def set_precision(self, precision): if precision != self.precision: if precision == "single": diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 2fe18819bd..84db8c47f2 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -141,3 +141,10 @@ def test_set_get_transpiler(): qibo.set_transpiler(transpiler) assert qibo.get_transpiler() == transpiler assert qibo.get_transpiler_name() == str(transpiler) + + +def test_backend_hw_properties(): + from qibo.backends.numpy import NumpyBackend + + backend = NumpyBackend() + assert backend.natives is None and backend.connectivity is None From eba4f5ee6e199055c9924ef123f51018c5ed9e29 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Thu, 10 Oct 2024 17:24:13 +0400 Subject: [PATCH 38/59] hw backend prototype --- src/qibo/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index f44fbc8011..4af072712a 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -137,7 +137,7 @@ def _default_transpiler(cls): from qibo.transpiler.router import Sabre from qibo.transpiler.unroller import NativeGates, Unroller - qubits: list[str] = cls._backend.qubits # list of qubit names + qubits: list[str] = list(cls._backend.qubits) # list of qubit names natives: list[str] = cls._backend.natives connectivity_edges: list[tuple[str, str]] = ( cls._backend.connectivity From 5613c4c53dc0d587bb3c8bebc16ded73a24a522c Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Fri, 11 Oct 2024 09:22:05 +0400 Subject: [PATCH 39/59] fix: hw attributes check --- src/qibo/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 4af072712a..4c91dbf901 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -142,7 +142,7 @@ def _default_transpiler(cls): connectivity_edges: list[tuple[str, str]] = ( cls._backend.connectivity ) # list of edges - if qubits and natives and connectivity: + if qubits is not None and natives is not None and connectivity is not None: # code is needed in unroll.py to convert str -> enum natives_enum = NativeGates.from_gatelist(natives) From b44c13a5e6a71742ddc6fb67e627df597f65ab3b Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 14 Oct 2024 10:16:07 +0400 Subject: [PATCH 40/59] fix: temporary _default_transpiler for current transpiler --- src/qibo/backends/__init__.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 4c91dbf901..74fb19d0be 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -137,25 +137,18 @@ def _default_transpiler(cls): from qibo.transpiler.router import Sabre from qibo.transpiler.unroller import NativeGates, Unroller - qubits: list[str] = list(cls._backend.qubits) # list of qubit names - natives: list[str] = cls._backend.natives - connectivity_edges: list[tuple[str, str]] = ( - cls._backend.connectivity - ) # list of edges + qubits = cls._backend.qubits + natives = cls._backend.natives + connectivity_edges = cls._backend.connectivity if qubits is not None and natives is not None and connectivity is not None: - - # code is needed in unroll.py to convert str -> enum natives_enum = NativeGates.from_gatelist(natives) - connectivity = nx.Graph() - - # q{i} naming - node_mapping = {qubits[i]: i for i in range(len(qubits))} - for e in connectivity_edges: - connectivity.add_edge(node_mapping[e[0]], node_mapping[e[1]]) - - # str naming - # connectivity.add_edges_from(connectivity_edges) + # only for q{i} naming + node_mapping = {q: i for i, q in enumerate(qubits)} + edges = [ + (node_mapping[e[0]], node_mapping[e[1]]) for e in connectivity_edges + ] + connectivity = nx.Graph(edges) cls._transpiler = Passes( connectivity=connectivity, From 11548dab3b1464b1fd05f981adf0e949463a8024 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 14 Oct 2024 10:41:59 +0400 Subject: [PATCH 41/59] feat: create NativeGates from list[str] --- src/qibo/backends/__init__.py | 2 +- src/qibo/transpiler/unroller.py | 31 +++++++++++++++++++++++++++++-- tests/test_transpiler_unroller.py | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 74fb19d0be..fc6da78a90 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -128,7 +128,7 @@ def set_transpiler(cls, transpiler): # TODO: check if transpiler is valid on the backend @classmethod - def _default_transpiler(cls): + def _default_transpiler(cls): # pragma: no cover import networkx as nx from qibo.transpiler.optimizer import Preprocessing diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index 9032e5e306..68f8e9f753 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -56,17 +56,44 @@ def from_gatelist(cls, gatelist: list): return natives @classmethod - def from_gate(cls, gate: gates.Gate): + def from_gate(cls, gate): """Create a :class:`qibo.transpiler.unroller.NativeGates` - object from a :class:`qibo.gates.gates.Gate`.""" + object from a :class:`qibo.gates.gates.Gate`, a gate class, or a gate name as a string. + """ if isinstance(gate, gates.Gate): return cls.from_gate(gate.__class__) + elif isinstance(gate, str): + return getattr(cls, cls.from_str(gate).__name__) try: return getattr(cls, gate.__name__) except AttributeError: raise_error(ValueError, f"Gate {gate} cannot be used as native.") + @classmethod + def from_str(cls, gate: str): + """Return the gate class corresponding to the input gate name.""" + gate_format = gate.lower() + if gate_format == "i": + return gates.I + elif gate_format == "z": + return gates.Z + elif gate_format == "rz": + return gates.RZ + elif gate_format == "m": + return gates.M + elif gate_format == "gpi2": + return gates.GPI2 + elif gate_format == "u3": + return gates.U3 + elif gate_format == "cz": + return gates.CZ + elif gate_format == "iswap": + return gates.iSWAP + elif gate_format == "cnot" or gate_format == "cx": + return gates.CNOT + raise_error(ValueError, f"Gate name {gate} not found.") + # TODO: Make setting single-qubit native gates more flexible class Unroller: diff --git a/tests/test_transpiler_unroller.py b/tests/test_transpiler_unroller.py index 474d2c50a3..749528e7e9 100644 --- a/tests/test_transpiler_unroller.py +++ b/tests/test_transpiler_unroller.py @@ -21,6 +21,29 @@ def test_native_gates_from_gatelist_fail(): NativeGates.from_gatelist([gates.RZ, gates.X(0)]) +def test_native_gates_str_from_gatelist(): + natives = NativeGates.from_gatelist( + ["I", "Z", "RZ", "M", "GPI2", "U3", "CZ", "iSWAP", "CX"] + ) + assert ( + natives + == NativeGates.I + | NativeGates.Z + | NativeGates.RZ + | NativeGates.M + | NativeGates.GPI2 + | NativeGates.U3 + | NativeGates.CZ + | NativeGates.iSWAP + | NativeGates.CNOT + ) + + +def test_native_gate_str_from_gatelist_fail(): + with pytest.raises(ValueError): + NativeGates.from_gatelist(["qibo"]) + + def test_translate_gate_error_1q(): natives = NativeGates(0) with pytest.raises(DecompositionError): From e0292ccecd34f79b53780817ac839211183bd91a Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 14 Oct 2024 12:55:52 +0400 Subject: [PATCH 42/59] fix: return value of default transpiler --- src/qibo/backends/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index fc6da78a90..35e9dc5928 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -150,7 +150,7 @@ def _default_transpiler(cls): # pragma: no cover ] connectivity = nx.Graph(edges) - cls._transpiler = Passes( + return Passes( connectivity=connectivity, passes=[ Preprocessing(connectivity), @@ -160,7 +160,7 @@ def _default_transpiler(cls): # pragma: no cover ], ) else: - cls._transpiler = Passes(passes=[]) + return Passes(passes=[]) class QiboMatrices: From 3c29f615ae74b5ff355617859e55316f8a5e98a5 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 10:07:28 +0400 Subject: [PATCH 43/59] feat: test files for _Global._default_transpiler --- src/qibo/backends/__init__.py | 12 ++++++--- src/qibo/backends/numpy.py | 8 +++--- tests/conftest.py | 2 -- tests/test_backends_global.py | 46 +++++++++++++++++++++++++++++++---- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 35e9dc5928..ccafffe347 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -128,7 +128,7 @@ def set_transpiler(cls, transpiler): # TODO: check if transpiler is valid on the backend @classmethod - def _default_transpiler(cls): # pragma: no cover + def _default_transpiler(cls): import networkx as nx from qibo.transpiler.optimizer import Preprocessing @@ -140,7 +140,11 @@ def _default_transpiler(cls): # pragma: no cover qubits = cls._backend.qubits natives = cls._backend.natives connectivity_edges = cls._backend.connectivity - if qubits is not None and natives is not None and connectivity is not None: + if ( + qubits is not None + and natives is not None + and connectivity_edges is not None + ): natives_enum = NativeGates.from_gatelist(natives) # only for q{i} naming @@ -159,8 +163,8 @@ def _default_transpiler(cls): # pragma: no cover Unroller(natives_enum), ], ) - else: - return Passes(passes=[]) + + return Passes(passes=[]) class QiboMatrices: diff --git a/src/qibo/backends/numpy.py b/src/qibo/backends/numpy.py index cb9b5addc9..ff56669ccf 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -1,6 +1,6 @@ import collections import math -from typing import Optional, Union +from typing import Union import numpy as np from scipy import sparse @@ -35,15 +35,15 @@ def __init__(self): ) @property - def qubits(self) -> Optional[list[str]]: # pragma: no cover + def qubits(self): return None @property - def connectivity(self) -> Optional[list[tuple[str, str]]]: # pragma: no cover + def connectivity(self): return None @property - def natives(self) -> Optional[list[str]]: # pragma: no cover + def natives(self): return None def set_precision(self, precision): diff --git a/tests/conftest.py b/tests/conftest.py index d28af6d2cc..8b38ab4152 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -82,8 +82,6 @@ def clear(): _Global._backend = None _Global._transpiler = None - _Global.backend() - _Global._transpiler = Passes(passes=[]) def pytest_generate_tests(metafunc): diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 84db8c47f2..40a56a6b5e 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -2,7 +2,11 @@ import pytest import qibo -from qibo import matrices +from qibo import gates, matrices +from qibo.backends import _Global +from qibo.backends.numpy import NumpyBackend +from qibo.models.circuit import Circuit +from qibo.transpiler.unroller import NativeGates def test_set_get_backend(): @@ -143,8 +147,40 @@ def test_set_get_transpiler(): assert qibo.get_transpiler_name() == str(transpiler) -def test_backend_hw_properties(): - from qibo.backends.numpy import NumpyBackend - +def test_default_transpiler_sim(): backend = NumpyBackend() - assert backend.natives is None and backend.connectivity is None + assert ( + backend.natives is None + and backend.connectivity is None + and backend.qubits is None + ) + + +def test_default_transpiler_hw(): + class TempBackend(NumpyBackend): + def __init__(self): + super().__init__() + self.name = "tempbackend" + + @property + def qubits(self): + return ["A1", "A2", "A3", "A4", "A5"] + + @property + def connectivity(self): + return [("A1", "A2"), ("A2", "A3"), ("A3", "A4"), ("A4", "A5")] + + @property + def natives(self): + return ["CZ", "GPI2"] + + backend = TempBackend() + _Global._backend = backend + transpiler = _Global.transpiler() + + assert list(transpiler.connectivity.nodes) == [0, 1, 2, 3, 4] + assert list(transpiler.connectivity.edges) == [(0, 1), (1, 2), (2, 3), (3, 4)] + assert ( + NativeGates.CZ in transpiler.native_gates + and NativeGates.GPI2 in transpiler.native_gates + ) From 3eeff46a8075fbb6a04f26644e3eb8068a57e633 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 10:24:37 +0400 Subject: [PATCH 44/59] fix: unused import/vars --- src/qibo/backends/__init__.py | 5 ++--- tests/conftest.py | 3 --- tests/test_backends_global.py | 11 +++++------ tests/test_backends_qibotn.py | 1 - tests/test_models_error_mitigation.py | 2 +- tests/test_models_qcnn.py | 2 -- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index ccafffe347..b5b9a04fda 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -1,6 +1,7 @@ import os from importlib import import_module +import networkx as nx import numpy as np from qibo.backends.abstract import Backend @@ -101,7 +102,7 @@ def _create_backend(cls): try: backend = construct_backend(**kwargs) break - except (ModuleNotFoundError, ImportError): + except (ImportError, MissingBackend): pass if backend is None: # pragma: no cover @@ -129,8 +130,6 @@ def set_transpiler(cls, transpiler): @classmethod def _default_transpiler(cls): - import networkx as nx - from qibo.transpiler.optimizer import Preprocessing from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Trivial diff --git a/tests/conftest.py b/tests/conftest.py index 8b38ab4152..db51f97456 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -77,9 +77,6 @@ def backend(backend_name): @pytest.fixture(autouse=True) def clear(): yield - - from qibo.transpiler.pipeline import Passes - _Global._backend = None _Global._transpiler = None diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 40a56a6b5e..da8daab1fe 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -2,17 +2,16 @@ import pytest import qibo -from qibo import gates, matrices +from qibo import matrices from qibo.backends import _Global from qibo.backends.numpy import NumpyBackend -from qibo.models.circuit import Circuit from qibo.transpiler.unroller import NativeGates def test_set_get_backend(): from qibo.backends import _Global - backend = _Global.backend() + _Global.backend() qibo.set_backend("numpy") assert qibo.get_backend_name() == "numpy" assert qibo.get_backend().name == "numpy" @@ -88,14 +87,14 @@ def test_circuit_execution(): qibo.set_backend("numpy") c = qibo.models.Circuit(2) c.add(qibo.gates.H(0)) - result = c() - unitary = c.unitary() + c() + c.unitary() def test_gate_matrix(): qibo.set_backend("numpy") gate = qibo.gates.H(0) - matrix = gate.matrix + gate.matrix def test_check_backend(backend): diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index ca7035016e..d2aba6f3c2 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -1,6 +1,5 @@ import os -# import qibo from qibo import get_backend, get_threads, set_backend # Force quimb to use qibojit default number of threads. diff --git a/tests/test_models_error_mitigation.py b/tests/test_models_error_mitigation.py index ca74e7e882..8e003993cf 100644 --- a/tests/test_models_error_mitigation.py +++ b/tests/test_models_error_mitigation.py @@ -2,7 +2,7 @@ import pytest from qibo import Circuit, gates -from qibo.backends import _Global, construct_backend +from qibo.backends import construct_backend from qibo.hamiltonians import SymbolicHamiltonian from qibo.models.error_mitigation import ( CDR, diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 9758e005fc..5c5c9230a4 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -2,9 +2,7 @@ import numpy as np -import qibo from qibo import gates, set_backend -from qibo.backends import _Global from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN From a4ee205ee17f1d0476da4407302258c657f7c69a Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 10:30:56 +0400 Subject: [PATCH 45/59] fix: else after return --- src/qibo/models/circuit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qibo/models/circuit.py b/src/qibo/models/circuit.py index b2d5da53d5..9b3916b3ae 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -1109,8 +1109,7 @@ def execute(self, initial_state=None, nshots=1000): return backend.execute_distributed_circuit( transpiled_circuit, initial_state, nshots ) - else: - return backend.execute_circuit(transpiled_circuit, initial_state, nshots) + return backend.execute_circuit(transpiled_circuit, initial_state, nshots) def __call__(self, initial_state=None, nshots=1000): """Equivalent to ``circuit.execute``.""" From be12cf908021fc218c53c9d03f19b87687f9bf7b Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 10:52:38 +0400 Subject: [PATCH 46/59] fix: improve star/line/grid connectivity helper functions --- doc/source/code-examples/advancedexamples.rst | 5 ++--- tests/test_transpiler_optimizer.py | 5 ++--- tests/test_transpiler_pipeline.py | 5 ++--- tests/test_transpiler_placer.py | 10 ++-------- tests/test_transpiler_router.py | 15 ++++++--------- 5 files changed, 14 insertions(+), 26 deletions(-) diff --git a/doc/source/code-examples/advancedexamples.rst b/doc/source/code-examples/advancedexamples.rst index c4aa4ccd84..8a3736b99c 100644 --- a/doc/source/code-examples/advancedexamples.rst +++ b/doc/source/code-examples/advancedexamples.rst @@ -2102,10 +2102,9 @@ Multiple transpilation steps can be implemented using the :class:`qibo.transpile # Define connectivity as nx.Graph def star_connectivity(): - Q = [i for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[i], Q[2]) for i in range(5) if i != 2] + chip.add_nodes_from(list(range(5))) + graph_list = [(i, 2) for i in range(5) if i != 2] chip.add_edges_from(graph_list) return chip diff --git a/tests/test_transpiler_optimizer.py b/tests/test_transpiler_optimizer.py index ad82e49911..171c7516d4 100644 --- a/tests/test_transpiler_optimizer.py +++ b/tests/test_transpiler_optimizer.py @@ -7,10 +7,9 @@ def star_connectivity(): - Q = ["q" + str(i) for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[i], Q[2]) for i in range(5) if i != 2] + chip.add_nodes_from(list(range(5))) + graph_list = [(i, 2) for i in range(5) if i != 2] chip.add_edges_from(graph_list) return chip diff --git a/tests/test_transpiler_pipeline.py b/tests/test_transpiler_pipeline.py index bd2c9749c3..bfa13f9e4d 100644 --- a/tests/test_transpiler_pipeline.py +++ b/tests/test_transpiler_pipeline.py @@ -54,10 +54,9 @@ def generate_random_circuit(nqubits, ngates, seed=None): def star_connectivity(): - Q = [i for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[i], Q[2]) for i in range(5) if i != 2] + chip.add_nodes_from(list(range(5))) + graph_list = [(i, 2) for i in range(5) if i != 2] chip.add_edges_from(graph_list) return chip diff --git a/tests/test_transpiler_placer.py b/tests/test_transpiler_placer.py index 3d19c03d18..6855a7eeac 100644 --- a/tests/test_transpiler_placer.py +++ b/tests/test_transpiler_placer.py @@ -20,15 +20,9 @@ def star_connectivity(): - Q = [i for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [ - (Q[0], Q[2]), - (Q[1], Q[2]), - (Q[3], Q[2]), - (Q[4], Q[2]), - ] + chip.add_nodes_from(list(range(5))) + graph_list = [(i, 2) for i in range(5) if i != 2] chip.add_edges_from(graph_list) return chip diff --git a/tests/test_transpiler_router.py b/tests/test_transpiler_router.py index d5901d5f92..80b0e72aa3 100644 --- a/tests/test_transpiler_router.py +++ b/tests/test_transpiler_router.py @@ -33,28 +33,25 @@ def star_connectivity(middle_qubit=2): - Q = [i for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[i], Q[middle_qubit]) for i in range(5) if i != middle_qubit] + chip.add_nodes_from(list(range(5))) + graph_list = [(i, middle_qubit) for i in range(5) if i != middle_qubit] chip.add_edges_from(graph_list) return chip def grid_connectivity(): - Q = [i for i in range(5)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[0], Q[1]), (Q[1], Q[2]), (Q[2], Q[3]), (Q[3], Q[0]), (Q[0], Q[4])] + chip.add_nodes_from(list(range(5))) + graph_list = [(0, 1), (1, 2), (2, 3), (3, 0), (0, 4)] chip.add_edges_from(graph_list) return chip def line_connectivity(n): - Q = [i for i in range(n)] chip = nx.Graph() - chip.add_nodes_from(Q) - graph_list = [(Q[i], (Q[i] + 1) % n) for i in range(n - 1)] + chip.add_nodes_from(list(range(n))) + graph_list = [(i, i + 1) for i in range(n - 1)] chip.add_edges_from(graph_list) return chip From 84dc20c463338d6b3882a9b77860fd4104e3d17c Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 11:05:39 +0400 Subject: [PATCH 47/59] fix: remove Nativegates.from_gate(str) --- src/qibo/backends/__init__.py | 5 ++++- src/qibo/transpiler/unroller.py | 30 +----------------------------- tests/test_transpiler_unroller.py | 18 ------------------ 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index b5b9a04fda..c4395158c4 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -1,5 +1,7 @@ import os +from functools import reduce from importlib import import_module +from operator import or_ import networkx as nx import numpy as np @@ -144,7 +146,8 @@ def _default_transpiler(cls): and natives is not None and connectivity_edges is not None ): - natives_enum = NativeGates.from_gatelist(natives) + # natives_enum = NativeGates.from_gatelist(natives) + natives_enum = reduce(or_, [NativeGates[nat] for nat in natives]) # only for q{i} naming node_mapping = {q: i for i, q in enumerate(qubits)} diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index 6d26dc84c1..5559066fa4 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -59,42 +59,14 @@ def from_gatelist(cls, gatelist: list): @classmethod def from_gate(cls, gate): """Create a :class:`qibo.transpiler.unroller.NativeGates` - object from a :class:`qibo.gates.gates.Gate`, a gate class, or a gate name as a string. - """ + object from a :class:`qibo.gates.gates.Gate`.""" if isinstance(gate, gates.Gate): return cls.from_gate(gate.__class__) - elif isinstance(gate, str): - return getattr(cls, cls.from_str(gate).__name__) - try: return getattr(cls, gate.__name__) except AttributeError: raise_error(ValueError, f"Gate {gate} cannot be used as native.") - @classmethod - def from_str(cls, gate: str): - """Return the gate class corresponding to the input gate name.""" - gate_format = gate.lower() - if gate_format == "i": - return gates.I - elif gate_format == "z": - return gates.Z - elif gate_format == "rz": - return gates.RZ - elif gate_format == "m": - return gates.M - elif gate_format == "gpi2": - return gates.GPI2 - elif gate_format == "u3": - return gates.U3 - elif gate_format == "cz": - return gates.CZ - elif gate_format == "iswap": - return gates.iSWAP - elif gate_format == "cnot" or gate_format == "cx": - return gates.CNOT - raise_error(ValueError, f"Gate name {gate} not found.") - # TODO: Make setting single-qubit native gates more flexible class Unroller: diff --git a/tests/test_transpiler_unroller.py b/tests/test_transpiler_unroller.py index 749528e7e9..b3b34149ab 100644 --- a/tests/test_transpiler_unroller.py +++ b/tests/test_transpiler_unroller.py @@ -21,24 +21,6 @@ def test_native_gates_from_gatelist_fail(): NativeGates.from_gatelist([gates.RZ, gates.X(0)]) -def test_native_gates_str_from_gatelist(): - natives = NativeGates.from_gatelist( - ["I", "Z", "RZ", "M", "GPI2", "U3", "CZ", "iSWAP", "CX"] - ) - assert ( - natives - == NativeGates.I - | NativeGates.Z - | NativeGates.RZ - | NativeGates.M - | NativeGates.GPI2 - | NativeGates.U3 - | NativeGates.CZ - | NativeGates.iSWAP - | NativeGates.CNOT - ) - - def test_native_gate_str_from_gatelist_fail(): with pytest.raises(ValueError): NativeGates.from_gatelist(["qibo"]) From bdb31b5153d407fb49e8420b49858294831def26 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 11:17:35 +0400 Subject: [PATCH 48/59] fix: remove _Global._backend usage / deprecate get_backend_name --- src/qibo/__init__.py | 1 - src/qibo/backends/__init__.py | 5 ----- src/qibo/models/error_mitigation.py | 9 ++------- src/qibo/models/qcnn.py | 5 +++-- tests/test_backends_clifford.py | 5 +---- tests/test_backends_global.py | 22 ++++++++-------------- 6 files changed, 14 insertions(+), 33 deletions(-) diff --git a/src/qibo/__init__.py b/src/qibo/__init__.py index 9d3682a385..5610cf493f 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -16,7 +16,6 @@ from qibo.backends import ( construct_backend, get_backend, - get_backend_name, get_device, get_precision, get_threads, diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index c4395158c4..a0983f5899 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -207,11 +207,6 @@ def get_backend(): return _Global.backend() -def get_backend_name(): - """Get the name of the current backend""" - return str(_Global.backend()) - - def set_backend(backend, **kwargs): """Set the current backend. diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 9fbfc045b2..4fe3a77109 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -8,12 +8,7 @@ from scipy.optimize import curve_fit from qibo import gates -from qibo.backends import ( - _check_backend, - _check_backend_and_local_state, - get_backend, - get_backend_name, -) +from qibo.backends import _check_backend, _check_backend_and_local_state, get_backend from qibo.config import raise_error @@ -1173,7 +1168,7 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend # TODO: remove backend.platform.topology and pragma: no cover if backend is None: # pragma: no cover backend = get_backend() - elif get_backend_name() == "qibolab": # pragma: no cover + elif str(get_backend()) == "qibolab": # pragma: no cover transpiler = Custom( initial_map=qubit_map, connectivity=backend.platform.topology ) diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 5a99c172c8..d3a35c2522 100644 --- a/src/qibo/models/qcnn.py +++ b/src/qibo/models/qcnn.py @@ -5,7 +5,8 @@ import numpy as np -from qibo import gates, get_backend_name +from qibo import gates +from qibo.backends import get_backend from qibo.models import Circuit @@ -80,7 +81,7 @@ def __init__( self.twoqubitansatz = twoqubitansatz if copy_init_state is None: - if "qibojit" in get_backend_name(): + if "qibojit" in str(get_backend()): self.copy_init_state = True else: self.copy_init_state = False diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 8ed626a747..2760ff015b 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -11,7 +11,6 @@ NumpyBackend, PyTorchBackend, TensorflowBackend, - _Global, ) from qibo.backends.clifford import _get_engine_name from qibo.noise import DepolarizingError, NoiseModel, PauliError @@ -45,9 +44,7 @@ def test_global_backend(backend): construct_clifford_backend(backend) set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() - target = ( - _Global._backend.name if backend.name == "numpy" else _Global._backend.platform - ) + target = get_backend().name if backend.name == "numpy" else get_backend().platform assert clifford_bkd.platform == target diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index da8daab1fe..45f990eb76 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -3,17 +3,18 @@ import qibo from qibo import matrices -from qibo.backends import _Global +from qibo.backends import _Global, get_backend from qibo.backends.numpy import NumpyBackend -from qibo.transpiler.unroller import NativeGates +from qibo.transpiler.optimizer import Preprocessing +from qibo.transpiler.pipeline import Passes +from qibo.transpiler.placer import Random +from qibo.transpiler.router import Sabre +from qibo.transpiler.unroller import NativeGates, Unroller def test_set_get_backend(): - from qibo.backends import _Global - - _Global.backend() qibo.set_backend("numpy") - assert qibo.get_backend_name() == "numpy" + assert str(qibo.get_backend()) == "numpy" assert qibo.get_backend().name == "numpy" @@ -107,8 +108,7 @@ def test_check_backend(backend): # testing when backend is None test = None test = qibo.backends._check_backend(test) - - target = qibo.backends._Global.backend() + target = get_backend() assert test.name == target.name assert test.__class__ == target.__class__ @@ -124,12 +124,6 @@ def _star_connectivity(): def test_set_get_transpiler(): - from qibo.transpiler.optimizer import Preprocessing - from qibo.transpiler.pipeline import Passes - from qibo.transpiler.placer import Random - from qibo.transpiler.router import Sabre - from qibo.transpiler.unroller import NativeGates, Unroller - connectivity = _star_connectivity() transpiler = Passes( connectivity=connectivity, From 6fe420508082155d69564dc611840ffeee7897c2 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 11:32:08 +0400 Subject: [PATCH 49/59] fix: remove pragma / improve _execute_circuit in error_mitigation.py --- src/qibo/models/error_mitigation.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 4fe3a77109..ed23cac843 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -4,6 +4,7 @@ from inspect import signature from itertools import product +import networkx as nx import numpy as np from scipy.optimize import curve_fit @@ -1163,17 +1164,23 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend Returns: qibo.states.CircuitResult: The result of the circuit execution. """ + from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Custom - # TODO: remove backend.platform.topology and pragma: no cover - if backend is None: # pragma: no cover + if backend is None: backend = get_backend() - elif str(get_backend()) == "qibolab": # pragma: no cover - transpiler = Custom( - initial_map=qubit_map, connectivity=backend.platform.topology + elif backend.name == "qibolab": # pragma: no cover + qubits = backend.qubits + connectivity_edges = backend.connectivity + node_mapping = {q: i for i, q in enumerate(qubits)} + edges = [(node_mapping[e[0]], node_mapping[e[1]]) for e in connectivity_edges] + connectivity = nx.Graph(edges) + transpiler = Passes( + connectivity=connectivity, + passes=[Custom(initial_map=qubit_map, connectivity=connectivity)], ) circuit, _ = transpiler(circuit) - elif noise_model is not None: # pragma: no cover + elif noise_model is not None: circuit = noise_model.apply(circuit) circuit_result = backend.execute_circuit(circuit, nshots=nshots) From 9e7cc6b9bbb90d62fdeb79e380fd2a9a87b8319a Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Tue, 15 Oct 2024 12:49:12 +0400 Subject: [PATCH 50/59] fix: add pragma --- src/qibo/models/error_mitigation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index ed23cac843..289cf2b7c7 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -1167,7 +1167,7 @@ def _execute_circuit(circuit, qubit_map, noise_model=None, nshots=10000, backend from qibo.transpiler.pipeline import Passes from qibo.transpiler.placer import Custom - if backend is None: + if backend is None: # pragma: no cover backend = get_backend() elif backend.name == "qibolab": # pragma: no cover qubits = backend.qubits From 6c77fdea261e8acc07560a895ed913bf4d987cd5 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 10:23:24 +0400 Subject: [PATCH 51/59] fix: minor docstring update --- src/qibo/quantum_info/entanglement.py | 2 +- src/qibo/quantum_info/linalg_operations.py | 4 ++-- src/qibo/quantum_info/metrics.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qibo/quantum_info/entanglement.py b/src/qibo/quantum_info/entanglement.py index d1b7cf7cde..3851739e4c 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -138,7 +138,7 @@ def negativity(state, bipartition, backend=None): state (ndarray): statevector or density matrix. bipartition (list or tuple or ndarray): qubits in the subsystem to be traced out. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses it uses the current backend. Defaults to ``None``. Returns: diff --git a/src/qibo/quantum_info/linalg_operations.py b/src/qibo/quantum_info/linalg_operations.py index 0cdd9d9d95..33cc494515 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -187,7 +187,7 @@ def partial_transpose( partition (Union[List[int], Tuple[int, ...]]): indices of qubits to be transposed. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + it uses the current backend. Defaults to ``None``. Returns: ndarray: Partially transposed operator(s) :math:`\\O^{T_{B}}`. @@ -316,7 +316,7 @@ def singular_value_decomposition(matrix, backend=None): matrix (ndarray): matrix whose SVD to calculate. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used in the execution. If ``None``, it uses - :class:`qibo.backends.GlobalBackend`. Defaults to ``None``. + the current backend. Defaults to ``None``. Returns: ndarray, ndarray, ndarray: Singular value decomposition of :math:`A`, i.e. diff --git a/src/qibo/quantum_info/metrics.py b/src/qibo/quantum_info/metrics.py index 2c1df26e6d..a6ca2535f5 100644 --- a/src/qibo/quantum_info/metrics.py +++ b/src/qibo/quantum_info/metrics.py @@ -147,7 +147,7 @@ def hilbert_schmidt_inner_product(operator_A, operator_B, backend=None): operator_A (ndarray): operator :math:`A`. operator_B (ndarray): operator :math:`B`. backend (:class:`qibo.backends.abstract.Backend`, optional): backend to be used - in the execution. If ``None``, it uses :class:`qibo.backends.GlobalBackend`. + in the execution. If ``None``, it uses the current backend. Defaults to ``None``. Returns: From e913307f5453241bab3c4b4705277b112eeb6ca8 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 11:57:32 +0400 Subject: [PATCH 52/59] feat: enable initializing NativeGates from list[str] --- src/qibo/backends/__init__.py | 7 +------ src/qibo/transpiler/unroller.py | 13 +++++++++++-- tests/test_transpiler_unroller.py | 11 ++++++++--- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index a4ae61056a..f666bdcd6c 100644 --- a/src/qibo/backends/__init__.py +++ b/src/qibo/backends/__init__.py @@ -1,7 +1,5 @@ import os -from functools import reduce from importlib import import_module -from operator import or_ import networkx as nx import numpy as np @@ -146,9 +144,6 @@ def _default_transpiler(cls): and natives is not None and connectivity_edges is not None ): - # natives_enum = NativeGates.from_gatelist(natives) - natives_enum = reduce(or_, [NativeGates[nat] for nat in natives]) - # only for q{i} naming node_mapping = {q: i for i, q in enumerate(qubits)} edges = [ @@ -162,7 +157,7 @@ def _default_transpiler(cls): Preprocessing(connectivity), Trivial(connectivity), Sabre(connectivity), - Unroller(natives_enum), + Unroller(NativeGates[natives]), ], ) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index 5559066fa4..2cff3d59fc 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -1,4 +1,6 @@ -from enum import Flag, auto +from enum import EnumMeta, Flag, auto +from functools import reduce +from operator import or_ from qibo import gates from qibo.backends import _check_backend @@ -15,7 +17,14 @@ ) -class NativeGates(Flag): +class FlagMeta(EnumMeta): + def __getitem__(self, keys): + if isinstance(keys, str): + return super().__getitem__(keys) + return reduce(or_, [self[key] for key in keys]) + + +class NativeGates(Flag, metaclass=FlagMeta): """Define native gates supported by the unroller. A native gate set should contain at least one two-qubit gate (:class:`qibo.gates.gates.CZ` or :class:`qibo.gates.gates.iSWAP`), and at least one single-qubit gate diff --git a/tests/test_transpiler_unroller.py b/tests/test_transpiler_unroller.py index b3b34149ab..d3aa3e9ba9 100644 --- a/tests/test_transpiler_unroller.py +++ b/tests/test_transpiler_unroller.py @@ -21,9 +21,14 @@ def test_native_gates_from_gatelist_fail(): NativeGates.from_gatelist([gates.RZ, gates.X(0)]) -def test_native_gate_str_from_gatelist_fail(): - with pytest.raises(ValueError): - NativeGates.from_gatelist(["qibo"]) +def test_native_gate_str_list(): + testlist = ["I", "Z", "RZ", "M", "GPI2", "U3", "CZ", "iSWAP", "CNOT"] + natives = NativeGates[testlist] + for gate in testlist: + assert NativeGates[gate] in natives + + with pytest.raises(KeyError): + NativeGates[["qi", "bo"]] # Invalid gate names def test_translate_gate_error_1q(): From 933f08c520eb5f3df608cb8f5cb24f65c440111b Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 12:04:49 +0400 Subject: [PATCH 53/59] fix: pylint error --- src/qibo/transpiler/unroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index 2cff3d59fc..e533da8a07 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -21,7 +21,7 @@ class FlagMeta(EnumMeta): def __getitem__(self, keys): if isinstance(keys, str): return super().__getitem__(keys) - return reduce(or_, [self[key] for key in keys]) + return reduce(or_, [super().__getitem__(key) for key in keys]) class NativeGates(Flag, metaclass=FlagMeta): From 08107cd01472e70fa297fb5af029de4b7ceb9645 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 13:55:02 +0400 Subject: [PATCH 54/59] fix: Flag OR operation in FlagMeta --- src/qibo/transpiler/unroller.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index e533da8a07..b6e66556d6 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -1,6 +1,4 @@ from enum import EnumMeta, Flag, auto -from functools import reduce -from operator import or_ from qibo import gates from qibo.backends import _check_backend @@ -21,7 +19,11 @@ class FlagMeta(EnumMeta): def __getitem__(self, keys): if isinstance(keys, str): return super().__getitem__(keys) - return reduce(or_, [super().__getitem__(key) for key in keys]) + + result = super().__getitem__(keys[0]) + for key in keys[1:]: + result |= super().__getitem__(key) + return result class NativeGates(Flag, metaclass=FlagMeta): From 099007693a8ebc511bbef132dbc822a5e2f31f9a Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Wed, 16 Oct 2024 12:40:42 +0200 Subject: [PATCH 55/59] fix: Restore previous flag meta implementation Silencing pylint false positive --- src/qibo/transpiler/unroller.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index b6e66556d6..55bb60d454 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -1,4 +1,6 @@ from enum import EnumMeta, Flag, auto +from functools import reduce +from operator import or_ from qibo import gates from qibo.backends import _check_backend @@ -19,11 +21,7 @@ class FlagMeta(EnumMeta): def __getitem__(self, keys): if isinstance(keys, str): return super().__getitem__(keys) - - result = super().__getitem__(keys[0]) - for key in keys[1:]: - result |= super().__getitem__(key) - return result + return reduce(or_, [self[key] for key in keys]) # pylint: disable=E1136 class NativeGates(Flag, metaclass=FlagMeta): From 5d260e33d6cab4e0d57cc36dadf3288ed0881c6f Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 14:45:31 +0400 Subject: [PATCH 56/59] fix: add docstring in FlagMeta --- src/qibo/transpiler/unroller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index b6e66556d6..d0ba16b28c 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -16,7 +16,9 @@ class FlagMeta(EnumMeta): - def __getitem__(self, keys): + """Metaclass for :class:`qibo.transpiler.unroller.NativeGates` that allows initialization with a list of gate name strings.""" + + def __getitem__(cls, keys): if isinstance(keys, str): return super().__getitem__(keys) From 731b8a126edfd64a7ae76b0ab2a7bb002ae119ab Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Wed, 16 Oct 2024 14:54:01 +0400 Subject: [PATCH 57/59] fix: undef variable --- src/qibo/transpiler/unroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index 6394ff7d3c..ee6e15d0a1 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -23,7 +23,7 @@ class FlagMeta(EnumMeta): def __getitem__(cls, keys): if isinstance(keys, str): return super().__getitem__(keys) - return reduce(or_, [self[key] for key in keys]) # pylint: disable=E1136 + return reduce(or_, [cls[key] for key in keys]) # pylint: disable=E1136 class NativeGates(Flag, metaclass=FlagMeta): From 33a998486bb7fffdf8be0082e141e83a7a02e139 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Fri, 18 Oct 2024 13:02:03 +0400 Subject: [PATCH 58/59] fix: type hint update --- src/qibo/backends/abstract.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qibo/backends/abstract.py b/src/qibo/backends/abstract.py index 02fb4752fa..18b05c1193 100644 --- a/src/qibo/backends/abstract.py +++ b/src/qibo/backends/abstract.py @@ -31,13 +31,15 @@ def __repr__(self): @property @abc.abstractmethod - def qubits(self) -> Optional[list[str]]: # pragma: no cover + def qubits(self) -> Optional[list[int | str]]: # pragma: no cover """Return the qubit names of the backend. If :class:`SimulationBackend`, return None.""" raise_error(NotImplementedError) @property @abc.abstractmethod - def connectivity(self) -> Optional[list[tuple[str, str]]]: # pragma: no cover + def connectivity( + self, + ) -> Optional[list[tuple[int | str, int | str]]]: # pragma: no cover """Return the available qubit pairs of the backend. If :class:`SimulationBackend`, return None.""" raise_error(NotImplementedError) From 65bdfee7f5d30eb1b18cb31e54a28bac5bfd2e1a Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Fri, 18 Oct 2024 14:05:39 +0400 Subject: [PATCH 59/59] fix: type hint update for python3.9 --- src/qibo/backends/abstract.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/backends/abstract.py b/src/qibo/backends/abstract.py index 18b05c1193..ed10483823 100644 --- a/src/qibo/backends/abstract.py +++ b/src/qibo/backends/abstract.py @@ -31,7 +31,7 @@ def __repr__(self): @property @abc.abstractmethod - def qubits(self) -> Optional[list[int | str]]: # pragma: no cover + def qubits(self) -> Optional[list[Union[int, str]]]: # pragma: no cover """Return the qubit names of the backend. If :class:`SimulationBackend`, return None.""" raise_error(NotImplementedError) @@ -39,7 +39,7 @@ def qubits(self) -> Optional[list[int | str]]: # pragma: no cover @abc.abstractmethod def connectivity( self, - ) -> Optional[list[tuple[int | str, int | str]]]: # pragma: no cover + ) -> Optional[list[tuple[Union[int, str], Union[int, str]]]]: # pragma: no cover """Return the available qubit pairs of the backend. If :class:`SimulationBackend`, return None.""" raise_error(NotImplementedError)