Implementare ed eseguire un modello di funzione Qiskit per la dinamica dell'Hamiltoniano AQC + Trotter
Panoramica
Questo è un modello di funzione Qiskit indipendente dall'esperimento per la dinamica hamiltoniana. Dato un Hamiltoniano di Pauli dei vicini più prossimi di tipo “ 1D ”, uno stato iniziale preparato (facoltativo) e un insieme di osservabili, l’algoritmo esegue l’evoluzione temporale di Trotter, la compressione dei circuiti tramite compilazione quantistica approssimativa (AQC) e l’esecuzione mitigata, per poi restituire le serie temporali di ciascun osservabile. Se si scambiano la fase di preparazione (PRE) e quella di analisi (POST), lo stesso nucleo dà origine a un esperimento diverso:
PRE (la tua configurazione) | FUNZIONE (implementata qui) | PUBBLICA (la tua analisi) |
|---|---|---|
| Preparare uno stato, come circuito o stato di prodotto, con un kick locale opzionale | Sintesi Trotter → compressione AQC → esecuzione su statevector, fake, o runtime, con restituzione di un | per la diffusione dei neutroni, oppure per la magnetizzazione, il trasporto, la dinamica di quench e così via |
Il modello è pubblicato nel repository dei modelli di funzione di Qiskit, insieme agli altri modelli di applicazione. Questo notebook lo distribuisce sul tuo account Qiskit Serverless. Eseguila una volta e qualsiasi notebook potrà poi richiamare la funzione con serverless.load("aqc-dynamics-function").
Per un esempio scientifico concreto, si veda “Simulazione della diffusione dei neutroni con un flusso di lavoro serverless basato su AQC e dinamica di Trotter”, che richiama questa funzione per calcolare il fattore di struttura dinamico di KCuF. Questo notebook tratta invece l’implementazione e il contratto di input.
Requisiti
Prima di iniziare, assicurati che nell'ambiente del kernel di questo notebook siano presenti i seguenti elementi:
- Qiskit SDK v2.0 o versioni successive (
pip install qiskit). - Il client Qiskit IBM Catalog (
pip install qiskit-ibm-catalog), che distribuisce ed esegue carichi di lavoro su Qiskit Serverless.
Non è necessario installare localmente le dipendenze scientifiche della funzione stessa (qiskit-addon-aqc-tensor, cotengrust, qiskit-aer).
Scarica i file sorgente del modello
La funzione è un piccolo pacchetto Python che Qiskit Serverless viene eseguito nel cloud, quindi il suo codice sorgente deve essere presente sotto forma di file locali che vengono caricati al momento della distribuzione. Il pacchetto è pubblicato nel repository dei modelli di funzione di Qiskit.
Scarica source_files
Il file da scaricare è un unico file ZIP, il cui nome corrisponde al percorso completo della directory presente nel repository:
qiskit-community qiskit-function-templates main physics aqc_trotter source_files.zip
- Decomprimilo nella cartella in cui si trova questo notebook.
- Rinomina la cartella estratta, sostituendo quel nome lungo con
source_files.
La tua directory di lavoro avrà quindi questo aspetto:
your-working-directory/
├── function-template-aqc-trotter.ipynb <- this notebook
└── source_files/ <- the renamed folder
├── __init__.py
├── program.py
└── source/
├── __init__.py
├── _serverless.py
├── app_function.py
├── aqc.py
├── build.py
├── execute.py
└── hamiltonian.py
Il nome deve corrispondere esattamente source_files, perché si tratta dei file caricati nella Fase working_dir 3.
program.py è il punto di ingresso che il gateway richiama. Tutto ciò che segue è source/ dedicato all'implementazione, suddivisa per fasi: sintesi dell'Hamiltoniano e di Trotter, compressione AQC ed esecuzione. Non è necessario apportare alcuna modifica per eseguire gli esempi che seguono. Il passaggio 3 carica l'intera directory, quindi ripeti quel passaggio ogni volta che modifichi un file.
1. Autenticazione
Utilizza qiskit-ibm-catalog per effettuare l'autenticazione su QiskitServerless con la tua chiave API (token) e l'istanza " CRN ", che puoi trovare nella dashboard di IBM Quantum® Platform. Con queste credenziali è possibile avviare localmente il client serverless per caricare o eseguire la funzione selezionata:
from qiskit_ibm_catalog import QiskitServerless
serverless = QiskitServerless(channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN")Se lo desideri, puoi utilizzare save_account() per salvare le tue credenziali nel tuo ambiente locale (consulta la guida “Configurazione dell’account IBM Cloud® ” ). Si noti che questa operazione salva le credenziali nello stesso file di QiskitRuntimeService.save_account():
QiskitServerless.save_account(channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN")Se l'account è stato salvato, non è necessario fornire il token per l'autenticazione:
from qiskit_ibm_catalog import QiskitServerless
# Authenticate to the remote cluster
# In this case, loading a saved account
serverless = QiskitServerless()
# REPLACE WITH YOUR OWN CREDENTIALS or SAVED ACCOUNT
# serverless = QiskitServerless(channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN")2. Dichiarare le dipendenze
Pacchetti necessari alla funzione oltre all'immagine serverless di base gestita.
Il gateway installa solo i nomi presenti nella propria lista di autorizzazioni (requirements-dynamic-dependencies.txt), identificati in base al nome del pacchetto e associati alla versione consentita tramite ==. Tutto il resto deve arrivare in modo transitivo (come dipendenza di un pacchetto presente nell'elenco dei pacchetti consentiti). La sintassi [extras] viene rispettata: qiskit-addon-aqc-tensor[quimb-jax] è ciò che installa e quimb jax. cotengrust è necessario per garantire l'efficienza della memoria durante la simulazione delle reti tensoriali. qiskit-aer è indicato separatamente per il backend fake (simulazione locale con rumore).
DEPENDENCIES = [
"qiskit-addon-aqc-tensor[quimb-jax]==0.3.1",
"qiskit-aer==0.17.2",
"cotengrust==0.2.0",
]3. Definire e caricare la funzione
from qiskit_ibm_catalog import QiskitFunction
fn = QiskitFunction(
title="aqc-dynamics-function",
entrypoint="program.py",
working_dir="source_files/",
dependencies=DEPENDENCIES,
)
serverless.upload(fn)Output:
QiskitFunction(aqc-dynamics-function)
4. Verificare che sia stato registrato
next(p for p in serverless.list() if p.title == "aqc-dynamics-function")Output:
QiskitFunction(aqc-dynamics-function)
Riferimento alle funzioni
Questa è una breve introduzione. Ogni campo è documentato in modo esaustivo nel file README del modello AQC Dynamics : la tabella completa degli input con le relative regole di validazione, i campi di output, i backend di esecuzione e ulteriori esempi pratici. Quella che segue è la versione sintetica, sufficiente per comprendere gli esempi riportati di seguito.
Input
Ogni esecuzione corrisponde a una singola chiamata fn.run(...) . Sono obbligatori solo i primi tre campi della tabella: hamiltonian, t_steps, e aqc_segments. Tutto ciò che segue è facoltativo e, in assenza di indicazioni, si ricorre al valore predefinito indicato; pertanto, una chiamata minima prevede tre argomenti, mentre il resto della tabella descrive le funzionalità che è possibile attivare a propria discrezione. L'Hamiltoniano num_qubits determina la lunghezza della catena, quindi non è previsto alcun parametro di input separato per la dimensione.
Input | Predefinito | Descrizione | Rubrica 4 |
|---|---|---|---|
hamiltonian | obbligatorio | 1D Hamiltoniano di Pauli del vicino più prossimo come SparsePauliOp. Le stringhe sono operatori di Pauli, quindi non vi è alcun fattore implicito pari a mezzo. | |
t_steps | obbligatorio | Totale passi di Trotter. Si evolve in e T = t_steps * dt riporta ogni grandezza osservabile in ogni t_k = k * dt. | |
aqc_segments | obbligatorio | Piano di compressione: un elenco di {"n_steps": k, "ansatz_steps": m}. sum(n_steps) i passi sono compressi; il resto viene eseguito come nel metodo Trotter standard. | |
dt | 0.2 | Il tempo fisico è avanzato di un passo di Trotter. | |
initial_state | ` | 0...0>` | Un individuo pronto QuantumCircuit a evolversi. Aggiungi un tocco locale a questo circuito. |
observables | per sito Z | Qualsiasi cosa EstimatorV2 accetta come argomento observables . Un dato osservabile per ogni colonna di output. | |
trotter_options | Suzuki di secondo ordine | {"method": ..., "synthesis_settings": {...}}. e reps time appartengono alla funzione. | |
aqc_options | Vedi la descrizione | max_bond (32), cutoff (1e-8), autodiff_backend ("jax"), fidelity_target (None), optimizer_settings (L-BFGS-B, jac=True, maxiter=300). | |
estimator_options | DD, piroette, TREX | EstimatorV2.options, approvato così com'è. Un dizionario fornito sostituisce integralmente quelli predefiniti, anziché fondersi con essi. | |
transpiler_options | {"optimization_level": 3} | generate_preset_pass_manager argomenti chiave. backend e target vengono scartati, poiché appartengono al percorso di esecuzione. | |
backend | "runtime" | "statevector", "fake", oppure "runtime". | |
backend_name | meno trafficato | IBM® nome del backend per runtime, oppure un backend fittizio con un nome specifico. | |
batches | 1 | Dividere i circuiti tra N processi di esecuzione. Un batch invia un singolo processo e non crea alcuna sessione. | |
parallel_sim | False | Distribuisci i percorsi del simulatore locale su tutti i core disponibili con Ray. Nessun effetto su runtime. | |
return_circuits | False | Restituire i circuiti logici AQC + Trotter nel risultato insieme alle serie osservabili. |
Backend di esecuzione
Tutti e tre i percorsi condividono lo stesso codice e le stesse impostazioni di mitigazione. Si differenziano solo per il percorso dei circuiti.
backend | Che cos’è | Credenziali | Note |
|---|---|---|---|
"statevector" | Esatta StatevectorEstimator | Solo per account serverless | Il percorso di riferimento esatto. Nessun tempo QPU. |
"fake" | Simulazione locale rumorosa su un backend fittizio di Qiskit | Solo per account serverless | Una fedele riproduzione del percorso runtime attenuato. Esigenze qiskit-aer. Il valore predefinito è il sistema da 127 qubit fake_sherbrooke. |
"runtime" (predefinito) | Le misure di mitigazione adottate EstimatorV2 nei confronti di una vera QPU | Account serverless e un'istanza con accesso alla QPU | backend_name facoltativo; se omesso, viene selezionato il dispositivo meno occupato. |
Entrambi i percorsi del simulatore continuano a richiamare la funzione distribuita, quindi richiedono un account Serverless salvato anche se non utilizzano tempo di elaborazione QPU. I due esempi che seguono eseguono lo stesso carico di lavoro prima statevector su, poi su runtime.
Output
job.result() restituisce un semplice dizionario:
{
"times": [...], # length t_steps + 1, t_k = k * dt (t=0 is the prepared state)
"expectation_values": [[...]], # shape (n_times, n_observables)
"observable_labels": [...], # for example: ["Z_0", "ZZ_0_1"]
"metadata": {
"n", "t_steps", "dt", "tier",
"aqc_compressed_steps": 5, # total compressed steps (= sum of segment n_steps)
"aqc_segments": [ # per segment: the plan plus its own results
{"n_steps": 3, "ansatz_steps": 1, "steps": [1, 2, 3], "n_params": 133,
"fidelities": {"1": ..., "2": ..., "3": ...}},
{"n_steps": 2, "ansatz_steps": 2, "steps": [4, 5], "n_params": 245,
"fidelities": {"4": ..., "5": ...}},
],
"execution_backend",
"aqc_fidelities": {"1": ..., "2": ...}, # flat per-step fidelity, all compressed steps
"circuit_stats": { # per-step 2q depth and gate count, full Trotter vs AQC
"1": {"full_trotter": {"depth_2q": ..., "num_2q_gates": ...},
"aqc_trotter": {"depth_2q": ..., "num_2q_gates": ...}},
"2": {...},
},
"warnings": [...], # non-fatal notices; for example, a cotengrust fallback
"resource_usage": { # per stage; QPU_TIME is the charged QPU time
"RUNNING: OPTIMIZING_FOR_HARDWARE": {"CPU_TIME": ...},
"RUNNING: WAITING_FOR_QPU": {"CPU_TIME": ...},
"RUNNING: EXECUTING_QPU": {"QPU_TIME": ...},
},
},
# present only when return_circuits=True
"circuits": [QuantumCircuit, ...], # one per evolved step; circuits[i] is at times[i + 1]
}aqc_fidelities e sono circuit_stats i due da leggere per primi: insieme ti dicono se la compressione è rimasta fedele all’originale e se ha effettivamente conservato la profondità. Il runtimesistema riporta resource_usage il tempo di attesa in coda separatamente dal tempo di utilizzo della QPU che ti viene addebitato. Un input non valido viene rifiutato rapidamente come un ServerlessError codice strutturato 4615.
Esempio di simulatore
Esegui prima la funzione proprio su quel backend statevector . Non richiede tempo di elaborazione da parte della QPU e verifica la distribuzione dall'inizio alla fine. Il modello qui considerato è una catena di Ising a campo trasversale a otto qubit, e observables è stato omesso in modo che la funzione misuri l’ predefinito per sito.
Il piano di compressione è l'elemento che vale la pena comprendere. Ogni segmento {"n_steps": k, "ansatz_steps": m} comprime i passi consecutivi k di Trotter in un ansatz costruito a partire da un obiettivo di Trotter a m-passi, mentre eventuali passi successivi vengono sum(n_steps) eseguiti come metodo di Trotter standard. Le fasi iniziali, caratterizzate da un basso livello di entanglement, si comprimono bene in un ansatz a singolo strato poco profondo; le fasi successive, caratterizzate da un maggiore entanglement, richiedono invece un ansatz più profondo.
from qiskit.quantum_info import SparsePauliOp
fn = serverless.load("aqc-dynamics-function")
n = 8
H = SparsePauliOp.from_sparse_list(
[("ZZ", [i, i + 1], 1.0) for i in range(n - 1)]
+ [("X", [i], 0.8) for i in range(n)],
num_qubits=n,
)
job = fn.run(
t_steps=8,
aqc_segments=[
{
"n_steps": 4,
"ansatz_steps": 1,
}, # early steps -> shallow 1-layer ansatz
{
"n_steps": 2,
"ansatz_steps": 2,
}, # later steps -> deeper 2-layer ansatz
],
hamiltonian=H,
aqc_options={"max_bond": 32},
backend="statevector",
)
print("job ID:", job.job_id)Output:
job ID: ee1f3793-e995-427d-81d1-5924549beb38
Segui la corsa e leggi il risultato
status() riporta sia il ciclo di vita generale del processo sia gli stati parziali relativi a ciascuna fase che la funzione pubblica durante la sua esecuzione. Le stesse fasi valgono anche per la configurazione hardware descritta più avanti in questa guida:
QUEUED -> INITIALIZING -> RUNNING: OPTIMIZING_FOR_HARDWARE -> RUNNING: WAITING_FOR_QPU -> RUNNING: EXECUTING_QPU -> RUNNING: POST_PROCESSING -> DONE
status() Valore | Fase |
|---|---|
RUNNING: OPTIMIZING_FOR_HARDWARE | preparazione dello stato, costruzione Trotter, compressione AQC |
RUNNING: WAITING_FOR_QPU | in coda sulla QPU (runtime solo backend) |
RUNNING: EXECUTING_QPU | circuiti in esecuzione (i simulatori locali lo segnalano direttamente) |
RUNNING: POST_PROCESSING | creazione del dizionario dei risultati |
Gli stati terminali sono DONE, ERROR, e CANCELED. Questa esecuzione statevector non ha una coda QPU, quindi salta RUNNING: WAITING_FOR_QPU. Utilizza job.logs() in qualsiasi momento per visualizzare i registri relativi a ciascuna fase, compresa la fedeltà AQC raggiunta in ogni fase.
print(job.status()) # re-run until this reports DONEOutput:
DONE
import numpy as np
result = job.result()
ev = np.array(result["expectation_values"])
print("observables:", result["observable_labels"])
print("shape:", ev.shape, "-> (n_times, n_observables)")
print("first row (t = 0, the prepared state):", np.round(ev[0], 4))
print("last row (t = t_steps * dt):", np.round(ev[-1], 4))
print(
"AQC fidelities:",
{k: round(v, 4) for k, v in result["metadata"]["aqc_fidelities"].items()},
)
# What the compression bought: 2-qubit depth at the final time step.
stats = result["metadata"]["circuit_stats"][
str(result["metadata"]["t_steps"])
]
print(
"2q depth at the final step:",
stats["full_trotter"]["depth_2q"],
"(full Trotter) ->",
stats["aqc_trotter"]["depth_2q"],
"(AQC + Trotter)",
)Output:
observables: ['Z_0', 'Z_1', 'Z_2', 'Z_3', 'Z_4', 'Z_5', 'Z_6', 'Z_7']
shape: (9, 8) -> (n_times, n_observables)
first row (t = 0, the prepared state): [1. 1. 1. 1. 1. 1. 1. 1.]
last row (t = t_steps * dt): [0.1442 0.2956 0.4686 0.4877 0.4869 0.4686 0.2963 0.1441]
AQC fidelities: {'1': 1.0, '2': 1.0, '3': 1.0, '4': 1.0, '5': 1.0, '6': 0.9999}
2q depth at the final step: 210 (full Trotter) -> 79 (AQC + Trotter)
Esempio di hardware
Una chiamata di funzione viene transposta backend="runtime" ed eseguita su un processore reale IBM Quantum, con le tecniche di mitigazione degli errori integrate nella funzione: disaccoppiamento dinamico ( XY4 ), gate twirling ed estinzione degli errori di lettura twirled (TREX). backend_name seleziona il dispositivo; se non viene specificato, la funzione sceglie quello meno occupato.
Non cambia nulla riguardo al codice scientifico. Ciò che differisce dall'esempio del simulatore è la lunghezza della catena, il numero di passi di Trotter, il piano di compressione, il backend e le impostazioni di mitigazione esplicita illustrate nella sezione seguente.
Determinazione delle dimensioni del lavoro per l’hardware di controllo
estimator_options Vale la pena impostare deliberatamente questo parametro? Il "gate twirling" crea circuiti casuali distinti num_randomizations per ogni PUB, e l'intero processo, ogni PUB con tutte le sue casualità, deve rientrare nella memoria di istruzioni del sistema di controllo classico della QPU. La funzione è impostata di default su 1000 randomizzazioni, quindi un’evoluzione in 10 fasi invia 11 PUB da 1000 circuiti ciascuno: circa 11.000 istanze di circuiti in un unico processo.
Se si supera il limite previsto dal sistema di controllo, l'operazione fallisce con l'errore 6073. La sezione "Limiti per job" indica le soglie e le modalità di calcolo, tra cui la principale è quella dell' 26.8 milione di istruzioni del sistema di controllo per qubit, applicata per singolo job anziché per singolo " PUB ". Il disaccoppiamento dinamico aggiunge porte che contribuiscono a determinarlo.
Due parametri determinano le dimensioni:
estimator_optionsstabilisce il budget per le riprese. Il numero totale di tentativi ènum_randomizations * shots_per_randomization, quindi è possibile scambiare le randomizzazioni con il numero di tentativi per randomizzazione, mantenere le statistiche e ridurre comunque le dimensioni del programma. La cella seguente utilizza 100 randomizzazioni da 200 shot ciascuna, per un totale di 20.000 shot per ogni osservabile e circa un decimo delle istanze di circuito che verrebbero generate con le impostazioni predefinite. Per l'elenco completo dei campi, consultare le opzioni " TwirlingOptions " e "Estimator".batchessuddivide i PUB in altrettanti processi di esecuzione distinti, il che è proprio la soluzione suggerita dal messaggio di errore 6073 e spiega perché la suddivisione per processo sia importante. Questa impostazione inviabatches=4circa tre PUB per ogni processo invece di undici contemporaneamente, e i processi vengono inviati insieme in un unico batch, in modo che il gruppo venga messo in coda una sola volta anziché che ogni processo venga messo in coda separatamente.
Si ricordi che un valore specificato sostituisce estimator_options completamente i valori predefiniti della funzione, anziché fondersi con essi; pertanto, il disaccoppiamento dinamico e TREX vengono ridefiniti nella cella seguente per mantenerli attivi.
from qiskit.quantum_info import SparsePauliOp
fn = serverless.load("aqc-dynamics-function")
n = 10
H = SparsePauliOp.from_sparse_list(
[("ZZ", [i, i + 1], 1.0) for i in range(n - 1)]
+ [("X", [i], 0.8) for i in range(n)],
num_qubits=n,
)
job = fn.run(
t_steps=10,
aqc_segments=[
{
"n_steps": 3,
"ansatz_steps": 1,
}, # early steps -> shallow 1-layer ansatz
{
"n_steps": 3,
"ansatz_steps": 2,
}, # later steps -> deeper 2-layer ansatz
],
hamiltonian=H,
aqc_options={"max_bond": 32},
backend="runtime",
backend_name="ibm_marrakesh",
# The function defaults to 1000 twirling randomizations, which was too large
# for this device. Total shots is num_randomizations *
# shots_per_randomization, so this is 20,000 shots per observable.
estimator_options={
"dynamical_decoupling": {"enable": True, "sequence_type": "XY4"},
"twirling": {
"enable_gates": True,
"num_randomizations": 100,
"shots_per_randomization": 200,
},
"resilience": {"measure_mitigation": True},
},
)
print("job ID (save this to reconnect later):", job.job_id)Output:
job ID (save this to reconnect later): 7229a8bf-9f83-4785-8dd4-489844abc2d9
Un'esecuzione hardware non è veloce e, nella maggior parte dei casi, avviene in modo classico anziché sulla QPU. La compressione AQC viene eseguita all'interno della funzione prima che qualsiasi dato raggiunga la QPU, mentre la coda della QPU si trova a livello superiore rispetto a essa. Non è necessario tenere aperto questo notebook o questo kernel mentre è in esecuzione.
Copia l'ID del lavoro visualizzato nella cella precedente e salvalo. Le tre caselle successive ti consentono di riprendere la sessione in un secondo momento:
- Riconnettere, operazione necessaria solo in una nuova sessione del kernel: rieseguire la cella di autenticazione per ricrearla
serverless, quindi ricostruire l'handlejoba partire dall'ID salvato. Salta questa cella se sei ancora nella sessione in cui hai inviato la richiesta, poiché l'handle è già attivo. - Verifica lo stato: ripeti l'operazione finché non viene segnalato
DONE. - Recupera il risultato: esegui l'operazione solo quando lo stato è
DONE.
Incolla l'ID che hai salvato al posto del segnaposto nella seguente cella di ricollegamento.
# Reconnect to a previously submitted job by its ID. Only needed in a NEW kernel
# session; if you are still in the session where you submitted, the `job` handle
# from the preceding cell is already live, so skip this cell. Replace the ID that follows with your own.
job = serverless.get_job_by_id("<your job ID>")# Re-run this until it reports DONE, then fetch the result in the following cell.
print(job.status())Output:
DONE
import numpy as np
# Run this only once the preceding status cell reports DONE. result() blocks until
# the job finishes, so calling it earlier just waits.
result = job.result()
ev = np.array(result["expectation_values"])
print("backend:", result["metadata"]["execution_backend"])
print("shape:", ev.shape, "-> (n_times, n_observables)")
print("last row (t = t_steps * dt):", np.round(ev[-1], 4))
print(
"AQC fidelities:",
{k: round(v, 4) for k, v in result["metadata"]["aqc_fidelities"].items()},
)
# What the compression bought: 2-qubit depth at the final time step.
stats = result["metadata"]["circuit_stats"][
str(result["metadata"]["t_steps"])
]
print(
"2q depth at the final step:",
stats["full_trotter"]["depth_2q"],
"(full Trotter) ->",
stats["aqc_trotter"]["depth_2q"],
"(AQC + Trotter)",
)Output:
backend: runtime
shape: (11, 10) -> (n_times, n_observables)
last row (t = t_steps * dt): [0.1504 0.1361 0.218 0.2144 0.2275 0.1783 0.1749 0.1599 0.0915 0.0922]
AQC fidelities: {'1': 1.0, '2': 1.0, '3': 1.0, '4': 1.0, '5': 0.9999, '6': 0.9999}
2q depth at the final step: 342 (full Trotter) -> 171 (AQC + Trotter)
Passi successivi
- Segui il flusso di lavoro Simulazione della diffusione neutronica con AQC + dinamica di Trotter (Serverless), l’esempio di accompagnamento che richiama questa funzione distribuita per calcolare il fattore di struttura dinamico di KCuF.
- Si prega di consultare il modello AQC Dynamics su GitHub per il contratto completo relativo a input e output, ulteriori esempi e i dettagli relativi alla citazione.
- Esplora il repository dei modelli di Qiskit Function per trovare altri modelli di applicazioni realizzati con lo stesso metodo.
- Leggi la guida “ Qiskit Serverless ” per la gestione delle funzioni distribuite.
- Approfondisci la fase di compressione AQC con l'add-on Qiskit: documentazione di AQC-Tensor.