Přeskočit na hlavní obsah

Přibližná kvantová kompilace pro obvody časového vývoje

Odhadovaná náročnost: pět minut na procesoru Eagle (POZNÁMKA: Jedná se pouze o odhad. Skutečná doba běhu se může lišit.)

Pozadí

Tento tutoriál ukazuje, jak implementovat přibližnou kvantovou kompilaci pomocí tenzorových sítí (AQC-Tensor) s Qiskit pro zlepšení výkonu kvantových obvodů. AQC-Tensor aplikujeme v kontextu Trotterizovaného časového vývoje, abychom snížili hloubku obvodu při zachování přesnosti simulace — v souladu s frameworkem Qiskit pro přípravu stavů a optimalizaci. Naučíš se, jak vytvořit nízko-hloubkový ansatz Circuit z počátečního Trotter obvodu, optimalizovat ho pomocí tenzorových sítí a připravit ho pro spuštění na kvantovém hardwaru.

Primárním cílem je simulovat časový vývoj modelového hamiltoniánu se sníženou hloubkou obvodu. K tomu slouží doplněk AQC-Tensor pro Qiskit, qiskit-addon-aqc-tensor, který využívá tenzorové sítě — konkrétně stavy maticových součinů (MPS) — ke kompresi a optimalizaci počátečního obvodu. Iterativními úpravami komprimovaný ansatz Circuit zachovává věrnost původnímu obvodu a zároveň zůstává proveditelný na near-term kvantovém hardwaru. Další podrobnosti najdeš v příslušné dokumentaci a jednoduchém příkladu pro začátek.

Přibližná kvantová kompilace je obzvláště výhodná v kvantových simulacích, které překračují dobu koherence hardwaru, protože umožňuje provádět složité simulace efektivněji. Tento tutoriál tě provede nastavením pracovního postupu AQC-Tensor v Qiskit, včetně inicializace hamiltoniánu, generování Trotter obvodů a transpilace finálního optimalizovaného obvodu pro cílové zařízení.

Požadavky

Před zahájením tohoto tutoriálu se ujisti, že máš nainstalováno následující:

  • Qiskit SDK v1.0 nebo novější s podporou vizualizace
  • Qiskit Runtime v0.22 nebo novější (pip install qiskit-ibm-runtime)
  • Doplněk AQC-Tensor pro Qiskit (pip install 'qiskit-addon-aqc-tensor[aer,quimb-jax]')

Nastavení

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-aqc-tensor qiskit-addon-utils qiskit-ibm-runtime quimb rustworkx scipy
import numpy as np
import quimb.tensor
import datetime
import matplotlib.pyplot as plt

from scipy.optimize import OptimizeResult, minimize

from qiskit.quantum_info import SparsePauliOp, Pauli
from qiskit.transpiler import CouplingMap
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit import QuantumCircuit
from qiskit.synthesis import SuzukiTrotter

from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit_addon_aqc_tensor.ansatz_generation import (
generate_ansatz_from_circuit,
)
from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity
from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
from qiskit_addon_aqc_tensor.simulation import compute_overlap

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator

from rustworkx.visualization import graphviz_draw

Část I. Malý příklad

První část tohoto tutoriálu používá malý příklad s 10 uzly, aby ilustrovala proces mapování kvantového simulačního problému na spustitelný kvantový Circuit. Zde prozkoumáme dynamiku modelu XXZ s 10 uzly, což nám umožní sestavit a optimalizovat zvládnutelný kvantový Circuit před přechodem na větší systémy.

Model XXZ je v fyzice hojně studován pro zkoumání spinových interakcí a magnetických vlastností. Hamiltonián nastavíme s otevřenými okrajovými podmínkami a interakcemi závislými na poloze uzlu mezi sousedními uzly v řetězci.

Hamiltonián modelu a pozorovatelná

Hamiltonián pro náš model XXZ s 10 uzly je definován jako:

H^XXZ=i=1L1Ji,(i+1)(XiX(i+1)+YiY(i+1)+2ZiZ(i+1)),\hat{\mathcal{H}}_{XXZ} = \sum_{i=1}^{L-1} J_{i,(i+1)}\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ 2\cdot Z_i Z_{(i+1)} \right) \, ,

kde Ji,(i+1)J_{i,(i+1)} je náhodný koeficient odpovídající hraně (i,i+1)(i, i+1) a L=10L=10 je počet uzlů.

Simulací vývoje tohoto systému se sníženou hloubkou obvodu získáme přehled o tom, jak AQC-Tensor využívat ke kompresi a optimalizaci obvodů.

Nastavení hamiltoniánu a pozorovatelné

Než namapujeme náš problém, musíme nastavit mapu propojení (coupling map), hamiltonián a pozorovatelnou pro model XXZ s 10 uzly.

# L is the number of sites, also the length of the 1D spin chain
L = 10

# Generate the coupling map
edge_list = [(i - 1, i) for i in range(1, L)]
# Generate an edge-coloring so we can make hw-efficient circuits
even_edges = edge_list[::2]
odd_edges = edge_list[1::2]
coupling_map = CouplingMap(edge_list)

# Generate random coefficients for our XXZ Hamiltonian
np.random.seed(0)
Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)
hamiltonian = SparsePauliOp(Pauli("I" * L))
for i, edge in enumerate(even_edges + odd_edges):
hamiltonian += SparsePauliOp.from_sparse_list(
[
("XX", (edge), Js[i] / 2),
("YY", (edge), Js[i] / 2),
("ZZ", (edge), Js[i]),
],
num_qubits=L,
)

