To't Hauptinholt springen

Grundtostandsenergie-Schätzung vun de Heisenberg-Keed mit VQE

Schätzung för de Bruuk: Twee Minuten op en Eagle r3 Prozessor (ANMARKEN: Dat is bloots en Schätzung. Dien Looptiet kann anners ween.)

Achtergrund

Düt Tutorial wiest, wo een en Qiskit pattern buut, deployt un lopen lött för de Simulation vun en Heisenberg-Keed un för de Schätzung vun de Grundtostandsenergie. Mehr Informatschonen över Qiskit patterns un wo Qiskit Serverless bruukt warden kann för ehr na de Wulk to deployen för verwaltete Utföhrung finnst du op uns Doku-Sied över IBM Quantum® Platform.

Vörutsetten

Bevör mit düt Tutorial anfungen ward, stell seker, dat du dat Folgen installeert hest:

  • Qiskit SDK v1.2 oder neeger, mit Visualisierung Ünnerstütten
  • Qiskit Runtime v0.28 oder neeger (pip install qiskit-ibm-runtime)
  • Qiskit Serverless (pip install qiskit_serverless)
  • IBM Catalog (pip install qiskit-ibm-catalog)

Setup

import numpy as np
import matplotlib.pyplot as plt

from scipy.optimize import minimize
from typing import Sequence

from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.primitives.base import BaseEstimatorV2
from qiskit.circuit.library import XGate
from qiskit.circuit.library import efficient_su2
from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes.scheduling import (
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
)

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session, Estimator

from qiskit_ibm_catalog import QiskitServerless, QiskitFunction
def visualize_results(results):
plt.plot(results["cost_history"], lw=2)
plt.xlabel("Iteration")
plt.ylabel("Energy")
plt.show()

def build_callback(
ansatz: QuantumCircuit,
hamiltonian: SparsePauliOp,
estimator: BaseEstimatorV2,
callback_dict: dict,
):
def callback(current_vector):
# Keep track of the number of iterations
callback_dict["iters"] += 1
# Set the prev_vector to the latest one
callback_dict["prev_vector"] = current_vector
# Compute the value of the cost function at the current vector
current_cost = (
estimator.run([(ansatz, hamiltonian, [current_vector])])
.result()[0]
.data.evs[0]
)
callback_dict["cost_history"].append(current_cost)
# Print to screen on single line
print(
"Iters. done: {} [Current cost: {}]".format(
callback_dict["iters"], current_cost
),
end="\r",
flush=True,
)

return callback

Schritt 1: Klassische Ingaav op en Quantenprobleem mappen

  • Ingaav: Antall vun Spins
  • Utgaav: Ansatz un Hamiltonian för de Modellierung vun de Heisenberg-Keed

Buut en Ansatz un Hamiltonian, de en 10-Spin Heisenberg-Keed modelleert. Eerst importeert wi en poor generische Pakete un maakt en poor Hölpfunkschonen.

num_spins = 10
ansatz = efficient_su2(num_qubits=num_spins, reps=3)

# Remember to insert your token in the QiskitRuntimeService constructor
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, min_num_qubits=num_spins, simulator=False
)

coupling = backend.target.build_coupling_map()
reduced_coupling = coupling.reduce(list(range(num_spins)))

edge_list = reduced_coupling.graph.edge_list()
ham_list = []

for edge in edge_list:
ham_list.append(("ZZ", edge, 0.5))
ham_list.append(("YY", edge, 0.5))
ham_list.append(("XX", edge, 0.5))

for qubit in reduced_coupling.physical_qubits:
ham_list.append(("Z", [qubit], np.random.random() * 2 - 1))

hamiltonian = SparsePauliOp.from_sparse_list(ham_list, num_qubits=num_spins)

ansatz.draw("mpl", style="iqp")

Output of the previous code cell

Schritt 2: Probleem för Quantenhardware-Utföhrung optimeren

  • Ingaav: Abstrakte Schaltkreis, Observable
  • Utgaav: Target-Schaltkreis un Observable, optimiert för de utköörte QPU

Bruukt de generate_preset_pass_manager Funkschoon ut Qiskit för automaatsch en Optimerengsroutine för uns Schaltkreis mit Betreck op de utköörte QPU to genereren. Wi wählt optimization_level=3, wat de högste Level vun Optimerung vun de Preset-Pass-Manager is. Wi slütt ok ALAPScheduleAnalysis un PadDynamicalDecoupling Scheduling-Passes in för Dekohärenzföhlers to ünnerdröcken.

