diff --git a/doc/source/api-reference/qibo.rst b/doc/source/api-reference/qibo.rst index a128558d80..fa29757bc2 100644 --- a/doc/source/api-reference/qibo.rst +++ b/doc/source/api-reference/qibo.rst @@ -2655,7 +2655,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/doc/source/code-examples/advancedexamples.rst b/doc/source/code-examples/advancedexamples.rst index 572342f79f..8a3736b99c 100644 --- a/doc/source/code-examples/advancedexamples.rst +++ b/doc/source/code-examples/advancedexamples.rst @@ -1297,9 +1297,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 GlobalBackend - backend = GlobalBackend() + backend = qibo.get_backend() # Define the observable obs = np.prod([Z(i) for i in range(nqubits)]) @@ -2103,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/src/qibo/__init__.py b/src/qibo/__init__.py index bcd912f1cc..5610cf493f 100644 --- a/src/qibo/__init__.py +++ b/src/qibo/__init__.py @@ -19,12 +19,15 @@ get_device, get_precision, get_threads, + get_transpiler, + get_transpiler_name, list_available_backends, matrices, set_backend, set_device, set_precision, set_threads, + set_transpiler, ) from qibo.config import ( get_batch_size, diff --git a/src/qibo/backends/__init__.py b/src/qibo/backends/__init__.py index 136db6e7c5..f666bdcd6c 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 @@ -65,10 +66,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 + # TODO: resolve circular import with qibo.transpiler.pipeline.Passes - _instance = None _dtypes = {"double": "complex128", "single": "complex64"} _default_order = [ {"backend": "qibojit", "platform": "cupy"}, @@ -78,39 +80,88 @@ class GlobalBackend(NumpyBackend): {"backend": "pytorch"}, ] - def __new__(cls): - if cls._instance is not None: - return cls._instance + @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() + log.info(f"Using {cls._backend} backend on {cls._backend.device}") + return cls._backend - backend = os.environ.get("QIBO_BACKEND") - if backend: # pragma: no cover + @classmethod + def _create_backend(cls): + backend_env = os.environ.get("QIBO_BACKEND") + if backend_env: # pragma: no cover # Create backend specified by user platform = os.environ.get("QIBO_PLATFORM") - cls._instance = 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._instance = construct_backend(**kwargs) + backend = construct_backend(**kwargs) break except (ImportError, MissingBackend): pass - if cls._instance is None: # pragma: no cover + if backend is None: # pragma: no cover raise_error(RuntimeError, "No backends available.") + return backend + + @classmethod + def set_backend(cls, backend, **kwargs): + cls._backend = construct_backend(backend, **kwargs) + log.info(f"Using {cls._backend} backend on {cls._backend.device}") - log.info(f"Using {cls._instance} backend on {cls._instance.device}") - return cls._instance + @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 set_backend(cls, backend, **kwargs): # pragma: no cover + def _default_transpiler(cls): + 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 NativeGates, Unroller + + qubits = cls._backend.qubits + natives = cls._backend.natives + connectivity_edges = cls._backend.connectivity if ( - cls._instance is None - or cls._instance.name != backend - or cls._instance.platform != kwargs.get("platform") + qubits is not None + and natives is not None + and connectivity_edges is not None ): - cls._instance = construct_backend(backend, **kwargs) - log.info(f"Using {cls._instance} backend on {cls._instance.device}") + # 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) + + return Passes( + connectivity=connectivity, + passes=[ + Preprocessing(connectivity), + Trivial(connectivity), + Sabre(connectivity), + Unroller(NativeGates[natives]), + ], + ) + + return Passes(passes=[]) class QiboMatrices: @@ -147,53 +198,97 @@ def create(self, dtype): def get_backend(): - return str(GlobalBackend()) + """Get the current backend.""" + return _Global.backend() def set_backend(backend, **kwargs): - GlobalBackend.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(): + """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()) + + +def set_transpiler(transpiler): + """Set the current transpiler. + + Args: + transpiler (Passes): The transpiler to use. + """ + _Global.set_transpiler(transpiler) def get_precision(): - return GlobalBackend().precision + """Get the precision of the backend.""" + return get_backend().precision def set_precision(precision): - GlobalBackend().set_precision(precision) - matrices.create(GlobalBackend().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 GlobalBackend().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 = GlobalBackend() + backend = get_backend() backend.set_device(device) log.info(f"Using {backend} backend on {backend.device}") def get_threads(): - return GlobalBackend().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.") - GlobalBackend().set_threads(nthreads) + get_backend().set_threads(nthreads) def _check_backend(backend): if backend is None: - return GlobalBackend() + return get_backend() return backend diff --git a/src/qibo/backends/abstract.py b/src/qibo/backends/abstract.py index 9e43261200..ed10483823 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,26 @@ def __repr__(self): else: return f"{self.name} ({self.platform})" + @property + @abc.abstractmethod + 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) + + @property + @abc.abstractmethod + def connectivity( + self, + ) -> 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) + + @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 bda83e75cd..ff56669ccf 100644 --- a/src/qibo/backends/numpy.py +++ b/src/qibo/backends/numpy.py @@ -34,6 +34,18 @@ def __init__(self): np.complex128, ) + @property + def qubits(self): + return None + + @property + def connectivity(self): + return None + + @property + def natives(self): + return None + def set_precision(self, precision): if precision != self.precision: if precision == "single": diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 7573f0052f..a2919c9f95 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -399,7 +399,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 ba4f285df2..2d178c1831 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/circuit.py b/src/qibo/models/circuit.py index 35d18100a6..9b3916b3ae 100644 --- a/src/qibo/models/circuit.py +++ b/src/qibo/models/circuit.py @@ -7,6 +7,7 @@ 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 @@ -1099,15 +1100,16 @@ 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 GlobalBackend - if self.accelerators: # pragma: no cover - return GlobalBackend().execute_distributed_circuit( - self, initial_state, nshots - ) - else: - return GlobalBackend().execute_circuit(self, initial_state, nshots) + backend = _Global.backend() + transpiler = _Global.transpiler() + transpiled_circuit, _ = transpiler(self) # pylint: disable=E1102 + + if self.accelerators: # pragma: no cover + return backend.execute_distributed_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/src/qibo/models/error_mitigation.py b/src/qibo/models/error_mitigation.py index 60a7da94af..289cf2b7c7 100644 --- a/src/qibo/models/error_mitigation.py +++ b/src/qibo/models/error_mitigation.py @@ -4,11 +4,12 @@ from inspect import signature from itertools import product +import networkx as nx import numpy as np 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, get_backend from qibo.config import raise_error @@ -173,7 +174,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: @@ -237,7 +238,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: @@ -388,7 +389,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: @@ -503,7 +504,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: @@ -631,7 +632,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: @@ -735,7 +736,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: @@ -877,7 +878,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: @@ -941,7 +942,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: @@ -1163,17 +1164,24 @@ 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 if backend is None: # pragma: no cover - backend = GlobalBackend() + backend = get_backend() elif backend.name == "qibolab": # pragma: no cover - backend.transpiler.passes[1] = Custom( - initial_map=qubit_map, connectivity=backend.platform.topology + 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: circuit = noise_model.apply(circuit) circuit_result = backend.execute_circuit(circuit, nshots=nshots) - return circuit_result diff --git a/src/qibo/models/qcnn.py b/src/qibo/models/qcnn.py index 1066971fa6..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 +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(): + if "qibojit" in str(get_backend()): self.copy_init_state = True else: self.copy_init_state = False 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 dae0ac2535..131d3b26d1 100644 --- a/src/qibo/quantum_info/basis.py +++ b/src/qibo/quantum_info/basis.py @@ -38,7 +38,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`` @@ -177,7 +177,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``, @@ -252,7 +252,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 dbd2cb4508..3851739e4c 100644 --- a/src/qibo/quantum_info/entanglement.py +++ b/src/qibo/quantum_info/entanglement.py @@ -28,7 +28,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: @@ -98,7 +98,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``. @@ -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: @@ -179,7 +179,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: @@ -247,7 +247,7 @@ def meyer_wallach_entanglement(state, backend=None): Args: state (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: @@ -315,7 +315,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 e5e667ff64..e424a09089 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 625051a9f3..33cc494515 100644 --- a/src/qibo/quantum_info/linalg_operations.py +++ b/src/qibo/quantum_info/linalg_operations.py @@ -109,7 +109,7 @@ def partial_trace( 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). @@ -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}}`. @@ -267,7 +267,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`. @@ -290,7 +290,7 @@ def matrix_power( Used when ``power`` is negative. 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}`. @@ -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 6fb1073234..a6ca2535f5 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: @@ -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: @@ -174,7 +174,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: @@ -229,7 +229,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: @@ -335,7 +335,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: @@ -360,7 +360,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: @@ -391,7 +391,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: @@ -421,7 +421,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: @@ -492,7 +492,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``. @@ -529,7 +529,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: @@ -564,7 +564,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: @@ -612,7 +612,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 @@ -734,7 +734,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: @@ -798,7 +798,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: @@ -851,7 +851,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 bae06d6402..da277cb272 100644 --- a/src/qibo/quantum_info/superoperator_transformations.py +++ b/src/qibo/quantum_info/superoperator_transformations.py @@ -38,7 +38,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``. @@ -119,7 +119,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``. @@ -179,7 +179,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. @@ -205,7 +205,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. @@ -242,7 +242,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. @@ -286,7 +286,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. @@ -332,7 +332,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. @@ -363,7 +363,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. @@ -436,7 +436,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 @@ -562,7 +562,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. """ @@ -618,7 +618,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. @@ -675,7 +675,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. @@ -721,7 +721,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. @@ -757,7 +757,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. @@ -803,7 +803,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. @@ -867,7 +867,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. @@ -951,7 +951,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. @@ -982,7 +982,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. @@ -1039,7 +1039,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. @@ -1082,7 +1082,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. @@ -1141,7 +1141,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. @@ -1183,7 +1183,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. @@ -1235,7 +1235,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. @@ -1277,7 +1277,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. @@ -1312,7 +1312,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. @@ -1372,7 +1372,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. @@ -1427,7 +1427,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. @@ -1472,7 +1472,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. @@ -1518,7 +1518,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. @@ -1581,7 +1581,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. @@ -1659,7 +1659,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. @@ -1715,7 +1715,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. @@ -1771,7 +1771,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. @@ -1831,7 +1831,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. @@ -1892,7 +1892,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. @@ -1989,7 +1989,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. @@ -2044,7 +2044,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. @@ -2148,7 +2148,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: diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index d3b564884b..ee6e15d0a1 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,16 @@ ) -class NativeGates(Flag): +class FlagMeta(EnumMeta): + """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) + return reduce(or_, [cls[key] for key in keys]) # pylint: disable=E1136 + + +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 @@ -57,12 +68,11 @@ 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`.""" if isinstance(gate, gates.Gate): return cls.from_gate(gate.__class__) - try: return getattr(cls, gate.__name__) except AttributeError: diff --git a/tests/conftest.py b/tests/conftest.py index 538ed7a1e5..db51f97456 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,13 @@ def backend(backend_name): yield get_backend(backend_name) +@pytest.fixture(autouse=True) +def clear(): + yield + _Global._backend = None + _Global._transpiler = None + + def pytest_generate_tests(metafunc): module_name = metafunc.module.__name__ diff --git a/tests/test_backends_clifford.py b/tests/test_backends_clifford.py index 5e4bae9d64..2760ff015b 100644 --- a/tests/test_backends_clifford.py +++ b/tests/test_backends_clifford.py @@ -5,10 +5,9 @@ import numpy as np import pytest -from qibo import Circuit, gates, set_backend +from qibo import Circuit, gates, get_backend, set_backend from qibo.backends import ( CliffordBackend, - GlobalBackend, NumpyBackend, PyTorchBackend, TensorflowBackend, @@ -36,8 +35,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(get_backend(), CliffordBackend) + global_platform = get_backend().platform assert global_platform == platform @@ -45,11 +44,8 @@ def test_global_backend(backend): construct_clifford_backend(backend) set_backend(backend.name, platform=backend.platform) clifford_bkd = CliffordBackend() - target = ( - GlobalBackend().name if backend.name == "numpy" else GlobalBackend().platform - ) + target = get_backend().name if backend.name == "numpy" else get_backend().platform assert clifford_bkd.platform == target - set_backend("numpy") THETAS_1Q = [ diff --git a/tests/test_backends_global.py b/tests/test_backends_global.py index 9ad3a4b2f4..45f990eb76 100644 --- a/tests/test_backends_global.py +++ b/tests/test_backends_global.py @@ -1,16 +1,21 @@ +import networkx as nx import pytest import qibo from qibo import matrices +from qibo.backends import _Global, get_backend +from qibo.backends.numpy import NumpyBackend +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_backend(): - from qibo.backends import GlobalBackend - - backend = GlobalBackend() +def test_set_get_backend(): qibo.set_backend("numpy") - assert qibo.get_backend() == "numpy" - assert GlobalBackend().name == "numpy" + assert str(qibo.get_backend()) == "numpy" + assert qibo.get_backend().name == "numpy" def test_set_precision(): @@ -83,14 +88,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): @@ -103,8 +108,72 @@ def test_check_backend(backend): # testing when backend is None test = None test = qibo.backends._check_backend(test) - - target = qibo.backends.GlobalBackend() + target = get_backend() assert test.name == target.name assert test.__class__ == target.__class__ + + +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(): + connectivity = _star_connectivity() + transpiler = Passes( + connectivity=connectivity, + passes=[ + Preprocessing(connectivity), + Random(connectivity, seed=0), + Sabre(connectivity), + Unroller(NativeGates.default()), + ], + ) + + qibo.set_transpiler(transpiler) + assert qibo.get_transpiler() == transpiler + assert qibo.get_transpiler_name() == str(transpiler) + + +def test_default_transpiler_sim(): + backend = NumpyBackend() + 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 + ) diff --git a/tests/test_backends_qibotn.py b/tests/test_backends_qibotn.py index ae850afefa..d2aba6f3c2 100644 --- a/tests/test_backends_qibotn.py +++ b/tests/test_backends_qibotn.py @@ -1,16 +1,14 @@ import os -import qibo +from qibo import get_backend, get_threads, set_backend # Force quimb to use qibojit default number of threads. -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 GlobalBackend - def test_backend_qibotn(): - qibo.set_backend(backend="qibotn", platform="qutensornet", runcard=None) - assert isinstance(GlobalBackend(), 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 48f7c6d65c..9ef0d8a9bd 100644 --- a/tests/test_backends_qulacs.py +++ b/tests/test_backends_qulacs.py @@ -3,8 +3,8 @@ import numpy as np import pytest -from qibo import Circuit, gates -from qibo.backends import GlobalBackend, MetaBackend, NumpyBackend, set_backend +from qibo import Circuit, gates, get_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,4 +40,4 @@ def test_initial_state_error(): def test_set_backend(): set_backend("qulacs") - assert GlobalBackend().name == "qulacs" + assert get_backend().name == "qulacs" diff --git a/tests/test_models_qcnn.py b/tests/test_models_qcnn.py index 45dfe9292e..5c5c9230a4 100644 --- a/tests/test_models_qcnn.py +++ b/tests/test_models_qcnn.py @@ -2,7 +2,6 @@ import numpy as np -import qibo from qibo import gates, set_backend from qibo.models import Circuit from qibo.models.qcnn import QuantumCNN @@ -320,7 +319,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)) 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 diff --git a/tests/test_transpiler_unroller.py b/tests/test_transpiler_unroller.py index 474d2c50a3..d3aa3e9ba9 100644 --- a/tests/test_transpiler_unroller.py +++ b/tests/test_transpiler_unroller.py @@ -21,6 +21,16 @@ def test_native_gates_from_gatelist_fail(): NativeGates.from_gatelist([gates.RZ, gates.X(0)]) +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(): natives = NativeGates(0) with pytest.raises(DecompositionError):