# Generate a ZZ observable between the two middle qubits
observable = SparsePauliOp.from_sparse_list(
[("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)

print("Hamiltonian:", hamiltonian)
print("Observable:", observable)
graphviz_draw(coupling_map.graph, method="circo")
Hamiltonian: SparsePauliOp(['IIIIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII'],
coeffs=[1. +0.j, 0.52440675+0.j, 0.52440675+0.j, 1.0488135 +0.j,
0.60759468+0.j, 0.60759468+0.j, 1.21518937+0.j, 0.55138169+0.j,
0.55138169+0.j, 1.10276338+0.j, 0.52244159+0.j, 0.52244159+0.j,
1.04488318+0.j, 0.4618274 +0.j, 0.4618274 +0.j, 0.9236548 +0.j,
0.57294706+0.j, 0.57294706+0.j, 1.14589411+0.j, 0.46879361+0.j,
0.46879361+0.j, 0.93758721+0.j, 0.6958865 +0.j, 0.6958865 +0.j,
1.391773 +0.j, 0.73183138+0.j, 0.73183138+0.j, 1.46366276+0.j])
Observable: SparsePauliOp(['IIIIZZIIII'],
coeffs=[1.+0.j])

Output of the previous code cell

Po definování hamiltoniánu můžeme přistoupit k sestavení počátečního stavu.

# Generate an initial state
initial_state = QuantumCircuit(L)
for i in range(L):
if i % 2:
initial_state.x(i)

Krok 1: Mapování klasických vstupů na kvantový problém

Nyní, když jsme sestavili hamiltonián definující spin-spinové interakce a vnější magnetická pole charakterizující systém, postupujeme ve třech hlavních krocích pracovního postupu AQC-Tensor:

  1. Vygenerování optimalizovaného obvodu AQC: Pomocí Trotterizace přibližujeme počáteční vývoj, který je poté zkomprimován za účelem snížení hloubky obvodu.
  2. Vytvoření zbývajícího obvodu časového vývoje: Zachycení vývoje pro zbývající čas za počátečním segmentem.
  3. Spojení obvodů: Sloučení optimalizovaného obvodu AQC se zbývajícím evolučním obvodem do kompletního obvodu časového vývoje připraveného ke spuštění.

Tento přístup vytváří nízko-hloubkový ansatz pro cílový vývoj, čímž podporuje efektivní simulaci v rámci omezení near-term kvantového hardwaru.

Určení části časového vývoje k simulaci klasicky

Naším cílem je simulovat časový vývoj dříve definovaného modelového hamiltoniánu pomocí Trotter evoluce. Aby byl tento proces efektivní pro kvantový hardware, rozdělíme vývoj do dvou segmentů:

  • Počáteční segment: Tato počáteční část vývoje, od ti=0.0t_i = 0.0 do tf=0.2t_f = 0.2, je simulovatelná pomocí MPS a lze ji efektivně „zkompilovat" pomocí AQC-Tensor. Pomocí doplňku AQC-Tensor pro Qiskit vygenerujeme komprimovaný Circuit pro tento segment, označovaný jako aqc_target_circuit. Protože tento segment bude simulován na simulátoru tenzorových sítí, můžeme si dovolit použít vyšší počet Trotter vrstev, aniž by to výrazně zatěžovalo hardwarové zdroje. Pro tento segment nastavíme aqc_target_num_trotter_steps = 32.

  • Následující segment: Tato zbývající část vývoje, od t=0.2t = 0.2 do t=0.4t = 0.4, bude spuštěna na kvantovém hardwaru a je označována jako subsequent_circuit. S ohledem na omezení hardwaru se snažíme použít co nejméně Trotter vrstev, aby hloubka obvodu zůstala zvládnutelná. Pro tento segment použijeme subsequent_num_trotter_steps = 3.

Volba času rozdělení

Jako čas rozdělení volíme t=0.2t = 0.2, abychom vyrovnali klasickou simulovatelnost s proveditelností na hardwaru. Na začátku vývoje zůstává provázanost v modelu XXZ dostatečně nízká, aby ji klasické metody jako MPS mohly přesně aproximovat.

Při volbě času rozdělení je dobrým vodítkem vybrat bod, kde je provázanost stále zvládnutelná klasicky, ale zachycuje dostatek vývoje, aby zjednodušila část prováděnou na hardwaru. Pro různé hamiltoniány může být nutné metodou pokus-omyl najít nejlepší rovnováhu.

# Generate the AQC target circuit (initial segment)
aqc_evolution_time = 0.2
aqc_target_num_trotter_steps = 32

aqc_target_circuit = initial_state.copy()
aqc_target_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
time=aqc_evolution_time,
),
inplace=True,
)
# Generate the subsequent circuit
subsequent_num_trotter_steps = 3
subsequent_evolution_time = 0.2

subsequent_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
time=subsequent_evolution_time,
)
subsequent_circuit.draw("mpl", fold=-1)

Output of the previous code cell

Pro smysluplné srovnání vygenerujeme dva další obvody:

  • Srovnávací obvod AQC: Tento Circuit vyvíjí systém až do aqc_evolution_time, ale používá stejný časový krok Trotter jako subsequent_circuit. Slouží ke srovnání s aqc_target_circuit a ukazuje vývoj, který bychom pozorovali bez použití zvýšeného počtu Trotter kroků. Tento Circuit budeme označovat jako aqc_comparison_circuit.

  • Referenční Circuit: Tento Circuit slouží jako základní linie pro získání přesného výsledku. Simuluje úplný vývoj pomocí tenzorových sítí k výpočtu přesného výsledku a poskytuje referenci pro hodnocení účinnosti AQC-Tensor. Tento Circuit budeme označovat jako reference_circuit.

# Generate the AQC comparison circuit
aqc_comparison_num_trotter_steps = int(
subsequent_num_trotter_steps
/ subsequent_evolution_time
* aqc_evolution_time
)
print(
"Number of Trotter steps for comparison:",
aqc_comparison_num_trotter_steps,
)

aqc_comparison_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_comparison_num_trotter_steps),
time=aqc_evolution_time,
)
Number of Trotter steps for comparison: 3
# Generate the reference circuit
evolution_time = 0.4
reps = 200

reference_circuit = initial_state.copy()
reference_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=reps),
time=evolution_time,
),
inplace=True,
)

Vygenerování ansatzu a počátečních parametrů z Trotter obvodu s menším počtem kroků

Nyní, když jsme sestavili naše čtyři obvody, přistoupíme k pracovnímu postupu AQC-Tensor. Nejprve sestavíme „dobrý" Circuit, který má stejný čas vývoje jako cílový Circuit, ale s menším počtem Trotter kroků (a tedy méně vrstvami).

Poté předáme tento „dobrý" Circuit funkci generate_ansatz_from_circuit z AQC-Tensor. Tato funkce analyzuje dvouQubitovou konektivitu Circuit a vrátí dvě věci:

  1. Obecný, parametrizovaný ansatz Circuit se stejnou dvouQubitovou konektivitou jako vstupní Circuit.
  2. Parametry, které po vložení do ansatzu dají vstupní (dobrý) Circuit.

Brzy vezmeme tyto parametry a iterativně je upravíme, abychom ansatz Circuit přiblížili co nejvíce k cílovému MPS.

aqc_ansatz_num_trotter_steps = 1

aqc_good_circuit = initial_state.copy()
aqc_good_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
time=aqc_evolution_time,
),
inplace=True,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
aqc_good_circuit
)
aqc_ansatz.draw("mpl", fold=-1)

Output of the previous code cell

