Pagbawas ng circuit depth gamit ang AQC-Tensor Qiskit addon
Sa notebook na ito, dadaan tayo sa mga hakbang ng isang Qiskit pattern habang ginagamit ang approximate quantum compilation gamit ang tensor networks (AQC-Tensor) upang makamit ang mas mababang circuit depth kaysa sa karaniwang kakailanganin para magsagawa ng Trotter evolution.
Ito ang mga hakbang na gagawin natin:
- Hakbang 1: I-map sa quantum problem
- I-initialize ang Hamiltonian at observable(s) ng ating problema
- Bumuo ng target tensor-network state para sa inisyal na bahagi ng circuit
- Bumuo ng low-depth circuit na nag-aapproximate sa bahaging kinukompres
- Bumuo ng general ansatz mula sa circuit na iyon
- I-optimize ang mga parameter upang dalhin ang ansatz nang kasinglapit hangga't maaari sa target
- Magdagdag ng mga sumusunod na Trotter step sa optimized na ansatz
- Hakbang 2: I-optimize para sa target hardware
- I-transpile ang circuit para sa hardware
- Hakbang 3: Isagawa ang mga eksperimento
- Gumamit ng fake backend para sa pagiging simple
- Hakbang 4: I-reconstruct ang mga resulta
- N/A; sa halip, ino-output lang natin ang sinukat na observable
Hakbang 1: Map sa quantum circuit at operatorβ
I-set up ang isang model Hamiltonian at observableβ
Sa notebook na ito, ginagamit natin ang Ising model sa isang bilog na may 10 site:
kung saan ang mga periodic boundary conditions ay nagpapahiwatig na para sa ay makakakuha tayo ng , ang coupling strength sa pagitan ng dalawang site at ang panlabas na magnetic field.
# 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),
)
Ang observable na susukatin natin ay ang kabuuang magnetization.
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)
Tukuyin kung gaano karaming time evolution ang i-simulate nang classicalβ
Ang ating pangkalahatang layunin ay i-simulate ang time evolution ng nasa itaas na model Hamiltonian. Ginagawa natin ito sa pamamagitan ng Trotter evolution, na hinahati natin sa dalawang bahagi:
- Isang inisyal na bahagi na maaaring i-simulate gamit ang matrix product states (MPS). "I-compile" natin ang bahaging ito gamit ang AQC tulad ng ipinakita sa https://arxiv.org/abs/2301.08609.
- Isang sumusunod na bahagi ng circuit na isasagawa sa hardware. Magplano tayong gumamit ng AQC-Tensor upang i-compress ang ating time evolution circuit hanggang , pagkatapos ay mag-evolve gamit ang ordinaryong mga Trotter step hanggang .
Bumuo ng mga circuit bago at pagkatapos ng splitβ
Ngayong pinili na natin na maghati sa , bubuo tayo ng dalawang circuit:
- Isang "target" circuit para sa AQC na bahagi ng evolution, mula hanggang . Dahil ito ay sini-simulate ng tensor-network simulator, ang bilang ng mga layer ay nakakaapekto lamang sa execution time sa pamamagitan ng constant factor, kaya maaari nating gamitin ang isang bukas-palad na bilang ng mga layer upang mabawasan ang Trotter error.
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,
)
- Isang sumusunod na evolution circuit, na nag-evolve mula hanggang . Dahil ito ay tinatakbo sa quantum hardware, kanais-nais na gumamit ng kakaunting Trotter layer hangga't maaari.
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,
)
Para sa kapakanan ng paghahambing mamaya, bumuo rin tayo ng pangatlong circuit: isa na nag-e-evolve para sa aqc_evolution_time ngunit may parehong evolution time bawat Trotter step gaya ng subsequent circuit. Ito ang circuit na pagtatrabahuhan natin kung hindi tayo gumamit ng bukas-palad na bilang ng mga Trotter step para sa target circuit. Tatawagin natin itong comparison circuit.
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,
)
Bumuo ng ansatz at mga inisyal na parameter mula sa Trotter circuit na may mas kaunting stepsβ
Una, gumagawa tayo ng "magandang" circuit na may parehong evolution time bilang ang target circuit, ngunit may mas kaunting Trotter steps (at sa gayon ay mas kaunting layer).
Pagkatapos ay ipapasa natin ang "magandang" circuit na ito sa generate_ansatz_from_circuit function ng AQC-Tensor. Ang function na ito ay sinusuri ang two-qubit connectivity ng circuit at nagbabalik ng dalawang bagay:
- isang general, parametrized ansatz circuit na may parehong two-qubit connectivity gaya ng input circuit; at,
- mga parameter na, kapag ipinasok sa ansatz, ay nag-yi-yield ng input (magandang) circuit.
Sa lalong madaling panahon, kukunin natin ang mga parameter na ito at iteratibong i-aadjust ang mga ito upang dalhin ang ansatz circuit nang kasinglapit hangga't maaari sa target MPS.
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
Pumili ng settings para sa tensor network simulationβ
Dito, gumagamit tayo ng tensor network simulator na nakabatay sa quimb. Sa halimbawang ito, ginagamit natin ang matrix-product state (MPS) simulator ng quimb, at ginagamit natin ang JAX para sa automatic differentiation. Tingnan ang API documentation para sa karagdagang impormasyon kung paano gamitin ang quimb simulator.
from functools import partial
import quimb.tensor
from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator
simulator_settings = QuimbSimulator(
partial(quimb.tensor.CircuitMPS, max_bond=100, cutoff=1e-8),
autodiff_backend="jax",
)
Bumuo ng matrix-product state representation ng AQC target stateβ
Susunod, bumuo tayo ng matrix-product representation ng state na ia-approximate ng AQC.
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)
Tandaan na dahil pumili tayo ng bukas-palad na bilang ng mga Trotter step para sa target state, ito ay talagang may mas mababang Trotter error kaysa sa comparison circuit. Maaari nating kalkulahin ang fidelity () ng state na inihanda ng comparison circuit kumpara sa target state:
from qiskit_addon_aqc_tensor.simulation import compute_overlap
comparison_mps = tensornetwork_from_circuit(comparison_circuit, simulator_settings)
comparison_fidelity = abs(compute_overlap(comparison_mps, aqc_target_mps)) ** 2
comparison_fidelity
0.9996761790297157
I-optimize ang mga parameter ng ansatz gamit ang MPS calculationsβ
Dito, mini-minimize natin ang pinakasimpleng posibleng cost function, MaximizeStateFidelity, sa pamamagitan ng paggamit ng L-BFGS optimizer mula sa scipy.
Pumipili tayo ng stopping point para sa fidelity na mas mataas kaysa sa kung ano ang naging halaga ng comparison circuit, nang hindi gumagamit ng AQC. Kapag naabot ito, ang compressed na circuit ay may mas mababang Trotter error at mas mababang depth kaysa sa orihinal na circuit. Sa karagdagang processing time, maaaring magsagawa ng karagdagang mga optimization step upang dalhin ang fidelity nang mas mataas pa.
from scipy.optimize import OptimizeResult, minimize
from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity
objective = MaximizeStateFidelity(aqc_target_mps, aqc_ansatz, simulator_settings)
stopping_point = 1 - comparison_fidelity
def callback(intermediate_result: OptimizeResult):
print(f"Intermediate result: Fidelity {1 - intermediate_result.fun:.8}")
if intermediate_result.fun < stopping_point:
# Good enough for now
raise StopIteration
result = minimize(
objective.loss_function,
aqc_initial_parameters,
method="L-BFGS-B",
jac=True,
options={"maxiter": 100},
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
Intermediate result: Fidelity 0.95080335
Intermediate result: Fidelity 0.98408927
Intermediate result: Fidelity 0.99140876
Intermediate result: Fidelity 0.9951876
Intermediate result: Fidelity 0.99563147
Intermediate result: Fidelity 0.99646297
Intermediate result: Fidelity 0.99679298
Intermediate result: Fidelity 0.99715793
Intermediate result: Fidelity 0.99756604
Intermediate result: Fidelity 0.99804283
Intermediate result: Fidelity 0.99832283
Intermediate result: Fidelity 0.99856583
Intermediate result: Fidelity 0.99868698
Intermediate result: Fidelity 0.998867
Intermediate result: Fidelity 0.99902237
Intermediate result: Fidelity 0.99912174
Intermediate result: Fidelity 0.99919705
Intermediate result: Fidelity 0.99926724
Intermediate result: Fidelity 0.99938605
Intermediate result: Fidelity 0.99951297
Intermediate result: Fidelity 0.99956172
Intermediate result: Fidelity 0.99962274
Intermediate result: Fidelity 0.99963919
Intermediate result: Fidelity 0.99967423
Intermediate result: Fidelity 0.9997101
Done after 25 iterations.
Buuin ang final na circuit na ipapasa sa transpilerβ
final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
final_circuit.compose(subsequent_circuit, inplace=True)
final_circuit.draw("mpl", fold=-1)

Hakbang 2: I-transpile para sa execution sa target hardwareβ
Sa Hakbang 2 ng isang Qiskit pattern, ti-transpile natin ang circuit na ito at anumang nais na observable(s) para sa execution sa isang target device. Dito gumagamit tayo ng fake backend na ibinigay ng qiskit-ibm-runtime.
from qiskit import transpile
from qiskit_ibm_runtime.fake_provider import FakeMelbourneV2
backend = FakeMelbourneV2()
isa_circuit = transpile(final_circuit, backend)
isa_observable = observable.apply_layout(isa_circuit.layout)
Ang resultang ISA circuit ay maaaring ipadala para sa execution sa backend (hakbang 3 ng isang Qiskit pattern).
Hakbang 3: Isagawa sa quantum hardwareβ
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(backend)
job = estimator.run([(isa_circuit, isa_observable)])
pub_result = job.result()[0]
Hakbang 4: Reconstructβ
Hindi kinakailangan ang reconstruction sa kaso natin. Maaari nating tingnan na lang ang resulta.
pub_result.data.evs[()]
np.float64(0.047998046875000006)