SpeQtrum
El paquet speqtrum proporciona un client síncron opcional per al núvol SpeQtrum de Qilimanjaro. A través de la classe SpeQtrum podeu autenticar-vos, inspeccionar dispositius i treballs, i enviar experiments digitals, analògics o de pols per a l’execució remota.
Instal·lació
El suport de SpeQtrum s’inclou com a grup de dependències opcional. Instal·leu-lo juntament amb QiliSDK amb:
pip install "qilisdk[speqtrum]"
Autenticació
L’API utilitza tokens OAuth de curta durada que s’emmagatzemen a la clauera del sistema. Crideu SpeQtrum.login una vegada i les credencials es reutilitzaran per a les sessions posteriors.
from qilisdk.speqtrum import SpeQtrum
# Credentials can be provided explicitly…
logged_in = SpeQtrum.login(username="alice", apikey="MY_SECRET_KEY")
# …or read from the environment (QILISDK_SPEQTRUM_USERNAME / QILISDK_SPEQTRUM_APIKEY)
logged_in = SpeQtrum.login()
if not logged_in:
raise RuntimeError("Authentication failed")
# Remove cached credentials when they are no longer needed
SpeQtrum.logout()
Construcció del Client
Un cop emmagatzemades les credencials, instancieu SpeQtrum per començar a emetre sol·licituds. La construcció falla amb un RuntimeError si no existeixen credencials en caché.
from qilisdk.speqtrum import SpeQtrum
client = SpeQtrum()
Catàleg de Dispositius
Els dispositius es representen mitjançant models Device que contenen el codi del dispositiu, el nombre de qubits, el tipus de maquinari i l’estat. Useu SpeQtrum.list_devices per enumerar-los. Un predicat where opcional permet el filtratge del costat del client.
from qilisdk.speqtrum import SpeQtrum, DeviceStatus
client = SpeQtrum()
for device in client.list_devices(where=lambda d: d.status == DeviceStatus.ONLINE):
print(f"{device.code}: {device.name} ({device.type}) – {device.nqubits} qubits")
Treballs Remots
SpeQtrum.list_jobs retorna registres lleugers JobInfo. El predicat where funciona de la mateixa manera que amb els dispositius.
from qilisdk.speqtrum import SpeQtrum
from qilisdk.speqtrum.speqtrum_models import JobStatus
client = SpeQtrum()
running = client.list_jobs(where=lambda job: job.status == JobStatus.RUNNING)
for job in running:
print(f"{job.id}: {job.status.value} on {job.device_id}")
Per inspeccionar les metadades completes del treball (càrrega útil, resultat, registres, errors descodificats) crideu SpeQtrum.get_job. Els camps binaris es retornen com a cadenes descodificades o objectes ExecuteResult estructurats.
Quan s’espera un JobHandle, l’objecte retornat és un TypedJobDetail que exposa un auxiliar fortament tipat get_results().
job_handle = client.submit(sampling, device=device)
final_job = client.wait_for_job(job_handle)
result = final_job.get_results() # -> FunctionalResult
Encara podeu cridar get_job() amb un identificador enter simple. En aquest cas es retorna un objecte regular JobDetail i podeu inspeccionar els camps *.result individuals manualment quan calgui.
Espera de Finalització
Useu SpeQtrum.wait_for_job per sondejar fins que un treball arriba a un estat terminal (completed, error o cancelled). Passar un JobHandle produeix un TypedJobDetail amb accés tipat als resultats, mentre que els identificadors enters simples continuen retornant un JobDetail simple. L’auxiliar genera un TimeoutError si el temps d’espera opcional s’exhaureix primer.
Enviament de Funcionals
SpeQtrum accepta els mateixos funcionals primitius que utilitzen els backends locals. El mètode SpeQtrum.submit inspecciona el tipus de funcional i serialitza la càrrega útil correcta. Heu de subministrar un argument device amb el codi del dispositiu obtingut de list_devices().
from qilisdk.digital import Circuit, H, CNOT
from qilisdk.functionals import DigitalPropagation
from qilisdk.readout import Readout
from qilisdk.speqtrum import SpeQtrum
circuit = Circuit(2)
circuit.add(H(0))
circuit.add(CNOT(0, 1))
functional = DigitalPropagation(circuit)
client = SpeQtrum()
device = client.list_devices()[0].code
job_handle = client.submit(functional, readout=Readout().with_sampling(nshots=1_000), device=device)
print("Submitted job:", job_handle.id)
final_job = client.wait_for_job(job_handle, timeout=600)
result = final_job.get_results()
print("Most frequent outcome:", result.probabilities)
Avís
Physical QPUs currently do not support analog functionals built on AnalogEvolution;
for now, analog hardware can run only pulse experiments from experiments.
Programes Variacionals
L’optimització híbrida es gestiona a través del mateix funcional VariationalProgram utilitzat amb els backends locals. Serialitzeu el programa variacional completament configurat (ansatz, optimitzador, funció de cost) i envieu-lo com qualsevol altre funcional.
from qilisdk.core.model import Model, ObjectiveSense
from qilisdk.core.variables import BinaryVariable, LEQ
from qilisdk.cost_functions import ModelCostFunction
from qilisdk.digital import CNOT, HardwareEfficientAnsatz, U2
from qilisdk.functionals import DigitalPropagation
from qilisdk.functionals.variational_program import VariationalProgram
from qilisdk.readout import Readout
from qilisdk.optimizers.scipy_optimizer import SciPyOptimizer
from qilisdk.speqtrum import SpeQtrum
# Build a small cost model
vars = [BinaryVariable(f"x{i}") for i in range(3)]
model = Model("toy")
model.set_objective(sum(vars), sense=ObjectiveSense.MAXIMIZE)
model.add_constraint("budget", LEQ(vars[0] + vars[1], 1))
ansatz = HardwareEfficientAnsatz(
nqubits=3,
layers=2,
one_qubit_gate=U2,
two_qubit_gate=CNOT,
connectivity="linear",
structure="grouped",
)
functional = DigitalPropagation(ansatz)
optimizer = SciPyOptimizer(method="Powell")
vprog = VariationalProgram(functional=functional, optimizer=optimizer, cost_function=ModelCostFunction(model))
client = SpeQtrum()
device = client.list_devices()[0].code
job_handle = client.submit(vprog, readout=Readout().with_sampling(nshots=1024), device=device)
Experiments de Pols
El client SpeQtrum també admet experiments d’estil de calibratge definits a qilisdk.experiments.experiment_functional. Aquests objectes funcionals reflecteixen les interfícies descrites al capítol Funcionals i retornen tipus de resultat rics.
import numpy as np
from qilisdk.speqtrum import DeviceType, SpeQtrum
from qilisdk.experiments import RabiExperiment, T1Experiment
client = SpeQtrum()
device = client.list_devices(
where=lambda d: d.type in (DeviceType.QPU_ANALOG, DeviceType.QPU_DIGITAL)
)[0].code
# Rabi experiment: sweep drive durations
rabi = RabiExperiment(qubit=0, drive_duration_values=np.linspace(0, 200, 21))
rabi_handle = client.submit(rabi, device=device)
rabi_response = client.wait_for_job(rabi_handle, timeout=600)
rabi_result = rabi_response.get_results()
# T1 relaxation experiment: sweep wait durations
t1 = T1Experiment(qubit=0, wait_duration_values=np.linspace(0, 400, 41))
t1_handle = client.submit(t1, device=device)
t1_response = client.wait_for_job(t1_handle, timeout=600)
t1_result = t1_response.get_results()
Els objectes RabiExperimentResult i T1ExperimentResult resultants es poden utilitzar directament.