print(f"AQC Comparison circuit: depth {aqc_comparison_circuit.depth()}")
print(f"Target circuit: depth {aqc_target_circuit.depth()}")
print(
f"Ansatz circuit: depth {aqc_ansatz.depth()}, with {len(aqc_initial_parameters)} parameters"
)
AQC Comparison circuit: depth 36
Target circuit: depth 385
Ansatz circuit: depth 7, with 156 parameters

Volba nastavení pro simulaci tenzorové sítě

Zde používáme simulátor Circuit s maticovými součiny (MPS) od Quimb spolu s jax pro výpočet gradientu.

simulator_settings = QuimbSimulator(
quimb.tensor.CircuitMPS, autodiff_backend="jax"
)

Dále sestavíme MPS reprezentaci cílového stavu, který bude aproximován pomocí AQC-Tensor. Tato reprezentace umožňuje efektivní práci s provázaností a poskytuje kompaktní popis kvantového stavu pro další optimalizaci.

aqc_target_mps = tensornetwork_from_circuit(
aqc_target_circuit, simulator_settings
)
print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())

# Obtains the reference MPS, where we can obtain the exact expectation value by examining the `local_expectation``
reference_mps = tensornetwork_from_circuit(
reference_circuit, simulator_settings
)
reference_expval = reference_mps.local_expectation(
quimb.pauli("Z") & quimb.pauli("Z"), (L // 2 - 1, L // 2)
).real.item()
print("Reference MPS maximum bond dimension:", reference_mps.psi.max_bond())
Target MPS maximum bond dimension: 5
Reference MPS maximum bond dimension: 7

Všimni si, že volbou vyššího počtu Trotter kroků pro cílový stav jsme efektivně snížili jeho Trotter chybu oproti počátečnímu Circuit. Věrnost (ψ1ψ22|\langle \psi_1 | \psi_2 \rangle|^2) mezi stavem připraveným počátečním Circuit a cílovým stavem můžeme vyhodnotit, abychom kvantifikovali tento rozdíl.

good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)
starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2
print("Starting fidelity:", starting_fidelity)
Starting fidelity: 0.9982464959067222

Optimalizace parametrů ansatzu pomocí výpočtů MPS

V tomto kroku optimalizujeme parametry ansatzu minimalizací jednoduché účelové funkce MaximizeStateFidelity pomocí optimalizátoru L-BFGS ze SciPy. Zvolíme kritérium zastavení pro věrnost, které zajistí, že překročí věrnost počátečního Circuit bez AQC-Tensor. Jakmile je tohoto prahu dosaženo, komprimovaný Circuit bude vykazovat jak nižší Trotter chybu, tak sníženou hloubku oproti původnímu Circuit. Použitím dalšího času CPU může pokračující optimalizace věrnost dále zvyšovat.

# Setting values for the optimization
aqc_stopping_fidelity = 1
aqc_max_iterations = 500

stopping_point = 1.0 - aqc_stopping_fidelity
objective = MaximizeStateFidelity(
aqc_target_mps, aqc_ansatz, simulator_settings
)

def callback(intermediate_result: OptimizeResult):
fidelity = 1 - intermediate_result.fun
print(
f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}"
)
if intermediate_result.fun < stopping_point:
# Good enough for now
raise StopIteration

result = minimize(
objective,
aqc_initial_parameters,
method="L-BFGS-B",
jac=True,
options={"maxiter": aqc_max_iterations},
callback=callback,
)
if (
result.status
not in (
0,
1,
99,
)
): # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration
raise RuntimeError(
f"Optimization failed: {result.message} (status={result.status})"
)

