Skip to main content
IBM Quantum Platform

Bereitstellung und Ausführung einer Qiskit-Funktionsvorlage für AQC + Trotter-Hamilton-Dynamik


Übersicht

Dies ist eine experimentunabhängige Qiskit-Funktionsvorlage für die Hamilton-Dynamik. Ausgehend von einem „ 1D “-Pauli-Hamiltonian nach der Nearest-Neighbor-Methode, einem vorbereiteten Anfangszustand (optional) und einer Menge von Observablen führt das Programm eine Trotter-Zeitentwicklung, eine Schaltkreiskompression mittels approximativer Quantenkompilierung (AQC) sowie eine mitigierte Ausführung durch und gibt anschließend die Zeitreihen der einzelnen Observablen zurück. Tauscht man die Versuchsanordnung (PRE) und die Auswertung (POST) aus, führt derselbe Kern zu einem anderen Experiment:

PRE (Ihre Konfiguration)
FUNKTION (hier bereitgestellt)
POST (deine Analyse)
Bereiten Sie einen Zustand vor – als Schaltkreis oder Produktzustand – mit einem optionalen lokalen KickTrotter-Synthese → AQC-Komprimierung → Ausführung auf statevector, fake, oder runtime, mit der Rückgabe von „ ⟨O⟩(t)\langle O \rangle(t) “S(q,ω)S(q, \omega) für Neutronenstreuung oder Magnetisierung, Transport, Quench-Dynamik und so weiter

Die Vorlage ist im Qiskit-Repository für Funktionsvorlagen zusammen mit den anderen Anwendungsvorlagen veröffentlicht. Dieses Notebook stellt es in Ihrem eigenen „ Qiskit Serverless “-Konto bereit. Führen Sie den Code einmal aus, dann kann jedes Notebook die Funktion mit aufrufen serverless.load("aqc-dynamics-function").

Ein konkretes wissenschaftliches Beispiel finden Sie unter Simulation der Neutronenstreuung mit einem AQC + Trotter-Dynamik-Workflow ohne Server, in dem diese Funktion aufgerufen wird, um den dynamischen Strukturfaktor von KCuF3_3 zu berechnen. Dieses Notebook befasst sich stattdessen mit der Bereitstellung und dem Eingabekontrakt.


Anforderungen

Bevor Sie beginnen, vergewissern Sie sich, dass in der Kernel-Umgebung dieses Notebooks Folgendes vorhanden ist:

  • Qiskit SDK v2.0 oder höher (pip install qiskit).
  • Der Qiskit- IBM -Katalog-Client (pip install qiskit-ibm-catalog), der Workloads auf Qiskit Serverless bereitstellt und ausführt.

Die funktionsspezifischen wissenschaftlichen Abhängigkeiten (qiskit-addon-aqc-tensor, cotengrust, qiskit-aer) müssen nicht lokal installiert werden.


Laden Sie die Quelldateien der Vorlage herunter

Bei der Funktion handelt es sich um ein kleines „ Python “-Paket, das unter Qiskit Serverless in der Cloud ausgeführt wird. Daher muss der Quellcode als lokale Dateien vorliegen, die zum Zeitpunkt der Bereitstellung hochgeladen werden. Das Paket ist im Repository „Qiskit Function templates“ veröffentlicht.

Herunterladen source_files

Der Download besteht aus einer einzigen ZIP-Datei, deren Name sich nach dem vollständigen Pfad des Verzeichnisses im Repository richtet:

qiskit-community qiskit-function-templates main physics aqc_trotter source_files.zip

  1. Entpacken Sie die Datei in das Verzeichnis, in dem sich dieses Notizbuch befindet.
  2. Benenne den entpackten Ordner von diesem langen Namen in source_files. um.

Ihr Arbeitsverzeichnis sieht dann wie folgt aus:

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

Der Name muss genau so lauten source_files, denn das sind die Uploads aus Schritt working_dir 3.

