Source code for pyqit.core.config
from contextvars import ContextVar
import logging
import numpy as np
from skbase.utils.dependencies import _check_soft_dependencies
logger = logging.getLogger("pyqit")
_BACKEND: ContextVar[str] = ContextVar("backend", default="pennylane")
_EXPLICITLY_SET: ContextVar[bool] = ContextVar("explicitly_set", default=False)
_WARNED_UNSET: ContextVar[bool] = ContextVar("warned_unset", default=False)
[docs]
def set_backend(backend: str):
"""Set the quantum computing backend for the current context.
Parameters
----------
backend : {"pennylane", "torch"}
Backend every object built afterwards will cache in ``__init__``.
Raises
------
ValueError
If ``backend`` is not a supported name.
ImportError
If ``backend`` is ``"torch"`` and torch is not installed. Checked here
because this is where the choice is made: every torch import downstream
is reached only through the backend being set, so without this the
failure surfaces later and unrecognisably.
"""
backend = backend.lower()
if backend not in ["pennylane", "torch"]:
raise ValueError(f"Unsupported backend '{backend}'.")
if backend == "torch" and not _check_soft_dependencies("torch", severity="none"):
raise ImportError(
"backend='torch' requires torch, which is not installed. "
"Install it with `pip install pyqit[all_extras]`, or stay on "
"backend='pennylane'."
)
_BACKEND.set(backend)
_EXPLICITLY_SET.set(True)
logger.info(f"Backend safely set to '{backend}' for current context.")
[docs]
def set_seed(seed: int) -> int:
"""Set the seed.
Seeds numpy and torch when it is installed.
Parameters
----------
seed : int
Value applied to every supported RNG.
Returns
-------
int
The seed that was applied.
Notes
-----
This mutates *global* RNG state, the same contract as Lightning's
``seed_everything``. ``Trainer.fit`` calls it for you; call it yourself
before constructing a model if you also want its initial weights to be
reproducible, since those are drawn at construction time.
"""
np.random.seed(seed)
seeded = ["numpy"]
if _check_soft_dependencies("torch", severity="none"):
import torch
torch.manual_seed(seed)
seeded.append("torch")
logger.info(f"Seeded {' and '.join(seeded)} with {seed}.")
return seed
[docs]
def get_backend() -> str:
"""Get the current quantum computing backend for the context."""
if not _EXPLICITLY_SET.get() and not _WARNED_UNSET.get():
logger.warning(
"No backend explicitly set for this context. Defaulting to 'pennylane'."
)
_WARNED_UNSET.set(True)
return _BACKEND.get()