print(f"Done after {result.nit} iterations.")
aqc_final_parameters = result.x
2025-04-14 11:46:52.174235 Intermediate result: Fidelity 0.99795851
2025-04-14 11:46:52.218249 Intermediate result: Fidelity 0.99822826
2025-04-14 11:46:52.280924 Intermediate result: Fidelity 0.99829675
2025-04-14 11:46:52.356214 Intermediate result: Fidelity 0.99832474
2025-04-14 11:46:52.411609 Intermediate result: Fidelity 0.99836131
2025-04-14 11:46:52.453747 Intermediate result: Fidelity 0.99839954
2025-04-14 11:46:52.496184 Intermediate result: Fidelity 0.99846517
2025-04-14 11:46:52.542046 Intermediate result: Fidelity 0.99865029
2025-04-14 11:46:52.583679 Intermediate result: Fidelity 0.99872332
2025-04-14 11:46:52.628732 Intermediate result: Fidelity 0.99892359
2025-04-14 11:46:52.690386 Intermediate result: Fidelity 0.99900640
2025-04-14 11:46:52.759398 Intermediate result: Fidelity 0.99907169
2025-04-14 11:46:52.819496 Intermediate result: Fidelity 0.99911423
2025-04-14 11:46:52.884505 Intermediate result: Fidelity 0.99918716
2025-04-14 11:46:52.947919 Intermediate result: Fidelity 0.99921278
2025-04-14 11:46:53.012808 Intermediate result: Fidelity 0.99924853
2025-04-14 11:46:53.083626 Intermediate result: Fidelity 0.99928797
2025-04-14 11:46:53.153235 Intermediate result: Fidelity 0.99933028
2025-04-14 11:46:53.221371 Intermediate result: Fidelity 0.99935757
2025-04-14 11:46:53.286211 Intermediate result: Fidelity 0.99938140
2025-04-14 11:46:53.352391 Intermediate result: Fidelity 0.99940964
2025-04-14 11:46:53.420472 Intermediate result: Fidelity 0.99944051
2025-04-14 11:46:53.486279 Intermediate result: Fidelity 0.99946828
2025-04-14 11:46:53.552338 Intermediate result: Fidelity 0.99948723
2025-04-14 11:46:53.618688 Intermediate result: Fidelity 0.99951011
2025-04-14 11:46:53.690878 Intermediate result: Fidelity 0.99954718
2025-04-14 11:46:53.762725 Intermediate result: Fidelity 0.99956267
2025-04-14 11:46:53.829784 Intermediate result: Fidelity 0.99958949
2025-04-14 11:46:53.897477 Intermediate result: Fidelity 0.99960498
2025-04-14 11:46:53.954633 Intermediate result: Fidelity 0.99961308
2025-04-14 11:46:54.010125 Intermediate result: Fidelity 0.99962894
2025-04-14 11:46:54.064717 Intermediate result: Fidelity 0.99964121
2025-04-14 11:46:54.118892 Intermediate result: Fidelity 0.99964348
2025-04-14 11:46:54.183236 Intermediate result: Fidelity 0.99964860
2025-04-14 11:46:54.245521 Intermediate result: Fidelity 0.99965695
2025-04-14 11:46:54.305792 Intermediate result: Fidelity 0.99966398
2025-04-14 11:46:54.355819 Intermediate result: Fidelity 0.99967816
2025-04-14 11:46:54.409580 Intermediate result: Fidelity 0.99968293
2025-04-14 11:46:54.457979 Intermediate result: Fidelity 0.99968936
2025-04-14 11:46:54.505891 Intermediate result: Fidelity 0.99969223
2025-04-14 11:46:54.551084 Intermediate result: Fidelity 0.99970009
2025-04-14 11:46:54.601817 Intermediate result: Fidelity 0.99970724
2025-04-14 11:46:54.650097 Intermediate result: Fidelity 0.99970987
2025-04-14 11:46:54.714727 Intermediate result: Fidelity 0.99971237
2025-04-14 11:46:54.780052 Intermediate result: Fidelity 0.99971916
2025-04-14 11:46:54.871994 Intermediate result: Fidelity 0.99971940
2025-04-14 11:46:54.958244 Intermediate result: Fidelity 0.99972465
2025-04-14 11:46:55.011057 Intermediate result: Fidelity 0.99972763
2025-04-14 11:46:55.175339 Intermediate result: Fidelity 0.99972894
2025-04-14 11:46:56.688912 Intermediate result: Fidelity 0.99972894
Done after 50 iterations.
parameters = [float(param) for param in aqc_final_parameters]
print("Final parameters:", parameters)
Final parameters: [-7.853983035039254, 1.5707966468427772, 1.5707962768868613, -1.570798010835122, 1.570794480409574, 1.5707972214146968, -1.570796593027083, 1.5707968206822998, -1.5707959018046258, -1.5707991700969144, 1.5707965852600927, 4.712386891737442, -7.853980840717957, 1.5707967508132654, 1.5707943162503217, -1.5707955382023582, 1.5707958007156742, 1.570796096113293, -1.5707928509846847, 1.5707971042943747, -1.570797909276557, -1.5707941020637393, 1.5707980179540793, 4.712389823219363, -1.5707928752386107, 1.5707996426312891, -1.5707975640471001, -1.570794132802984, 1.5707944361599957, 4.712390747060803, 0.1048818190315936, 0.06686710468840577, -0.0668645844756557, -3.1415923537135466, 1.2374931269696063, 6.323169390432535e-07, 3.53229204771738e-08, 2.1091105688681484, 6.283186439944202, 0.12152258846156239, 0.07961752617254866, -0.07961775088604585, -1.6564278051174865e-06, 2.0771163596472384, 3.141592651630471, -6.283185775192653, 1.7691609006726954, 3.1415922910116216, 0.19837572065074083, 0.11114901449078964, -0.11115124544944892, -3.141591983034976, 0.8570788408766729, 4.201601390404146e-07, -3.141593736550978, 0.34652010942396333, 6.283186232785291, 0.13606356527241956, 0.03891676349289617, -0.03891524189533726, -1.5707965732853424, 1.5707968967088564, -0.3086133992238162, 1.5707957152428194, 1.5707968398959653, -0.32062737993080026, 0.11027416939993417, 0.0726167290795046, -0.07262020423334464, -2.3729431959735024e-06, 1.8204437429254703, 9.299060301196612e-07, -3.141592899563451, 2.103269568939461, 3.1415937539734626, 0.11536891854817125, 0.09099022308254198, -0.09098864958606581, -3.1415913307373127, 2.078429034357281, -1.509777998069368e-06, -3.1415922600663255, 1.5189162645358172, -3.1415878461323583, 0.09999070991480716, 0.04352011445148391, -0.04351849541849812, -1.570797642506462, 1.570795238023824, 0.8903442644396505, 1.5707962698006606, 1.5707946765132268, 0.9098791754570567, 0.10448284343424026, 0.07317037684936827, -0.07316718173961152, -3.141592682240966, 2.1665363080039612, -7.450882112394189e-07, -5.771181304929921e-07, 2.615334999517103, -3.1415914971653898, 0.1890887078648001, 0.13578163074571992, -0.13578078143610256, 7.156734195912883e-07, 1.7915385305413096, -5.188866034727312e-07, 1.2827742939197711e-06, 1.2348316581417487, 6.28318357406372, 0.08061187643781703, 0.03820789039271876, -0.03820731868804904, 1.5707964027727628, 1.570798734462218, 4.387336153720882, -1.570795722044763, 1.570798457375325, 4.450361734163248, 0.092360147257953, 0.06047700345049011, -0.06048592856713045, -3.141591214829027, 2.6593289993286047, -2.366937342261038e-07, 8.112162974032695e-08, 1.8907014631413432, 8.355881261853104e-07, 0.23303641819370874, 0.14331998953606456, -0.1433194488304741, -3.141591621822901, 0.7455776479558791, 3.1415914520163586, -3.1415933560496105, 0.7603938554148255, -1.6230983177616282e-06, 0.07186349688535713, 0.03197144517771341, -0.031971177878588546, -4.712389048748508, 1.5707948403165752, 1.2773619319829186, -1.5707990802172127, 1.5707957676951863, 1.289083769394045, 0.13644999397718796, 0.032761460443590046, -0.032762060585195645, -1.5707977610073176, 1.5707964181578042, -3.4826435600366983, -4.712389691708343, 1.570794277502252, 2.799088046133275]

V tomto okamžiku stačí najít finální parametry ansatz Circuit. Poté můžeme sloučit optimalizovaný Circuit AQC se zbývajícím evolučním obvodem a vytvořit kompletní Circuit časového vývoje pro spuštění na kvantovém hardwaru.

aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
aqc_final_circuit.compose(subsequent_circuit, inplace=True)
aqc_final_circuit.draw("mpl", fold=-1)

Output of the previous code cell

Musíme také sloučit náš aqc_comparison_circuit se zbývajícím evolučním obvodem. Tento Circuit bude použit k porovnání výkonu obvodu optimalizovaného pomocí AQC-Tensor s původním Circuit.

aqc_comparison_circuit.compose(subsequent_circuit, inplace=True)
aqc_comparison_circuit.draw("mpl", fold=-1)

Output of the previous code cell

Krok 2: Optimalizace problému pro spuštění na kvantovém hardwaru

Vyber hardware. Zde použijeme libovolné dostupné zařízení IBM Quantum® s alespoň 127 qubity.

service = QiskitRuntimeService()
backend = service.least_busy(min_num_qubits=127)
print(backend)

