Skip to main content
IBM Quantum Platform

Intégrer des ressources quantiques externes avec Qiskit

Le site Qiskit SDK est conçu pour aider les tiers à créer des fournisseurs externes de ressources quantiques.

Cela signifie que toute organisation qui développe ou déploie des ressources de calcul quantique peut intégrer ses services dans Qiskit et profiter de sa base d'utilisateurs.

Pour ce faire, il faut créer un paquet qui prenne en charge les demandes de ressources de calcul quantique et les renvoie à l'utilisateur.

En outre, le paquet doit permettre aux utilisateurs de soumettre des travaux et de récupérer leurs résultats par le biais d'une implémentation des objets qiskit.primitives .


Fournir l'accès aux backends

Pour que les utilisateurs puissent transpiler et exécuter des objets QuantumCircuit à l'aide de ressources externes, ils doivent instancier un objet contenant un Target qui fournit des informations sur les contraintes d'une QPU telles que sa connectivité, ses portes de base et le nombre de qubits. Cela peut se faire par le biais d'une interface similaire à celle qui permet à un utilisateur de demander une QPU QiskitRuntimeService par laquelle un utilisateur peut demander une QPU. Cet objet doit, au minimum, contenir une Target, mais une approche plus simple consisterait à renvoyer une BackendV2 instance.

Un exemple de mise en œuvre peut ressembler à quelque chose comme :

from qiskit.transpiler import Target
from qsikit.providers import BackendV2

class ProviderService:
    """ Class for interacting with a provider's service"""

    def __init__(
        self,
        #Receive arguments for authentication/instantiation
    ):
        """ Initiate a connection with the provider service, given some method 
                of authentication """

    def return_target(name: Str) -> Target:
        """ Interact with the service and return a Target object """
        return target

    def return_backend(name: Str) -> BackendV2:
        """ Interact with the service and return a BackendV2 object """
        return backend

Fournir une interface pour l'exécution

Outre un service permettant de récupérer les configurations matérielles, un service donnant accès à des ressources QPU externes pourrait également prendre en charge l'exécution de charges de travail quantiques. Pour exploiter cette fonctionnalité, il suffit de créer des implémentations des classes de base primitives de Qiskit; par exemple, BasePrimitiveJob, BaseEstimatorV2 et, BaseSamplerV2 entre autres. Ces interfaces doivent au minimum permettre d'exécuter une tâche, de consulter son état d'avancement et de renvoyer ses résultats.

Pour gérer l'état des travaux et les résultats, le site Qiskit SDK fournit une fonction DataBin, PubResult, PrimitiveResult,, et BasePrimitiveJob doivent être utilisés.

Voir la documentation de l'API qiskit.primitives ainsi que les implémentations de référence BackendEstimatorV2 et BackendSampleV2 pour plus d'informations.

Un exemple de mise en œuvre de la primitive Estimateur peut se présenter comme suit :

from qiskit.primitives import BaseEstimatorV2, BaseSamplerV2, EstimatorPubLike
from qiskit.primitives import DataBin, PubResult, PrimitiveResult, BasePrimitiveJob
from qiskit.providers import BackendV2

class EstimatorImplementation(BaseEstimatorV2):
    """ Class for interacting with the provider's Estimator service """

    def __init__(
        self,
        *,
        backend: BackendV2,
        options: dict
        # Receive other arguments to instantiate an Estimator primitive with the service
    ):
        self._backend = backend
        self._options = options
        self._default_precision = 0.01

    @property
    def backend(self) -> BackendV2:
        """ Return the backend """
        return self._backend

    def run(
        self, pubs: Iterable[EstimatorPubLike], *, precision: float | None = None
    ) -> BasePrimitiveJob[PrimitiveResult[PubResult]]:
    """ Steps to implement: 
            1. Define a default precision if none is given 
            2. Validate pub format
            3. Instantiate an object which inherits from BasePrimitiveJob 
                containing pub and runtime information
            4. Send the job to the execution service of the provider
    """
    job = BasePrimitiveJob(pubs, precision)
    job_with_results = job.submit()
    return job_with_results

Une implémentation de la primitive Sampler peut ressembler à ce qui suit :

class SamplerImplementation(BaseSamplerV2):
    """ Class for interacting with the provider's Sampler service """

    def __init__(
        self,
        *,
        backend: BackendV2,
        options: dict
        # Receive other arguments to instantiate an Estimator primitive with the service
    ):
        self._backend = backend
        self._options = options
        self._default_shots = 1024

    @property
    def backend(self) -> BackendV2:
        """ Return the Sampler's backend """
        return self._backend

    def run(
        self, pubs: Iterable[SamplerPubLike], *, shots: int | None = None
    ) -> BasePrimitiveJob[PrimitiveResult[SamplerPubResult]]:
    """ Steps to implement: 
            1. Define a default number of shots if none is given 
            2. Validate pub format
            3. Instantiate an object which inherits from BasePrimitiveJob 
                containing pub and runtime information
            4. Send the job to the execution service of the provider
            5. Return the data in some format
    """
    job = BasePrimitiveJob(pubs, shots)
    job_with_results = job.submit()
    return job_with_results
Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.