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.