Transpilujeme PUBs (Circuit a observables) tak, aby odpovídaly ISA (Instruction Set Architecture) backendu. Nastavením optimization_level=3 transpiler optimalizuje Circuit tak, aby se vešel do jednorozměrného řetězce qubitů, čímž se snižuje šum ovlivňující věrnost Circuitu. Jakmile jsou Circuity transformovány do formátu kompatibilního s backendem, aplikujeme odpovídající transformaci na observables, aby odpovídaly upravenému rozložení qubitů.

pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=3
)
isa_circuit = pass_manager.run(aqc_final_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print("Observable info:", isa_observable)
print("Circuit depth:", isa_circuit.depth())
isa_circuit.draw("mpl", fold=-1, idle_wires=False)
Observable info: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZ'],
coeffs=[1.+0.j])
Circuit depth: 111

Výstup předchozí buňky kódu

Proveď transpilaci pro srovnávací Circuit.

isa_comparison_circuit = pass_manager.run(aqc_comparison_circuit)
isa_comparison_observable = observable.apply_layout(
isa_comparison_circuit.layout
)
print("Observable info:", isa_comparison_observable)
print("Circuit depth:", isa_comparison_circuit.depth())
isa_comparison_circuit.draw("mpl", fold=-1, idle_wires=False)
Observable info: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZ'],
coeffs=[1.+0.j])
Circuit depth: 158

Výstup předchozí buňky kódu

Krok 3: Spuštění pomocí primitiv Qiskit

V tomto kroku spustíme transpilovaný Circuit na kvantovém hardwaru (nebo simulovaném backendu). Pomocí třídy EstimatorV2 z qiskit_ibm_runtime nastavíme Estimator pro spuštění Circuitu a měření zadaného observable. Výsledek úlohy poskytuje očekávaný výsledek pro observable, což nám dává přehled o výkonu Circuitu na cílovém hardwaru.

estimator = Estimator(backend)
job = estimator.run([(isa_circuit, isa_observable)])
print("Job ID:", job.job_id())
job.result()
Job ID: czyhqdxd8drg008hx0yg
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})

Proveď spuštění pro srovnávací Circuit.

job_comparison = estimator.run([(isa_comparison_circuit, isa_observable)])
print("Job Comparison ID:", job.job_id())
job_comparison.result()
Job Comparison ID: czyhqdxd8drg008hx0yg
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})

Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu

V tomto případě není rekonstrukce nutná. Výsledek lze přímo prozkoumat přístupem k očekávané hodnotě z výstupu spuštění.

# AQC results
hw_results = job.result()
hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]
hw_expvals = [
pub_result_data["evs"].tolist() for pub_result_data in hw_results_dicts
]
aqc_expval = hw_expvals[0]

# AQC comparison results
hw_comparison_results = job_comparison.result()
hw_comparison_results_dicts = [
pub_result.data.__dict__ for pub_result in hw_comparison_results
]
hw_comparison_expvals = [
pub_result_data["evs"].tolist()
for pub_result_data in hw_comparison_results_dicts
]
aqc_compare_expval = hw_comparison_expvals[0]

print(f"Exact: \t{reference_expval:.4f}")
print(
f"AQC: \t{aqc_expval:.4f}, |∆| = {np.abs(reference_expval- aqc_expval):.4f}"
)
print(
f"AQC Comparison:\t{aqc_compare_expval:.4f}, |∆| = {np.abs(reference_expval- aqc_compare_expval):.4f}"
)
Exact:         	-0.5252
AQC: -0.4903, |∆| = 0.0349
AQC Comparison: 0.5424, |∆| = 1.0676

Sloupcový graf pro porovnání výsledků AQC, srovnávacích a přesných Circuitů.

plt.style.use("seaborn-v0_8")

labels = ["AQC Result", "AQC Comparison Result"]
values = [abs(aqc_expval), abs(aqc_compare_expval)]

plt.figure(figsize=(10, 6))
bars = plt.bar(labels, values, color=["tab:blue", "tab:purple"])
plt.axhline(
y=abs(reference_expval), color="red", linestyle="--", label="Exact Result"
)
plt.xlabel("Results")
plt.ylabel("Absolute Expected Value")
plt.title("AQC Result vs AQC Comparison Result (Absolute Values)")
plt.legend()
for bar in bars:
y_val = bar.get_height()
plt.text(
bar.get_x() + bar.get_width() / 2.0,
y_val,
round(y_val, 2),
va="bottom",
)
plt.show()

Výstup předchozí buňky kódu

Část II: škálování nahoru

Druhá část tohoto tutoriálu navazuje na předchozí příklad škálováním na větší systém s 50 uzly a ilustruje, jak mapovat složitější problémy kvantové simulace na spustitelné kvantové Circuity. Zde zkoumáme dynamiku XXZ modelu s 50 uzly, což nám umožňuje sestavit a optimalizovat rozsáhlý kvantový Circuit odpovídající reálnějším velikostem systémů.

Hamiltonián pro náš XXZ model s 50 uzly je definován jako:

H^XXZ=i=1L1Ji,(i+1)(XiX(i+1)+YiY(i+1)+2ZiZ(i+1)),\hat{\mathcal{H}}_{XXZ} = \sum_{i=1}^{L-1} J_{i,(i+1)}\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ 2\cdot Z_i Z_{(i+1)} \right) \, ,

kde Ji,(i+1)J_{i,(i+1)} je náhodný koeficient odpovídající hraně (i,i+1)(i, i+1) a L=50L=50 je počet uzlů. Definuj mapu párování a hrany pro Hamiltonián.

L = 50  # L = length of our 1D spin chain

# Generate the edge list for this spin-chain
edge_list = [(i - 1, i) for i in range(1, L)]
# Generate an edge-coloring so we can make hw-efficient circuits
even_edges = edge_list[::2]
odd_edges = edge_list[1::2]

# Instantiate a CouplingMap object
coupling_map = CouplingMap(edge_list)

# Generate random coefficients for our XXZ Hamiltonian
np.random.seed(0)
Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)

hamiltonian = SparsePauliOp(Pauli("I" * L))
for i, edge in enumerate(even_edges + odd_edges):
hamiltonian += SparsePauliOp.from_sparse_list(
[
("XX", (edge), Js[i] / 2),
("YY", (edge), Js[i] / 2),
("ZZ", (edge), Js[i]),
],
num_qubits=L,
)

