외부 양자 리소스를 Qiskit과 통합합니다
Qiskit SDK 은 제3자가 양자 리소스의 외부 공급자를 만들 수 있도록 지원하기 위해 만들어졌습니다.
즉, 양자 컴퓨팅 리소스를 개발하거나 배포하는 모든 조직은 자신의 서비스를 키스킷에 통합하고 사용자 기반을 활용할 수 있습니다.
이렇게 하려면 양자 컴퓨팅 리소스에 대한 요청을 지원하고 사용자에게 리소스를 반환하는 패키지를 만들어야 합니다.
또한 패키지는 사용자가 qiskit.primitives 객체의 구현을 통해 작업을 제출하고 결과를 검색할 수 있어야 합니다.
백엔드에 대한 접근 제공
사용자가 외부 리소스를 사용하여 QuantumCircuit 객체를 트랜스파일하고 실행하려면, 연결성, 비트 수 등의 제약 조건에 대한 정보를 제공하는 Target 를 포함하는 객체를 인스턴스화해야 하며, 이는 연결성, 베이스 게이트 및 큐비트 수와 같은 QPU의 제약 조건에 대한 정보를 제공합니다. 이 기능은 사용자가 QPU를 요청할 수 있는 QiskitRuntimeService 와 유사한 인터페이스를 통해 제공될 수 있습니다. 이 객체는 최소한 Target 를 포함해야 하지만 더 간단한 접근 방식은 BackendV2 인스턴스를 반환하는 것입니다.
구현의 예는 다음과 같습니다:
from qiskit.transpiler import Target
from qiskit.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
실행용 인터페이스 제공
하드웨어 구성을 반환하는 서비스 외에도, 외부 QPU 리소스에 대한 액세스를 제공하는 서비스는 양자 워크로드의 실행을 지원할 수도 있습니다. 이러한 기능을 노출하려면 Qiskit 기본 클래스의 구현체를 생성하면 됩니다. 예를 들어 BasePrimitiveJob,, BaseEstimatorV2 및 BaseSamplerV2 등이 있습니다. 최소한 이러한 인터페이스는 작업 실행, 작업 상태 조회 및 작업 결과 반환 기능을 제공해야 합니다.
작업 상태 및 결과를 처리하기 위해 Qiskit SDK 에서 DataBin, PubResult, PrimitiveResult및 BasePrimitiveJob 객체를 사용해야 합니다.
qiskit.primitives API 문서와 참조 구현을 참조하세요 BackendEstimatorV2 과 BackendSampleV2 를 참조하세요.
추정기 프리미티브의 구현 예시는 다음과 같습니다:
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샘플러 프리미티브의 구현은 다음과 같습니다:
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