program.py ist der Einstiegspunkt, den das Gateway aufruft. Alles unter source/ ist die Implementierung, unterteilt nach Phasen: Hamilton- und Trotter-Synthese, AQC-Komprimierung und Ausführung. Es sind keinerlei Änderungen erforderlich, um die folgenden Beispiele auszuführen. In Schritt 3 wird das gesamte Verzeichnis hochgeladen. Wiederholen Sie diesen Schritt daher jedes Mal, wenn Sie eine Datei ändern.


1. Authentifizierung

Verwenden Sie qiskit-ibm-catalog zur Authentifizierung bei QiskitServerless mit Ihrem API-Schlüssel (Token) und der „ CRN “ (Instanz), die Sie im Dashboard von „ IBM Quantum® Platform “ finden. Mit diesen Anmeldedaten können Sie den serverlosen Client lokal instanziieren, um die ausgewählte Funktion hochzuladen oder auszuführen:

from qiskit_ibm_catalog import QiskitServerless
serverless = QiskitServerless(channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN")

Optional können Sie verwenden, save_account() um Ihre Anmeldedaten in Ihrer lokalen Umgebung zu speichern (siehe die Anleitung „Einrichten Ihres IBM Cloud® -Kontos“ ). Beachten Sie, dass Ihre Anmeldedaten dabei in dieselbe Datei geschrieben werden wie bei QiskitRuntimeService.save_account():

QiskitServerless.save_account(channel="ibm_quantum_platform", token="MY_TOKEN", instance="MY_CRN")

Wenn das Konto gespeichert ist, muss zur Authentifizierung kein Token angegeben werden:

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. Abhängigkeiten deklarieren

Pakete, die die Funktion zusätzlich zum verwalteten Basis-Serverless-Image benötigt.

Note

Das Gateway installiert nur Namen, die in seiner Zulassungsliste (requirements-dynamic-dependencies.txt) aufgeführt sind, die anhand des Paketnamens abgeglichen und mit der zulässigen Version verknüpft sind ==. Alles andere muss transitiv bereitgestellt werden (als Abhängigkeit eines Pakets, das auf der Zulassungsliste steht). Die Syntax [extras] wird berücksichtigt: Damit werden qiskit-addon-aqc-tensor[quimb-jax] und quimb installiert jax. cotengrust wird für eine effiziente Speichernutzung bei der Simulation von Tensornetzwerken benötigt. qiskit-aer wird für das fake Backend (lokale Simulation mit Rauschen) separat aufgeführt.

DEPENDENCIES = [
    "qiskit-addon-aqc-tensor[quimb-jax]==0.3.1",
    "qiskit-aer==0.17.2",
    "cotengrust==0.2.0",
]

3. Die Funktion definieren und hochladen

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. Überprüfen Sie, ob es registriert ist

next(p for p in serverless.list() if p.title == "aqc-dynamics-function")

Output:

QiskitFunction(aqc-dynamics-function)

Funktionsübersicht

Dies ist eine kurze Einführung. Jedes Feld ist in der README-Datei zur AQC Dynamics-Vorlage ausführlich dokumentiert: die vollständige Eingabetabelle mit ihren Validierungsregeln, die Ausgabefelder, die Ausführungs-Backends sowie weitere ausgearbeitete Beispiele. Was nun folgt, ist die Kurzfassung – ausreichend, um die nachfolgenden Beispiele zu verstehen.

Eingaben

Jeder Durchlauf ist ein einzelner Aufruf fn.run(...) . Nur die ersten drei Einträge in der Tabelle sind erforderlich: hamiltonian, t_steps, und aqc_segments. Alles, was danach folgt, ist optional und wird auf die angezeigte Standardeinstellung zurückgesetzt. Ein minimaler Aufruf umfasst also drei Argumente, und der Rest der Tabelle enthält die Funktionen, die Sie optional nutzen können. Der Hamilton-Operator num_qubits legt die Kettenlänge fest, daher gibt es keine separate Eingabe für die Größe.

Eingabe
Standard
Beschreibung
Kolumne „ 4 “
hamiltonianerforderlich1D Pauli-Hamiltonian des nächsten Nachbarn als SparsePauliOp. Strings sind Pauli-Operatoren, daher gibt es keinen impliziten Faktor von einem Halb.
t_stepserforderlichGesamtzahl der Trotter-Schritte. Entwickelt sich zu T = t_steps * dt und gibt bei jedem jede Beobachtungsgröße an t_k = k * dt.
aqc_segmentserforderlichKomprimierungsplan: eine Liste von {"n_steps": k, "ansatz_steps": m}. sum(n_steps) Die Schritte sind komprimiert; der Rest läuft als normales Trotter.
dt0.2Die physikalische Zeit wurde um einen Trotter-Schritt vorgerückt.
initial_state`0...0>`Ein, das bereit ist, sich QuantumCircuit weiterzuentwickeln. Bringen Sie in dieser Rennstrecke etwas Lokales mit ein.
observablespro Standort ZAlles EstimatorV2 akzeptiert als Argument observables . Ein Beobachtungswert pro Ausgabespalte.
trotter_optionsSuzuki zweiter Ordnung{"method": ..., "synthesis_settings": {...}}. und reps time gehören der Funktion.
aqc_optionssiehe Beschreibungmax_bond (32), cutoff (1e-8), autodiff_backend ("jax"), fidelity_target (None), optimizer_settings (L-BFGS-B, jac=True, maxiter=300).
estimator_optionsDD, Wirbeln, TREXEstimatorV2.options, unverändert übernommen. Ein bereitgestelltes Wörterbuch ersetzt die Standardwörterbücher vollständig, anstatt sich mit ihnen zu vermischen.
transpiler_options{"optimization_level": 3}generate_preset_pass_manager Schlüsselwortargumente. backend und target werden verworfen, da sie zum Ausführungspfad gehören.
backend"runtime""statevector", "fake", oder "runtime".
backend_nameam wenigsten frequentiertIBM® Backend-Name für runtime… oder ein benanntes Schein-Backend.
batches1Verteilen Sie die Schaltkreise auf N Laufzeit-Jobs. Bei einem Batch-Lauf wird ein einzelner Auftrag übermittelt, ohne dass eine Sitzung erstellt wird.
parallel_simFalseVerteilen Sie die lokalen Simulatorpfade mit Ray auf alle verfügbaren Kerne. Keine Auswirkungen auf runtime.
return_circuitsFalseGeben Sie im Ergebnis neben der Beobachtungsreihe auch die logischen AQC- und Trotter-Schaltungen zurück.

Ausführungs-Backends

Alle drei Pfade verwenden denselben Code und dieselben Einstellungen zur Risikominderung. Sie unterscheiden sich lediglich darin, wo die Schaltkreise verlaufen.

backend
Was es ist
Berechtigungsnachweise
Hinweise
"statevector"Exakt StatevectorEstimatorNur für Serverless-KontenDer genaue Referenzpfad. Keine QPU-Zeit.
"fake"Lärmbehaftete lokale Simulation auf einem Qiskit-Fake-BackendNur für Serverless-KontenEine getreue Nachahmung des gemilderten runtime Weges. Bedarf qiskit-aer. Standardmäßig ist der 127-Qubit-Wert eingestellt fake_sherbrooke.
"runtime"(Standard)Die Gegenmaßnahmen EstimatorV2 gegen eine echte QPUServerless-Konto und eine Instanz mit QPU-Zugriffbackend_name optional; wird dieser Parameter weggelassen, wird das am wenigsten ausgelastete Gerät ausgewählt.

Beide Simulatorpfade rufen weiterhin die bereitgestellte Funktion auf, daher benötigen sie ein gespeichertes Serverless-Konto, auch wenn sie keine QPU-Zeit beanspruchen. In den beiden folgenden Beispielen wird dieselbe Arbeitslast zunächst statevector auf und anschließend auf ausgeführt runtime.

Ausgabe

job.result() gibt ein einfaches Wörterbuch zurück:

{
    "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 und circuit_stats sind die beiden, die man zuerst lesen sollte: Zusammen geben sie Aufschluss darüber, ob die Komprimierung originalgetreu geblieben ist und ob dadurch tatsächlich an Tiefe gewonnen wurde. Am resource_usage wird die Wartezeit in der Warteschlange getrennt von der QPU-Zeit ausgewiesen runtime, die Ihnen in Rechnung gestellt wird. Eine ungültige Eingabe wird als strukturierter ( ServerlessError Code 4615) schnell zurückgewiesen.


Simulator-Beispiel

Führen Sie die Funktion zunächst auf genau diesem Backend statevector aus. Es beansprucht keine QPU-Zeit und überprüft die Bereitstellung von Anfang bis Ende. Das vorliegende Modell ist eine Ising-Kette mit acht Qubits im transversalen Feld, und observables wird weggelassen, sodass die Funktion die standardmäßige „ ZZ “ pro Knoten misst.

Der Komprimierungsplan ist die Angabe, die man verstehen sollte. Jedes Segment {"n_steps": k, "ansatz_steps": m} fasst aufeinanderfolgende k Trotter-Schritte zu einem Ansatz zusammen, der aus einem m-Schritt-Trotter-Ziel aufgebaut ist, und alle darüber hinausgehenden Schritte werden als reines Trotter-Verfahren sum(n_steps) ausgeführt. Frühe Schritte mit geringer Verschränkung lassen sich gut in einen flachen einschichtigen Ansatz komprimieren; spätere Schritte mit stärkerer Verschränkung erfordern einen tieferen Ansatz.

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

Verfolgen Sie den Durchlauf und lesen Sie das Ergebnis ab

status() Gibt sowohl den groben Lebenszyklus des Auftrags als auch die Teilstatusangaben zu den einzelnen Phasen wieder, die die Funktion während ihrer Ausführung veröffentlicht. Die gleichen Schritte gelten auch für den Hardware-Durchlauf, der später in dieser Anleitung beschrieben wird:

QUEUED -> INITIALIZING -> RUNNING: OPTIMIZING_FOR_HARDWARE -> RUNNING: WAITING_FOR_QPU -> RUNNING: EXECUTING_QPU -> RUNNING: POST_PROCESSING -> DONE

status() Wert
Phase
RUNNING: OPTIMIZING_FOR_HARDWAREZustandsvorbereitung, Trotter-Aufbau, AQC-Kompression
RUNNING: WAITING_FOR_QPUin der Warteschlange der QPU (runtime nur Backend)
RUNNING: EXECUTING_QPUausgeführte Schaltkreise (lokale Simulatoren kennzeichnen dies direkt)
RUNNING: POST_PROCESSINGErstellen des Ergebniswörterbuchs

Die Endzustände sind DONE, ERROR, und CANCELED. Dieser statevector Durchlauf hat keine QPU-Warteschlange, daher wird er übersprungen RUNNING: WAITING_FOR_QPU. Verwenden Sie job.logs() an beliebiger Stelle, um die Protokolle der einzelnen Phasen anzuzeigen, einschließlich der in jedem Schritt erreichten AQC-Genauigkeit.

print(job.status())  # re-run until this reports DONE

Output:

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)

Beispiel für Hardware

Ein Funktionsaufruf wird auf einem echten „ IBM Quantum “-Prozessor transpiliert backend="runtime" und ausgeführt, wobei die in die Funktion integrierten Fehlerminderungsmechanismen zum Einsatz kommen: dynamische Entkopplung ( XY4 ), Gate-Twirling und Twirled Readout Error Extinction (TREX). backend_name wählt das Gerät aus; wird dieser Parameter weggelassen, wählt die Funktion das Gerät mit der geringsten Auslastung aus.

Am Wissenschaftscode ändert sich nichts. Im Vergleich zum Simulatorbeispiel unterscheiden sich die Kettenlänge, die Anzahl der Trotter-Schritte, der Komprimierungsplan, das Backend sowie die Einstellungen zur expliziten Fehlerbehebung, die im folgenden Abschnitt behandelt werden.

Dimensionierung der Aufgabe für die Steuerungshardware

estimator_options Lohnt es sich, diese Einstellung bewusst vorzunehmen? Beim „Gate Twirling“ werden für jeden „ PUB “ separate num_randomizations , zufällig generierte Schaltkreise erstellt, und der gesamte Vorgang – jeder „ PUB “ mit all seinen Zufallselementen – muss in den Befehlsspeicher des klassischen Steuerungssystems der QPU passen. Die Funktion ist standardmäßig auf 1000 Randomisierungen eingestellt, sodass eine 10-stufige Evolution 11 PUBs mit jeweils 1000 Schaltungen übermittelt: das sind etwa 11.000 Schaltungsinstanzen in einem einzigen Auftrag.

Wird der vom Steuerungssystem festgelegte Wert überschritten, schlägt der Vorgang mit dem Fehler 6073 fehl. Unter „Job-Limits“ werden die Grenzwerte und deren Berechnung erläutert. Der wichtigste Wert ist „ 26.8 “ Millionen Steuerbefehle pro Qubit, der pro Job und nicht pro „ PUB “ gilt. Bei der dynamischen Entkopplung werden Gatter hinzugefügt, die dazu beitragen.

Zwei Eingaben bestimmen die Größe:

  • estimator_options legt das Budget für die Aufnahmen fest. Die Gesamtzahl der Schüsse beträgt num_randomizations * shots_per_randomization, sodass man die Zufallsgenerierung gegen die Anzahl der Schüsse pro Zufallsgenerierung eintauschen, die Statistiken beibehalten und das Programm dennoch verkleinern kann. Die folgende Zelle verwendet 100 Randomisierungen mit jeweils 200 Schüssen, was 20.000 Schüssen pro Beobachtungsgröße entspricht und etwa einem Zehntel der Schaltungsinstanzen, die die Standardeinstellungen liefern würden. Eine vollständige Übersicht über alle Felder finden Sie unter „ TwirlingOptions “ und in den „Estimator“-Optionen.
  • batches teilt die PUBs auf so viele separate Laufzeit-Jobs auf – genau das ist die Abhilfe, die der Fehler 6073 selbst vorschlägt, und der Grund, warum die Framing-Einstellung pro Job von Bedeutung ist. Mit dieser Einstellung werden pro Auftrag etwa drei PUBs statt elf auf einmal gesendet batches=4 , und die Aufträge werden gemeinsam in einem Stapel versendet, sodass die Gruppe nur einmal in die Warteschlange gestellt wird, anstatt dass jeder Auftrag einzeln in die Warteschlange gestellt wird.

Beachten Sie, dass eine angegebene Einstellung die Standardwerte der Funktion vollständig ersetzt estimator_options , anstatt mit diesen zusammengeführt zu werden. Daher werden „Dynamische Entkopplung“ und „TREX“ in der folgenden Zelle erneut festgelegt, um sicherzustellen, dass sie aktiviert bleiben.

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
Erneute Verbindung zu einem seit Langem laufenden Job herstellen

Ein Hardware-Lauf dauert seine Zeit, und der Großteil der Zeit wird eher klassisch als auf der QPU verbracht. Die AQC-Komprimierung läuft innerhalb der Funktion ab, bevor irgendetwas die QPU erreicht, und die QPU-Warteschlange wird darüberhinaus noch hinzugefügt. Sie müssen dieses Notizbuch oder diesen Kernel während der Ausführung nicht geöffnet lassen.

Kopieren Sie die in der vorherigen Zelle angezeigte Auftrags-ID und speichern Sie sie. In den nächsten drei Zellen können Sie den Lauf später fortsetzen:

  1. Erneut verbinden – nur in einer neuen Kernel-Sitzung erforderlich: Führen Sie die Authentifizierungszelle erneut aus, um sie neu zu erstellen serverless, und bauen Sie anschließend den job Handle anhand der von Ihnen gespeicherten ID wieder auf. Überspringen Sie diese Zelle, wenn Sie sich noch in der Sitzung befinden, in der Sie die Daten übermittelt haben, da das Handle bereits aktiv ist.
  2. Status prüfen: So lange wiederholen, bis die Meldung erscheint DONE.
  3. Ergebnis abrufen: Erst ausführen, wenn der Status ist DONE.

Fügen Sie Ihre gespeicherte ID anstelle des Platzhalters in die folgende Zelle „Erneut verbinden“ ein.

# 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)

Nächste Schritte

Empfehlungen
War diese Seite hilfreich?
Melden Sie auf GitHub einen Fehler, einen Tippfehler oder fordern Sie Inhalte an.