observable = SparsePauliOp.from_sparse_list(
[("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)

# Generate an initial state
L = hamiltonian.num_qubits
initial_state = QuantumCircuit(L)
for i in range(L):
if i % 2:
initial_state.x(i)

Krok 1: Převod klasických vstupů na kvantový problém

Pro tento větší problém začínáme konstrukcí Hamiltoniánu pro XXZ model s 50 místy, přičemž definujeme interakce spin-spin a externí magnetická pole napříč všemi místy. Poté postupujeme ve třech hlavních krocích:

  1. Vygeneruj optimalizovaný AQC Circuit: Použij Trotterizaci pro přiblížení počáteční evoluce, pak tento segment komprimuj, abys snížil hloubku Circuit.
  2. Vytvoř zbývající Circuit časové evoluce: Zachyť zbývající časovou evoluci přesahující počáteční segment.
  3. Spoj Circuity: Slouč optimalizovaný AQC Circuit se zbývajícím evolučním Circuitem, čímž vytvoříš úplný Circuit časové evoluce připravený ke spuštění.

Vygeneruj cílový AQC Circuit (počáteční segment).

aqc_evolution_time = 0.2
aqc_target_num_trotter_steps = 32

aqc_target_circuit = initial_state.copy()
aqc_target_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
time=aqc_evolution_time,
),
inplace=True,
)

Vygeneruj následující Circuit (zbývající segment).

subsequent_num_trotter_steps = 3
subsequent_evolution_time = 0.2

subsequent_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
time=subsequent_evolution_time,
)

Vygeneruj srovnávací AQC Circuit (počáteční segment, ale se stejným počtem Trotterových kroků jako následující Circuit).

# Generate the AQC comparison circuit
aqc_comparison_num_trotter_steps = int(
subsequent_num_trotter_steps
/ subsequent_evolution_time
* aqc_evolution_time
)
print(
"Number of Trotter steps for comparison:",
aqc_comparison_num_trotter_steps,
)

aqc_comparison_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_comparison_num_trotter_steps),
time=aqc_evolution_time,
)
Number of Trotter steps for comparison: 3

Vygeneruj referenční Circuit.

evolution_time = 0.4
reps = 200

reference_circuit = initial_state.copy()
reference_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=reps),
time=evolution_time,
),
inplace=True,
)

Vygeneruj ansatz a počáteční parametry z Trotterova Circuit s menším počtem kroků.

aqc_ansatz_num_trotter_steps = 1

aqc_good_circuit = initial_state.copy()
aqc_good_circuit.compose(
generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
time=aqc_evolution_time,
),
inplace=True,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
aqc_good_circuit
)
print(f"AQC Comparison circuit: depth {aqc_comparison_circuit.depth()}")
print(f"Target circuit: depth {aqc_target_circuit.depth()}")
print(
f"Ansatz circuit: depth {aqc_ansatz.depth()}, with {len(aqc_initial_parameters)} parameters"
)
AQC Comparison circuit: depth 36
Target circuit: depth 385
Ansatz circuit: depth 7, with 816 parameters

Nastav parametry pro simulaci tensorových sítí a poté sestav reprezentaci cílového stavu pomocí matrix product state pro optimalizaci. Následně vyhodnoť věrnost (fidelitu) mezi počátečním Circuit a cílovým stavem, aby ses přesvědčil o rozdílu v Trotterově chybě.

simulator_settings = QuimbSimulator(
quimb.tensor.CircuitMPS, autodiff_backend="jax"
)

# Build the matrix-product representation of the state to be approximated by AQC
aqc_target_mps = tensornetwork_from_circuit(
aqc_target_circuit, simulator_settings
)
print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())

# Obtains the reference MPS, where we can obtain the exact expectation value by examining the `local_expectation``
reference_mps = tensornetwork_from_circuit(
reference_circuit, simulator_settings
)
reference_expval = reference_mps.local_expectation(
quimb.pauli("Z") & quimb.pauli("Z"), (L // 2 - 1, L // 2)
).real.item()

# Compute the starting fidelity
good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)
starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2
print("Starting fidelity:", starting_fidelity)
Target MPS maximum bond dimension: 5
Starting fidelity: 0.9926466919924161

Abychom optimalizovali parametry ansatzu, minimalizujeme nákladovou funkci MaximizeStateFidelity pomocí optimalizátoru L-BFGS ze SciPy, přičemž podmínka zastavení je nastavena tak, aby překonala věrnost počátečního Circuit bez AQC-Tensor. Tím zajistíme, že komprimovaný Circuit má jak nižší Trotterovu chybu, tak i menší hloubku.

# Setting values for the optimization
aqc_stopping_fidelity = 1
aqc_max_iterations = 500

stopping_point = 1.0 - aqc_stopping_fidelity
objective = MaximizeStateFidelity(
aqc_target_mps, aqc_ansatz, simulator_settings
)

def callback(intermediate_result: OptimizeResult):
fidelity = 1 - intermediate_result.fun
print(
f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}"
)
if intermediate_result.fun < stopping_point:
# Good enough for now
raise StopIteration

result = minimize(
objective,
aqc_initial_parameters,
method="L-BFGS-B",
jac=True,
options={"maxiter": aqc_max_iterations},
callback=callback,
)
if (
result.status
not in (
0,
1,
99,
)
): # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration
raise RuntimeError(
f"Optimization failed: {result.message} (status={result.status})"
)

