diff --git a/src/qibotn/backends/__init__.py b/src/qibotn/backends/__init__.py index 4942a45..11eaf02 100644 --- a/src/qibotn/backends/__init__.py +++ b/src/qibotn/backends/__init__.py @@ -1,5 +1,50 @@ -import importlib.metadata as im +from typing import Union -from qibotn.backends import MetaBackend +from qibo.config import raise_error -__version__ = im.version(__package__) +from qibotn.backends.abstract import QibotnBackend +from qibotn.backends.cutensornet import CuTensorNet # pylint: disable=E0401 +from qibotn.backends.quimb import QuimbBackend # pylint: disable=E0401 + +PLATFORMS = ("cutensornet", "qutensornet", "qmatchatea") + + +class MetaBackend: + """Meta-backend class which takes care of loading the qibotn backends.""" + + @staticmethod + def load(platform: str, runcard: dict = None) -> QibotnBackend: + """Loads the backend. + + Args: + platform (str): Name of the backend to load: either `cutensornet` or `qutensornet`. + runcard (dict): Dictionary containing the simulation settings. + Returns: + qibo.backends.abstract.Backend: The loaded backend. + """ + + if platform == "cutensornet": # pragma: no cover + return CuTensorNet(runcard) + elif platform == "quimb": # pragma: no cover + return QuimbBackend(runcard) + elif platform == "qmatchatea": # pragma: no cover + from qibotn.backends.qmatchatea import QMatchaTeaBackend + + return QMatchaTeaBackend() + else: + raise_error( + NotImplementedError, + f"Unsupported platform {platform}, please pick one in {PLATFORMS}", + ) + + def list_available(self) -> dict: + """Lists all the available qibotn backends.""" + available_backends = {} + for platform in PLATFORMS: + try: + MetaBackend.load(platform=platform) + available = True + except: + available = False + available_backends[platform] = available + return available_backends \ No newline at end of file diff --git a/src/qibotn/backends/quimb.py b/src/qibotn/backends/quimb.py index b3b0b72..d55bbab 100644 --- a/src/qibotn/backends/quimb.py +++ b/src/qibotn/backends/quimb.py @@ -24,6 +24,7 @@ class QuimbBackend(QibotnBackend, NumpyBackend): self, ansatz: str = "MPS", max_bond_dimension: int = 10, + n_most_frequent_states: int = 100, ): """ Configure tensor network simulation. @@ -40,6 +41,7 @@ class QuimbBackend(QibotnBackend, NumpyBackend): """ self.ansatz = ansatz self.max_bond_dimension = max_bond_dimension + self.n_most_frequent_states = n_most_frequent_states def setup_backend_specifics(self, qimb_backend="numpy"): """Setup backend specifics. @@ -69,6 +71,8 @@ class QuimbBackend(QibotnBackend, NumpyBackend): The number of shots for sampling the circuit. If None, no sampling is performed, and the full statevector is used. return_array : bool, optional If True, returns the statevector as a dense array. Default is False. + n_most_frequent_states : int, optional + The number of most frequent computational basis states to return. Default is 100. **prob_kwargs : dict, optional Additional keyword arguments for probability computation (currently unused). @@ -109,9 +113,7 @@ class QuimbBackend(QibotnBackend, NumpyBackend): ) frequencies = Counter(circ_quimb.sample(nshots)) if nshots is not None else None - main_frequencies = { - state: count for state, count in frequencies.most_common(n=100) - } + main_frequencies = {state: count for state, count in frequencies.most_common(self.n_most_frequent_states)} computational_states = [state for state in main_frequencies.keys()] amplitudes = { state: circ_quimb.amplitude(state) for state in computational_states