Mengintegrasikan sumber daya kuantum eksternal dengan Qiskit
Qiskit SDK dirancang untuk mendukung pihak ketiga dalam membuat provider eksternal dari sumber daya kuantum.
Artinya, organisasi mana pun yang mengembangkan atau menggunakan sumber daya komputasi kuantum bisa mengintegrasikan layanan mereka ke dalam Qiskit dan memanfaatkan basis penggunanya.
Untuk melakukan ini, kamu perlu membuat paket yang mendukung permintaan sumber daya komputasi kuantum dan mengembalikannya ke pengguna.
Selain itu, paket tersebut harus memungkinkan pengguna untuk mengirim job dan mengambil hasilnya melalui implementasi objek qiskit.primitives.
Menyediakan akses ke Backend​
Agar pengguna bisa men-transpile dan mengeksekusi objek QuantumCircuit menggunakan sumber daya eksternal, mereka perlu membuat instansi objek yang berisi Target yang menyediakan informasi tentang batasan QPU seperti konektivitasnya, gate basis, dan jumlah qubit. Ini bisa disediakan melalui antarmuka yang mirip dengan QiskitRuntimeService yang memungkinkan pengguna membuat permintaan untuk QPU. Objek ini setidaknya harus berisi sebuah Target, tapi pendekatan yang lebih sederhana adalah mengembalikan instansi BackendV2.
Contoh implementasinya bisa terlihat seperti ini:
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
Menyediakan antarmuka untuk eksekusi​
Selain menyediakan layanan yang mengembalikan konfigurasi perangkat keras, layanan yang memberikan akses ke sumber daya QPU eksternal juga mungkin mendukung eksekusi beban kerja kuantum. Kemampuan tersebut bisa diekspos dengan membuat implementasi antarmuka primitif Qiskit; misalnya BasePrimitiveJob, BaseEstimatorV2 dan BaseSamplerV2 di antaranya. Setidaknya, antarmuka ini harus menyediakan metode untuk eksekusi, mengecek status job, dan mengembalikan hasil job.
Untuk menangani status dan hasil job, Qiskit SDK menyediakan objek DataBin, PubResult, PrimitiveResult, dan BasePrimitiveJob yang harus digunakan.
Lihat dokumentasi API qiskit.primitives serta implementasi referensi BackendEstimatorV2 dan BackendSampleV2 untuk informasi lebih lanjut.
Contoh implementasi primitif Estimator bisa terlihat seperti:
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
Dan implementasi primitif Sampler bisa terlihat seperti:
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