Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal global backend _Global #1440

Merged
merged 69 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
bdbdc7e
GlobalBackend -> _Global
Sep 9, 2024
98d07ff
GlobalBackend -> _Global
Sep 9, 2024
b3fcc2a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 9, 2024
f8a3cfc
disable not callable error
Sep 9, 2024
5b312bf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 9, 2024
4697a9f
disable not callable error
Sep 9, 2024
e58157b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 9, 2024
583d26b
fix bug
Sep 10, 2024
2419d7d
add funcs
Sep 10, 2024
e8126a2
Merge branch 'master' into qibo_global
Sep 16, 2024
32ed23a
update test funcs
Sep 16, 2024
435c5f5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 16, 2024
94cb879
update review
Sep 18, 2024
53fa831
Merge branch 'master' into qibo_global
Oct 1, 2024
efb22c5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 1, 2024
b2f82d5
update test files
Oct 7, 2024
c828f67
Merge branch 'master' into qibo_global
Oct 7, 2024
8b3a95a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
352015b
fix test
Oct 7, 2024
59b0c71
qcnn.py get_backend -> get_backend_name
Oct 7, 2024
907bebb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
7cd16a4
remove resolve_global
Oct 7, 2024
a3c993d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
79ef360
remove resolve_global
Oct 7, 2024
b3614a4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
69189f4
remove resolve_global
Oct 7, 2024
0f68533
fix test_backends_global
Oct 7, 2024
b9b10d7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
2dc6797
add reset_global
Oct 7, 2024
cf39210
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 7, 2024
b7209ad
add reset global
Oct 7, 2024
f0a4c4c
Merge branch 'qibo_global' of github.com:qiboteam/qibo into qibo_global
Oct 8, 2024
c6391b6
fix error mitigation
Oct 8, 2024
23f6054
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 8, 2024
a63fbe9
update docs (replace 'GlobalBackend')
Oct 8, 2024
a3083d7
Merge branch 'qibo_global' of github.com:qiboteam/qibo into qibo_global
Oct 8, 2024
15be594
coverage
Oct 8, 2024
6a1c921
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 8, 2024
d4670f6
fix test_set_get_transpiler
Oct 8, 2024
6b04315
Merge branch 'qibo_global' of github.com:qiboteam/qibo into qibo_global
Oct 8, 2024
5c32260
Merge branch 'master' into qibo_global
Oct 8, 2024
dcd318a
add clear in conftest.py
Oct 9, 2024
3e99140
pytest autouse & default transpiler prototype
Oct 9, 2024
535c5a4
hw backend prototype
Oct 10, 2024
eba4f5e
hw backend prototype
Oct 10, 2024
5613c4c
fix: hw attributes check
Oct 11, 2024
b44c13a
fix: temporary _default_transpiler for current transpiler
Oct 14, 2024
11548da
feat: create NativeGates from list[str]
Oct 14, 2024
fcfb579
Merge branch 'master' into qibo_global
Oct 14, 2024
e0292cc
fix: return value of default transpiler
Oct 14, 2024
3c29f61
feat: test files for _Global._default_transpiler
Oct 15, 2024
3eeff46
fix: unused import/vars
Oct 15, 2024
a4ee205
fix: else after return
Oct 15, 2024
be12cf9
fix: improve star/line/grid connectivity helper functions
Oct 15, 2024
84dc20c
fix: remove Nativegates.from_gate(str)
Oct 15, 2024
bdb31b5
fix: remove _Global._backend usage / deprecate get_backend_name
Oct 15, 2024
6fe4205
fix: remove pragma / improve _execute_circuit in error_mitigation.py
Oct 15, 2024
9e7cc6b
fix: add pragma
Oct 15, 2024
8c02e78
Merge branch 'master' into qibo_global
Oct 15, 2024
6c77fde
fix: minor docstring update
Oct 16, 2024
e913307
feat: enable initializing NativeGates from list[str]
Oct 16, 2024
933f08c
fix: pylint error
Oct 16, 2024
08107cd
fix: Flag OR operation in FlagMeta
Oct 16, 2024
0990076
fix: Restore previous flag meta implementation
alecandido Oct 16, 2024
5d260e3
fix: add docstring in FlagMeta
Oct 16, 2024
3bc74dd
Merge branch 'qibo_global' of github.com:qiboteam/qibo into qibo_global
Oct 16, 2024
731b8a1
fix: undef variable
Oct 16, 2024
33a9984
fix: type hint update
Oct 18, 2024
65bdfee
fix: type hint update for python3.9
Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/source/code-examples/advancedexamples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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()
csookim marked this conversation as resolved.
Show resolved Hide resolved