print(f"Done after {result.nit} iterations.")
aqc_final_parameters = result.x
2025-04-14 11:48:28.705807 Intermediate result: Fidelity 0.99795851
2025-04-14 11:48:28.743265 Intermediate result: Fidelity 0.99822826
2025-04-14 11:48:28.776629 Intermediate result: Fidelity 0.99829675
2025-04-14 11:48:28.816153 Intermediate result: Fidelity 0.99832474
2025-04-14 11:48:28.856437 Intermediate result: Fidelity 0.99836131
2025-04-14 11:48:28.896432 Intermediate result: Fidelity 0.99839954
2025-04-14 11:48:28.936670 Intermediate result: Fidelity 0.99846517
2025-04-14 11:48:28.982069 Intermediate result: Fidelity 0.99865029
2025-04-14 11:48:29.026130 Intermediate result: Fidelity 0.99872332
2025-04-14 11:48:29.067426 Intermediate result: Fidelity 0.99892359
2025-04-14 11:48:29.110742 Intermediate result: Fidelity 0.99900640
2025-04-14 11:48:29.161362 Intermediate result: Fidelity 0.99907169
2025-04-14 11:48:29.207933 Intermediate result: Fidelity 0.99911423
2025-04-14 11:48:29.266772 Intermediate result: Fidelity 0.99918716
2025-04-14 11:48:29.331727 Intermediate result: Fidelity 0.99921278
2025-04-14 11:48:29.401694 Intermediate result: Fidelity 0.99924853
2025-04-14 11:48:29.467980 Intermediate result: Fidelity 0.99928797
2025-04-14 11:48:29.533281 Intermediate result: Fidelity 0.99933028
2025-04-14 11:48:29.600833 Intermediate result: Fidelity 0.99935757
2025-04-14 11:48:29.670816 Intermediate result: Fidelity 0.99938140
2025-04-14 11:48:29.736928 Intermediate result: Fidelity 0.99940964
2025-04-14 11:48:29.802931 Intermediate result: Fidelity 0.99944051
2025-04-14 11:48:29.869177 Intermediate result: Fidelity 0.99946828
2025-04-14 11:48:29.940156 Intermediate result: Fidelity 0.99948723
2025-04-14 11:48:30.005751 Intermediate result: Fidelity 0.99951011
2025-04-14 11:48:30.070853 Intermediate result: Fidelity 0.99954718
2025-04-14 11:48:30.139171 Intermediate result: Fidelity 0.99956267
2025-04-14 11:48:30.210506 Intermediate result: Fidelity 0.99958949
2025-04-14 11:48:30.279647 Intermediate result: Fidelity 0.99960498
2025-04-14 11:48:30.348016 Intermediate result: Fidelity 0.99961308
2025-04-14 11:48:30.414311 Intermediate result: Fidelity 0.99962894
2025-04-14 11:48:30.488910 Intermediate result: Fidelity 0.99964121
2025-04-14 11:48:30.561298 Intermediate result: Fidelity 0.99964348
2025-04-14 11:48:30.632214 Intermediate result: Fidelity 0.99964860
2025-04-14 11:48:30.705703 Intermediate result: Fidelity 0.99965695
2025-04-14 11:48:30.775679 Intermediate result: Fidelity 0.99966398
2025-04-14 11:48:30.842629 Intermediate result: Fidelity 0.99967816
2025-04-14 11:48:30.912357 Intermediate result: Fidelity 0.99968293
2025-04-14 11:48:30.979420 Intermediate result: Fidelity 0.99968936
2025-04-14 11:48:31.049196 Intermediate result: Fidelity 0.99969223
2025-04-14 11:48:31.125391 Intermediate result: Fidelity 0.99970009
2025-04-14 11:48:31.201256 Intermediate result: Fidelity 0.99970724
2025-04-14 11:48:31.272424 Intermediate result: Fidelity 0.99970987
2025-04-14 11:48:31.338907 Intermediate result: Fidelity 0.99971237
2025-04-14 11:48:31.404800 Intermediate result: Fidelity 0.99971916
2025-04-14 11:48:31.475226 Intermediate result: Fidelity 0.99971940
2025-04-14 11:48:31.547746 Intermediate result: Fidelity 0.99972465
2025-04-14 11:48:31.622827 Intermediate result: Fidelity 0.99972763
2025-04-14 11:48:31.819516 Intermediate result: Fidelity 0.99972894
2025-04-14 11:48:33.444538 Intermediate result: Fidelity 0.99972894
Done after 50 iterations.
parameters = [float(param) for param in aqc_final_parameters]

Sestav výsledný Circuit pro transpilaci spojením optimalizovaného ansatzu se zbývajícím Circuitem časové evoluce.

aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
aqc_final_circuit.compose(subsequent_circuit, inplace=True)
aqc_comparison_circuit.compose(subsequent_circuit, inplace=True)

Krok 2: Optimalizace problému pro spuštění na kvantovém hardwaru

Vyber backend.

service = QiskitRuntimeService()
backend = service.least_busy(min_num_qubits=127)
print(backend)

Transpiluj dokončený Circuit na cílovém hardwaru, čímž ho připravíš ke spuštění. Výsledný ISA Circuit pak lze odeslat ke spuštění na backendu.

pass_manager = generate_preset_pass_manager(
backend=backend, optimization_level=3
)
isa_circuit = pass_manager.run(aqc_final_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print("Observable info:", isa_observable)
print("Circuit depth:", isa_circuit.depth())
isa_circuit.draw("mpl", fold=-1, idle_wires=False)
Observable info: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])
Circuit depth: 122

Výstup předchozí buňky kódu

isa_comparison_circuit = pass_manager.run(aqc_comparison_circuit)
isa_comparison_observable = observable.apply_layout(
isa_comparison_circuit.layout
)
print("Observable info:", isa_comparison_observable)
print("Circuit depth:", isa_comparison_circuit.depth())
isa_comparison_circuit.draw("mpl", fold=-1, idle_wires=False)
Observable info: SparsePauliOp(['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIZZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])
Circuit depth: 158

Výstup předchozí buňky kódu

Krok 3: Spuštění pomocí primitiv Qiskit

V tomto kroku spustíme transpilovaný Circuit na kvantovém hardwaru (nebo simulovaném backendu) pomocí EstimatorV2 z qiskit_ibm_runtime a změříme zadaný observábl. Výsledek úlohy poskytne cenné informace o výkonu Circuitu na cílovém hardwaru.

Pro tento rozsáhlejší příklad prozkoumáme, jak využít EstimatorOptions ke správě a řízení parametrů našeho hardwarového experimentu. Tato nastavení jsou volitelná, ale jsou užitečná pro sledování parametrů experimentu a upřesnění možností spuštění pro dosažení optimálních výsledků.

Úplný seznam dostupných možností spuštění najdeš v dokumentaci qiskit-ibm-runtime.

twirling_options = {
"enable_gates": True,
"enable_measure": True,
"num_randomizations": 300,
"shots_per_randomization": 100,
"strategy": "active",
}

zne_options = {
"amplifier": "gate_folding",
"noise_factors": [1, 2, 3],
"extrapolated_noise_factors": list(np.linspace(0, 3, 31)),
"extrapolator": ["exponential", "linear", "fallback"],
}

meas_learning_options = {
"num_randomizations": 512,
"shots_per_randomization": 512,
}

resilience_options = {
"measure_mitigation": True,
"zne_mitigation": True,
"zne": zne_options,
"measure_noise_learning": meas_learning_options,
}

estimator_options = {
"resilience": resilience_options,
"twirling": twirling_options,
}

estimator = Estimator(backend, options=estimator_options)
job = estimator.run([(isa_circuit, isa_observable)])
print("Job ID:", job.job_id())
job.result()
Job ID: czyjx6crxz8g008f63r0
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), evs_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), stds_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), ensemble_stds_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), evs_extrapolated=np.ndarray(<shape=(3, 31), dtype=float64>), stds_extrapolated=np.ndarray(<shape=(3, 31), dtype=float64>)), metadata={'shots': 30000, 'target_precision': 0.005773502691896258, 'circuit_metadata': {}, 'resilience': {'zne': {'extrapolator': 'exponential'}}, 'num_randomizations': 300})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': True, 'enable_measure': True, 'num_randomizations': 300, 'shots_per_randomization': 100, 'interleave_randomizations': True, 'strategy': 'active'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': True, 'pec_mitigation': False, 'zne': {'noise_factors': [1, 2, 3], 'extrapolator': ['exponential', 'linear', 'fallback'], 'extrapolated_noise_factors': [0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1, 1.1, 1.2000000000000002, 1.3, 1.4000000000000001, 1.5, 1.6, 1.7000000000000002, 1.8, 1.9000000000000001, 2, 2.1, 2.2, 2.3000000000000003, 2.4000000000000004, 2.5, 2.6, 2.7, 2.8000000000000003, 2.9000000000000004, 3]}}, 'version': 2})
job_comparison = estimator.run([(isa_comparison_circuit, isa_observable)])
print("Job Comparison ID:", job.job_id())
job_comparison.result()
Job Comparison ID: czyjx6crxz8g008f63r0
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), evs_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), stds_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), ensemble_stds_noise_factors=np.ndarray(<shape=(3,), dtype=float64>), evs_extrapolated=np.ndarray(<shape=(3, 31), dtype=float64>), stds_extrapolated=np.ndarray(<shape=(3, 31), dtype=float64>)), metadata={'shots': 30000, 'target_precision': 0.005773502691896258, 'circuit_metadata': {}, 'resilience': {'zne': {'extrapolator': 'exponential'}}, 'num_randomizations': 300})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': True, 'enable_measure': True, 'num_randomizations': 300, 'shots_per_randomization': 100, 'interleave_randomizations': True, 'strategy': 'active'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': True, 'pec_mitigation': False, 'zne': {'noise_factors': [1, 2, 3], 'extrapolator': ['exponential', 'linear', 'fallback'], 'extrapolated_noise_factors': [0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1, 1.1, 1.2000000000000002, 1.3, 1.4000000000000001, 1.5, 1.6, 1.7000000000000002, 1.8, 1.9000000000000001, 2, 2.1, 2.2, 2.3000000000000003, 2.4000000000000004, 2.5, 2.6, 2.7, 2.8000000000000003, 2.9000000000000004, 3]}}, 'version': 2})

