Integre recursos quânticos externos com o Qiskit
O site Qiskit SDK foi desenvolvido para dar suporte a terceiros na criação de provedores externos de recursos quânticos.
Isso significa que qualquer organização que desenvolva ou implante recursos de computação quântica pode integrar seus serviços ao Qiskit e aproveitar sua base de usuários.
Para isso, é necessário criar um pacote que ofereça suporte a solicitações de recursos de computação quântica e os retorne ao usuário.
Além disso, o pacote deve permitir que os usuários enviem trabalhos e recuperem seus resultados por meio de uma implementação dos objetos qiskit.primitives .
Fornecendo acesso a backends
Para que os usuários transpilem e executem objetos QuantumCircuit usando recursos externos, eles precisam instanciar um objeto contendo um Target que fornece informações sobre as restrições de uma QPU, como conectividade, portas de base e número de qubits. Isso pode ser fornecido por meio de uma interface semelhante à interface QiskitRuntimeService por meio da qual um usuário pode fazer solicitações para uma QPU. Esse objeto deve, no mínimo, conter um Target, mas uma abordagem mais simples seria retornar uma BackendV2 instância.
Um exemplo de implementação pode ser algo parecido com:
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
Fornecendo uma interface para execução
Além de fornecer um serviço que retorna as configurações de hardware, um serviço que fornece acesso a recursos externos de QPU também pode dar suporte à execução de cargas de trabalho quânticas. A exposição desse recurso pode ser feita por meio da criação de implementações das interfaces Qiskit primitives; por exemplo, as interfaces BasePrimitiveJob, BaseEstimatorV2 e BaseSamplerV2 entre outras. No mínimo, essas interfaces devem ser capazes de fornecer um método para execução, consulta do status do trabalho e retorno dos resultados do trabalho.
Para lidar com o status e os resultados do trabalho, o site Qiskit SDK fornece um arquivo DataBin, PubResult, PrimitiveResult, e BasePrimitiveJob devem ser usados.
Consulte a documentação da API qiskit.primitives , bem como as implementações de referência BackendEstimatorV2 e BackendSampleV2 para obter mais informações.
Um exemplo de implementação da primitiva Estimator pode ter a seguinte aparência:
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_resultsE uma implementação da primitiva Sampler pode ser semelhante:
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