# Define the observable
obs = np.prod([Z(i) for i in range(nqubits)])
Expand Down
98 changes: 70 additions & 28 deletions src/qibo/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ 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
_dtypes = {"double": "complex128", "single": "complex64"}
_default_order = [
{"backend": "qibojit", "platform": "cupy"},
Expand All @@ -78,39 +78,73 @@ 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):
csookim marked this conversation as resolved.
Show resolved Hide resolved
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
csookim marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
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
csookim marked this conversation as resolved.
Show resolved Hide resolved
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}")
else:
log.info(f"Backend {backend} is already loaded.")
csookim marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def get_backend(cls):
return cls._backend
csookim marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def transpiler(cls): # pragma: no cover
csookim marked this conversation as resolved.
Show resolved Hide resolved
from qibo.transpiler.pipeline import Passes
alecandido marked this conversation as resolved.
Show resolved Hide resolved

if cls._transpiler is not None:
return cls._transpiler

cls._transpiler = Passes(passes=[])
csookim marked this conversation as resolved.
Show resolved Hide resolved
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): # pragma: no cover
return cls._transpiler
csookim marked this conversation as resolved.
Show resolved Hide resolved

@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:
Expand Down Expand Up @@ -147,24 +181,32 @@ def create(self, dtype):


def get_backend():
return str(GlobalBackend())
return str(_Global.get_backend())
csookim marked this conversation as resolved.
Show resolved Hide resolved


def set_backend(backend, **kwargs):
csookim marked this conversation as resolved.
Show resolved Hide resolved
GlobalBackend.set_backend(backend, **kwargs)
_Global.set_backend(backend, **kwargs)


def get_transpiler():
return str(_Global.get_transpiler())
csookim marked this conversation as resolved.
Show resolved Hide resolved


def set_transpiler(transpiler):
_Global.set_transpiler(transpiler)


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
csookim marked this conversation as resolved.
Show resolved Hide resolved


def set_device(device):
Expand All @@ -174,26 +216,26 @@ def set_device(device):
ValueError,
"Device name should follow the pattern: /{device type}:{device number}.",
)
backend = GlobalBackend()
backend = _Global.get_backend()
csookim marked this conversation as resolved.
Show resolved Hide resolved
backend.set_device(device)
log.info(f"Using {backend} backend on {backend.device}")


def get_threads():
return GlobalBackend().nthreads
return _Global.get_backend().nthreads
csookim marked this conversation as resolved.
Show resolved Hide resolved


def set_threads(nthreads):
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.")
GlobalBackend().set_threads(nthreads)
_Global.get_backend().set_threads(nthreads)
csookim marked this conversation as resolved.
Show resolved Hide resolved


def _check_backend(backend):
if backend is None:
return GlobalBackend()
return _Global.backend()

return backend

Expand Down
14 changes: 10 additions & 4 deletions src/qibo/models/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,14 +1099,20 @@ def execute(self, initial_state=None, nshots=1000):
self._final_state = self.compiled.result(state, nshots)
return self._final_state
else:
csookim marked this conversation as resolved.
Show resolved Hide resolved
from qibo.backends import GlobalBackend
from qibo.backends import _Global
csookim marked this conversation as resolved.
Show resolved Hide resolved