Krok 4: Následné zpracování a vrácení výsledku v požadovaném klasickém formátu

Zde není potřeba žádná rekonstrukce jako dříve; střední hodnotu lze přímo číst z výstupu spuštění a prozkoumat výsledek.

# AQC results
hw_results = job.result()
hw_results_dicts = [pub_result.data.__dict__ for pub_result in hw_results]
hw_expvals = [
pub_result_data["evs"].tolist() for pub_result_data in hw_results_dicts
]
aqc_expval = hw_expvals[0]

# AQC comparison results
hw_comparison_results = job_comparison.result()
hw_comparison_results_dicts = [
pub_result.data.__dict__ for pub_result in hw_comparison_results
]
hw_comparison_expvals = [
pub_result_data["evs"].tolist()
for pub_result_data in hw_comparison_results_dicts
]
aqc_compare_expval = hw_comparison_expvals[0]

print(f"Exact: \t{reference_expval:.4f}")
print(
f"AQC: \t{aqc_expval:.4f}, |∆| = {np.abs(reference_expval- aqc_expval):.4f}"
)
print(
f"AQC Comparison:\t{aqc_compare_expval:.4f}, |∆| = {np.abs(reference_expval- aqc_compare_expval):.4f}"
)
Exact:         	-0.5888
AQC: -0.4809, |∆| = 0.1078
AQC Comparison: 1.1764, |∆| = 1.7652

Vykresli výsledky AQC, srovnávacího a přesného Circuitu pro XXZ model s 50 uzly.

labels = ["AQC Result", "AQC Comparison Result"]
values = [abs(aqc_expval), abs(aqc_compare_expval)]

plt.figure(figsize=(10, 6))
bars = plt.bar(labels, values, color=["tab:blue", "tab:purple"])
plt.axhline(
y=abs(reference_expval), color="red", linestyle="--", label="Exact Result"
)
plt.xlabel("Results")
plt.ylabel("Absolute Expected Value")
plt.title("AQC Result vs AQC Comparison Result (Absolute Values)")
plt.legend()
for bar in bars:
y_val = bar.get_height()
plt.text(
bar.get_x() + bar.get_width() / 2.0,
y_val,
round(y_val, 2),
va="bottom",
)

plt.show()

Výstup předchozí buňky kódu

Závěr

Tento tutoriál ukázal, jak používat přibližnou kvantovou kompilaci s tenzorovanými sítěmi (AQC-Tensor) ke kompresi a optimalizaci Circuitů pro simulaci kvantové dynamiky ve velkém měřítku. Na malých i velkých Heisenbergových modelech jsme aplikovali AQC-Tensor ke snížení hloubky Circuit potřebné pro Trotterizovanou časovou evoluci. Vygenerováním parametrizovaného ansatzu ze zjednodušeného Trotter Circuitu a jeho optimalizací pomocí technik maticových produktových stavů (MPS) jsme dosáhli nízkohloubkové aproximace cílové evoluce, která je zároveň přesná i efektivní.

Zde popsaný postup zdůrazňuje klíčové výhody AQC-Tensor pro škálování kvantových simulací:

  • Výrazná komprese Circuit: AQC-Tensor snížil hloubku Circuit potřebnou pro komplexní časovou evoluci, čímž zvýšil její proveditelnost na současných zařízeních.
  • Efektivní optimalizace: Přístup MPS poskytl robustní rámec pro optimalizaci parametrů vyvažující věrnost s výpočetní efektivitou.
  • Připravenost pro hardware: Transpilace výsledného optimalizovaného Circuitu zajistila splnění omezení cílového kvantového hardwaru.

S tím, jak se objevují větší kvantová zařízení a pokročilejší algoritmy, budou techniky jako AQC-Tensor nezbytné pro spouštění komplexních kvantových simulací na near-term hardwaru, což demonstruje slibný pokrok ve zvládání hloubky a věrnosti pro škálovatelné kvantové aplikace.

Průzkum o tutoriálu

Vyplň prosím tento krátký průzkum a poskytni zpětnou vazbu k tomuto tutoriálu. Tvoje poznatky nám pomohou zlepšit naši nabídku obsahu a uživatelský zážitek.

Odkaz na průzkum

Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.