target = backend.target
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
pm.scheduling = PassManager(
[
ALAPScheduleAnalysis(durations=target.durations()),
PadDynamicalDecoupling(
durations=target.durations(),
dd_sequence=[XGate(), XGate()],
pulse_alignment=target.pulse_alignment,
),
]
)
ansatz_ibm = pm.run(ansatz)
observable_ibm = hamiltonian.apply_layout(ansatz_ibm.layout)
ansatz_ibm.draw("mpl", scale=0.6, style="iqp", fold=-1, idle_wires=False)

Output of the previous code cell

Schritt 3: Mit Qiskit Primitives utföhren

  • Ingaav: Target-Schaltkreis un Observable
  • Utgaav: Resultaten vun de Optimerung

Minimert de schätzde Grundtostandsenergie vun dat System dör Optimerung vun de Schaltkreis-Parameters. Bruukt de Estimator Primitive ut Qiskit Runtime för de Kostfunkschoon während de Optimerung to evalueren.

För düt Demo lopt wi op en QPU mit qiskit-ibm-runtime Primitives. För mit qiskit statevector-baseerte Primitives to lopen, vervangt den Block vun den Code, de Qiskit IBM Runtime Primitives bruukt, dör den kommenteerte Block.

# SciPy minimizer routine
def cost_func(
params: Sequence,
ansatz: QuantumCircuit,
hamiltonian: SparsePauliOp,
estimator: BaseEstimatorV2,
) -> float:
"""Ground state energy evaluation."""
return (
estimator.run([(ansatz, hamiltonian, [params])])
.result()[0]
.data.evs[0]
)

num_params = ansatz_ibm.num_parameters
params = 2 * np.pi * np.random.random(num_params)

callback_dict = {
"prev_vector": None,
"iters": 0,
"cost_history": [],
}

# Evaluate the problem on a QPU by using Qiskit IBM Runtime
with Session(backend=backend) as session:
estimator = Estimator()
callback = build_callback(
ansatz_ibm, observable_ibm, estimator, callback_dict
)
res = minimize(
cost_func,
x0=params,
args=(ansatz_ibm, observable_ibm, estimator),
callback=callback,
method="cobyla",
options={"maxiter": 100},
)

visualize_results(callback_dict)

Schritt 4: Nabearbeiden un Resultaat in dat wünschte klassische Formaat torüchgeven

  • Ingaav: Grundtostandsenergie-Schätzungen während de Optimerung
  • Utgaav: Schätzde Grundtostandsenergie
print(f'Estimated ground state energy: {res["fun"]}')

Dat Qiskit-Muster na de Wulk deployen

För dat to doon, verschuuv den Quellcode baven na en Datei, ./source/heisenberg.py, pack den Code in en Skript, dat Ingaav annimmt un de endgültige Lösing torüchgifft, un laad dat denn na en Remote-Cluster hoch mit de QiskitFunction Klass ut qiskit-ibm-catalog. För Anwiesen över dat Spezifizeren vun externeAfhängigkeiten, dat Övergeven vun Ingaav-Argumenten un mehr, kiek na de Qiskit Serverless guides.

De Ingaav för dat Pattern is de Antall vun Spins in de Keed. De Utgaav is en Schätzung vun de Grundtostandsenergie vun dat System.

# Authenticate to the remote cluster and submit the pattern for remote execution
serverless = QiskitServerless()
heisenberg_function = QiskitFunction(
title="ibm_heisenberg",
entrypoint="heisenberg.py",
working_dir="./source/",
)
serverless.upload(heisenberg_function)

Dat Qiskit-Muster as verwalteten Service lopen laten

Wenn wi dat Pattern na de Wulk hoochlaadt hemmt, köönt wi dat eenfach mit den QiskitServerless Client lopen laten.

# Run the pattern on the remote cluster

ibm_heisenberg = serverless.load("ibm_heisenberg")
job = serverless.run(ibm_heisenberg)
solution = job.result()

print(solution)
print(job.logs())

Tutorial-Ümfraag

Bitte maakt düsse korte Ümfraag för Feedback över düt Tutorial to geven. Dien Insichten hölpt uns, uns Inholtsangeboden un Brukerervahren to verbetern.

Link na de Ümfraag