Reducerea adâncimii Circuit-ului cu addon-ul AQC-Tensor pentru Qiskit
În acest notebook, vom parcurge pașii unui pattern Qiskit folosind compilarea cuantică aproximativă cu rețele tensoriale (AQC-Tensor) pentru a obține o adâncime a Circuit-ului mai mică decât ar fi necesară în mod obișnuit pentru a efectua evoluția Trotter.
Aceștia sunt pașii pe care îi vom urma:
- Pasul 1: Maparea la problema cuantică
- Inițializarea Hamiltonianului problemei și a observabilului (observabilelor)
- Generarea unei stări țintă tip rețea tensorială pentru porțiunea inițială a Circuit-ului
- Generarea unui Circuit cu adâncime redusă care aproximează porțiunea ce urmează a fi comprimată
- Generarea unui ansatz general din acel Circuit
- Optimizarea parametrilor pentru a aduce ansatz-ul cât mai aproape de țintă
- Adăugarea pașilor Trotter următori la ansatz-ul optimizat
- Pasul 2: Optimizarea pentru hardware-ul țintă
- Transpilarea Circuit-ului pentru hardware
- Pasul 3: Executarea experimentelor
- Folosirea unui Backend fals pentru simplitate
- Pasul 4: Reconstruirea rezultatelor
- N/A; în schimb, afișăm pur și simplu observabilul măsurat
Pasul 1: Maparea la Circuit-ul cuantic și operator
Configurarea unui Hamiltonian model și a unui observabil
În acest notebook, folosim modelul Ising pe un cerc de 10 site-uri:
unde condițiile periodice la frontieră implică faptul că pentru obținem , este intensitatea cuplajului dintre două site-uri, iar este câmpul magnetic extern.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-addon-aqc-tensor qiskit-addon-utils qiskit-ibm-runtime quimb scipy
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)
# Choose a 10-qubit circle on this coupling map
reduced_coupling_map = coupling_map.reduce([0, 13, 1, 14, 10, 16, 4, 15, 3, 9])
# Get a qubit operator describing the Ising field model
hamiltonian = generate_xyz_hamiltonian(
reduced_coupling_map,
coupling_constants=(0.0, 0.0, 1.0),
ext_magnetic_field=(0.4, 0.0, 0.0),
)
Observabilul pe care îl vom măsura este magnetizarea totală.
from qiskit.quantum_info import SparsePauliOp
L = reduced_coupling_map.size()
observable = SparsePauliOp.from_sparse_list([("Z", [i], 1 / L / 2) for i in range(L)], num_qubits=L)
Determinarea cât din evoluția temporală urmează să fie simulată clasic
Scopul nostru general este de a simula evoluția temporală a Hamiltonianului model de mai sus. Facem acest lucru prin evoluție Trotter, pe care o împărțim în două porțiuni:
- O porțiune inițială care poate fi simulată cu stări produs matriceal (MPS). Vom „compila" această porțiune folosind AQC, conform prezentării din https://arxiv.org/abs/2301.08609.
- O porțiune ulterioară a Circuit-ului, care va fi executată pe hardware. Planificăm să folosim AQC-Tensor pentru a comprima Circuit-ul nostru de evoluție temporală până la momentul , apoi să evoluăm folosind pași Trotter obișnuiți până la .
Generarea Circuit-urilor înainte și după împărțire
Acum că am ales să facem împărțirea la , vom genera două Circuit-uri:
- Un Circuit „țintă" pentru porțiunea AQC a evoluției, de la până la . Deoarece aceasta este simulată de un simulator bazat pe rețele tensoriale, numărul de straturi afectează timpul de execuție doar cu un factor constant, deci putem folosi un număr generos de straturi pentru a minimiza eroarea Trotter.
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
aqc_evolution_time = 4.0
aqc_target_num_trotter_steps = 45
aqc_target_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
time=aqc_evolution_time,
)
- Un Circuit de evoluție ulterioară, care evoluează de la până la . Deoarece acesta va fi rulat pe hardware cuantic, este de dorit să folosim cât mai puține straturi Trotter.
subsequent_evolution_time = 1.0
subsequent_num_trotter_steps = 5
subsequent_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
time=subsequent_evolution_time,
)
Pentru o comparație ulterioară, să generăm și un al treilea Circuit: unul care evoluează pentru aqc_evolution_time, dar care are același timp de evoluție per pas Trotter ca Circuit-ul ulterior. Acesta este Circuit-ul cu care am fi lucrat dacă nu am fi folosit un număr generos de pași Trotter pentru Circuit-ul țintă. Îl vom numi Circuit-ul de comparație.
aqc_comparison_num_trotter_steps = int(
subsequent_num_trotter_steps / subsequent_evolution_time * aqc_evolution_time
)
aqc_comparison_num_trotter_steps
20
comparison_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_comparison_num_trotter_steps),
time=aqc_evolution_time,
)
Generarea unui ansatz și a parametrilor inițiali dintr-un Circuit Trotter cu mai puțini pași
Mai întâi, construim un Circuit „bun" care are același timp de evoluție ca Circuit-ul țintă, dar cu mai puțini pași Trotter (și, astfel, mai puține straturi).
Apoi, transmitem acest Circuit „bun" funcției generate_ansatz_from_circuit din AQC-Tensor. Această funcție analizează conectivitatea cu doi Qubiți a Circuit-ului și returnează două lucruri:
- un Circuit ansatz general, parametrizat, cu aceeași conectivitate cu doi Qubiți ca Circuit-ul de intrare; și
- parametri care, introduși în ansatz, reproduc Circuit-ul de intrare (bun).
În curând, vom lua acești parametri și îi vom ajusta iterativ pentru a aduce Circuit-ul ansatz cât mai aproape de MPS-ul țintă.
from qiskit_addon_aqc_tensor import generate_ansatz_from_circuit
aqc_ansatz_num_trotter_steps = 5
aqc_good_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
time=aqc_evolution_time,
)
aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
aqc_good_circuit, qubits_initially_zero=True
)
aqc_ansatz.draw("mpl", fold=-1)

print(f"Comparison circuit: depth {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")
Comparison circuit: depth 120
Target circuit: depth 270
Ansatz circuit: depth 23, with 515 parameters