_Global.resolve_global()
transpiler = _Global.get_transpiler()
transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102

if self.accelerators: # pragma: no cover
return GlobalBackend().execute_distributed_circuit(
self, initial_state, nshots
return _Global.get_backend().execute_distributed_circuit(
csookim marked this conversation as resolved.
Show resolved Hide resolved
transpiled_circuit, initial_state, nshots
)
else:
csookim marked this conversation as resolved.
Show resolved Hide resolved
return GlobalBackend().execute_circuit(self, initial_state, nshots)
return _Global.get_backend().execute_circuit(
csookim marked this conversation as resolved.
Show resolved Hide resolved
transpiled_circuit, initial_state, nshots
)

def __call__(self, initial_state=None, nshots=1000):
"""Equivalent to ``circuit.execute``."""
Expand Down
5 changes: 3 additions & 2 deletions src/qibo/models/error_mitigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 _check_backend, _check_backend_and_local_state, _Global
from qibo.config import raise_error


Expand Down Expand Up @@ -1095,8 +1095,9 @@ 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
# TODO: Use _Global.set_transpiler
backend.transpiler.passes[1] = Custom(
initial_map=qubit_map, connectivity=backend.platform.topology
)
Expand Down
10 changes: 6 additions & 4 deletions tests/test_backends_clifford.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
from qibo import Circuit, gates, set_backend
from qibo.backends import (
CliffordBackend,
GlobalBackend,
NumpyBackend,
PyTorchBackend,
TensorflowBackend,
_Global,
)
from qibo.backends.clifford import _get_engine_name
from qibo.noise import DepolarizingError, NoiseModel, PauliError
Expand All @@ -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
csookim marked this conversation as resolved.
Show resolved Hide resolved
assert global_platform == platform


Expand All @@ -46,7 +46,9 @@ 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
csookim marked this conversation as resolved.
Show resolved Hide resolved
)
assert clifford_bkd.platform == target
set_backend("numpy")
Expand Down
56 changes: 51 additions & 5 deletions tests/test_backends_global.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import networkx as nx
import pytest

import qibo
from qibo import matrices


def test_set_backend():
from qibo.backends import GlobalBackend
def test_set_get_backend():
from qibo.backends import _Global

backend = GlobalBackend()
backend = _Global.backend()
csookim marked this conversation as resolved.
Show resolved Hide resolved
qibo.set_backend("numpy")
assert qibo.get_backend() == "numpy"
assert GlobalBackend().name == "numpy"
assert _Global.get_backend().name == "numpy"


def test_set_precision():
Expand Down Expand Up @@ -104,7 +105,52 @@ 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__


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]
csookim marked this conversation as resolved.
Show resolved Hide resolved
chip.add_edges_from(graph_list)
return chip


def test_set_get_transpiler():
from qibo.backends import _Global
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,
passes=[
Preprocessing(connectivity),
Random(connectivity, seed=0),
Sabre(connectivity),
Unroller(NativeGates.default()),
],
)

_Global.set_transpiler(transpiler)
assert _Global.get_transpiler() == transpiler
6 changes: 4 additions & 2 deletions tests/test_backends_qibotn.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import os

import qibo
from qibo.backends import _Global

# Force quimb to use qibojit default number of threads.
_Global.backend()
csookim marked this conversation as resolved.
Show resolved Hide resolved
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
csookim marked this conversation as resolved.
Show resolved Hide resolved


def test_backend_qibotn():
qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=None)
assert isinstance(GlobalBackend(), QuimbBackend)
assert isinstance(_Global.get_backend(), QuimbBackend)
csookim marked this conversation as resolved.
Show resolved Hide resolved

qibo.set_backend("numpy")
4 changes: 2 additions & 2 deletions tests/test_backends_qulacs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from qibo import Circuit, gates
from qibo.backends import GlobalBackend, 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()
Expand Down Expand Up @@ -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"
csookim marked this conversation as resolved.
Show resolved Hide resolved
Loading