Source code for qnexus.client.devices

"""Client API for devices in Nexus."""

from enum import Enum
from typing import Literal

from qnexus.client import get_nexus_client
from qnexus.exceptions import ResourceFetchFailed
from qnexus.models import (
    BackendConfig,
    Credential,
    Device,
    IssuerEnum,
    QuantinuumConfig,
    StoredBackendInfo,
    issuer_enum_to_config_str,
)
from qnexus.models.filters import DevicesFilter
from qnexus.models.references import DataframableList


[docs] class DeviceStateEnum(str, Enum): """Quantinuum Systems Device status enum.""" ONLINE = "online" OFFLINE = "offline" MAINTENANCE = "in maintenance" RESERVED_ONLINE = "online, reserved" RESERVED_MAINTENANCE = "in maintenance, reserved" RESERVED_OFFLINE = "offline, reserved"
class Params(DevicesFilter): """Params for filtering devices."""
[docs] def get_all( issuers: list[IssuerEnum] | None = None, aws_region: str | None = None, ibmq_hub: str | None = None, ibmq_group: str | None = None, ibmq_project: str | None = None, credentials: list[Credential] | None = None, credential_names: list[str] | None = None, nexus_hosted: bool | None = None, ) -> DataframableList[Device]: """Get all available devices.""" issuer_config_names = ( [ config_str for issuer in issuers for config_str in issuer_enum_to_config_str(issuer) ] if issuers else [] ) params = Params( backend=issuer_config_names if issuer_config_names else None, region=aws_region, ibmq_hub=ibmq_hub, ibmq_group=ibmq_group, ibmq_project=ibmq_project, credential_ids=[cred.id for cred in credentials] if credentials else None, credential_names=credential_names, is_local=nexus_hosted, ).model_dump(by_alias=True, exclude_unset=True, exclude_none=True) res = get_nexus_client().get( "/api/v5/available_devices", params=params, ) if res.status_code != 200: raise ResourceFetchFailed(message=res.text, status_code=res.status_code) device_list: DataframableList[Device] = DataframableList([]) for backendinfolist in res.json(): for backend_info in backendinfolist["backend_info_list"]: # Clean up the backend name for user consumption backend_name = backend_info["name"].replace("Backend", "") backend_name = backend_name.replace("EmulatorEnabled", "") device_list.append( Device( backend_name=backend_name, device_name=backend_info["device_name"], nexus_hosted=backendinfolist["is_local"], stored_backend_info=StoredBackendInfo(**backend_info), ) ) return device_list
[docs] def supports_shots(backend_config: BackendConfig) -> bool: """Does the backend configuration support shots?""" return _get_backend_property(backend_config, "supports_shots")
[docs] def supports_counts(backend_config: BackendConfig) -> bool: """Does the backend configuration support shots?""" return _get_backend_property(backend_config, "supports_counts")
[docs] def supports_state(backend_config: BackendConfig) -> bool: """Does the backend configuration support statevector results?""" return _get_backend_property(backend_config, "supports_state")
[docs] def supports_unitary(backend_config: BackendConfig) -> bool: """Does the backend configuration support a unitary?""" return _get_backend_property(backend_config, "supports_unitary")
[docs] def supports_density_matrix(backend_config: BackendConfig) -> bool: """Does the backend configuration support density matrix results?""" return _get_backend_property(backend_config, "supports_density_matrix")
[docs] def supports_expectation(backend_config: BackendConfig) -> bool: """Does the backend configuration support expectation values?""" return _get_backend_property(backend_config, "supports_expectation")
[docs] def expectation_allows_nonhermitian(backend_config: BackendConfig) -> bool: """Does the backend configuration support expectation_allows_nonhermitian?""" return _get_backend_property(backend_config, "expectation_allows_nonhermitian")
[docs] def supports_contextual_optimisation(backend_config: BackendConfig) -> bool: """Does the backend configuration support TKET contextual optimization?""" return _get_backend_property(backend_config, "supports_contextual_optimisation")
[docs] def status(backend_config: QuantinuumConfig) -> DeviceStateEnum: """Get the status of a hardware-hosted Quantinuum Systems device, such as whether is it online or offline. Please note this operation is not supported for cloud-hosted emulators, which can be assumed to be always online. """ assert isinstance(backend_config, QuantinuumConfig), ( "Operation only supported for QuantinuumConfig." ) res = get_nexus_client().get( f"/api/machines/v1beta/{backend_config.device_name}/status", ) if res.status_code != 200: raise ResourceFetchFailed(message=res.text, status_code=res.status_code) return DeviceStateEnum(res.json()["state"])
def _get_backend_property( backend_config: BackendConfig, backend_property: Literal[ "supports_shots", "supports_counts", "supports_state", "supports_unitary", "supports_density_matrix", "supports_expectation", "expectation_allows_nonhermitian", "supports_contextual_optimisation", ], ) -> bool: """Retrieves a Backend property for a given BackendConfig.""" res = get_nexus_client().post( "/api/v5/backend_info/backend_property", json={ "backend_config": backend_config.model_dump(), "property": backend_property, }, ) if res.status_code != 200: raise ResourceFetchFailed(message=res.text, status_code=res.status_code) property_value: bool = res.json() return property_value