Mengurangkan kedalaman Circuit dengan tambahan AQC-Tensor Qiskit
Dalam notebook ini, kita akan melalui langkah-langkah sebuah corak Qiskit sambil menggunakan pengkompilan kuantum hampiran dengan rangkaian tensor (AQC-Tensor) untuk mencapai kedalaman Circuit yang lebih rendah berbanding yang biasanya diperlukan untuk melaksanakan evolusi Trotter.
Ini adalah langkah-langkah yang akan kita ambil:
- Langkah 1: Peta ke masalah kuantum
- Mulakan Hamiltonian masalah kita dan observable(s)
- Jana keadaan rangkaian tensor sasaran untuk bahagian awal Circuit
- Jana Circuit berkedalaman rendah yang menghampiri bahagian yang dimampatkan
- Jana ansatz umum daripada Circuit tersebut
- Optimumkan parameter untuk membawa ansatz sedekat mungkin ke sasaran
- Tambah langkah Trotter seterusnya ke ansatz yang telah dioptimumkan
- Langkah 2: Optimumkan untuk perkakasan sasaran
- Transpile Circuit untuk perkakasan
- Langkah 3: Jalankan eksperimen
- Gunakan backend palsu untuk memudahkan
- Langkah 4: Bina semula keputusan
- T/B; sebaliknya, kita hanya keluarkan observable yang diukur
Langkah 1: Peta ke Circuit kuantum dan operatorβ
Sediakan Hamiltonian model dan observableβ
Dalam notebook ini, kita menggunakan model Ising pada bulatan 10 tapak:
di mana syarat sempadan berkala bermakna untuk kita memperoleh , adalah kekuatan gandingan antara dua tapak dan adalah medan magnet luaran.
# 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),
)
Observable yang akan kita ukur adalah jumlah kemagnetan.
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)
Tentukan berapa banyak evolusi masa yang hendak disimulasi secara klasikβ
Matlamat keseluruhan kita adalah untuk mensimulasi evolusi masa model Hamiltonian di atas. Kita lakukan ini melalui evolusi Trotter, yang kita bahagikan kepada dua bahagian:
- Bahagian awal yang boleh disimulasi dengan keadaan produk matriks (MPS). Kita akan "mengkompil" bahagian ini menggunakan AQC seperti yang dibentangkan dalam https://arxiv.org/abs/2301.08609.
- Bahagian seterusnya dari Circuit yang akan dijalankan pada perkakasan. Mari kita rancang untuk menggunakan AQC-Tensor bagi memampatkan Circuit evolusi masa kita sehingga masa , kemudian berevolusi menggunakan langkah Trotter biasa sehingga .
Jana Circuit sebelum dan selepas pemisahanβ
Kini setelah kita memilih untuk membahagi pada , kita akan menjana dua Circuit:
- Circuit "sasaran" untuk bahagian AQC evolusi, dari ke . Oleh kerana ini disimulasi oleh simulator rangkaian tensor, bilangan lapisan hanya mempengaruhi masa pelaksanaan dengan faktor malar, jadi kita lebih baik menggunakan bilangan lapisan yang banyak untuk meminimumkan ralat 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,
)
- Circuit evolusi seterusnya, yang berevolusi dari ke . Oleh kerana ini dijalankan pada perkakasan kuantum, adalah wajar untuk menggunakan seberapa sedikit lapisan Trotter yang mungkin.
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,
)
Untuk tujuan perbandingan kemudian, mari kita juga jana Circuit ketiga: satu yang berevolusi untuk aqc_evolution_time tetapi mempunyai masa evolusi yang sama setiap langkah Trotter seperti Circuit seterusnya. Ini adalah Circuit yang kita akan gunakan sekiranya kita tidak menggunakan bilangan langkah Trotter yang banyak untuk Circuit sasaran. Kita akan menyebutnya sebagai Circuit perbandingan.
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,
)
Jana ansatz dan parameter awal daripada Circuit Trotter dengan langkah lebih sedikitβ
Pertama, kita bina Circuit "baik" yang mempunyai masa evolusi yang sama seperti Circuit sasaran, tetapi dengan langkah Trotter yang lebih sedikit (dan dengan itu lapisan yang lebih sedikit).
Kemudian kita hantar Circuit "baik" ini ke fungsi generate_ansatz_from_circuit AQC-Tensor. Fungsi ini menganalisis sambungan dua-Qubit Circuit dan mengembalikan dua perkara:
- Circuit ansatz berparameter umum dengan sambungan dua-Qubit yang sama seperti Circuit input; dan,
- parameter yang, apabila dimasukkan ke dalam ansatz, menghasilkan Circuit input (baik) tersebut.
Tidak lama lagi kita akan mengambil parameter ini dan menyesuaikannya secara berulang untuk membawa Circuit ansatz sedekat mungkin ke MPS sasaran.
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
Pilih tetapan untuk simulasi rangkaian tensorβ
Di sini, kita menggunakan simulator rangkaian tensor berasaskan quimb. Dalam contoh ini, kita menggunakan simulator keadaan produk matriks (MPS) quimb, dan kita menggunakan JAX untuk pembezaan automatik. Lihat dokumentasi API untuk maklumat lanjut tentang cara menggunakan simulator quimb.
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",
)
Bina perwakilan keadaan produk matriks untuk keadaan sasaran AQCβ
Seterusnya, kita bina perwakilan produk matriks bagi keadaan yang hendak dihampiri oleh AQC.
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)
Perhatikan bahawa oleh kerana kita memilih bilangan langkah Trotter yang banyak untuk keadaan sasaran, ia sebenarnya mempunyai ralat Trotter yang lebih kecil berbanding Circuit perbandingan. Kita boleh mengira kesetiaan () bagi keadaan yang disediakan oleh Circuit perbandingan berbanding keadaan sasaran:
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
Optimumkan parameter ansatz menggunakan pengiraan MPSβ
Di sini, kita meminimumkan fungsi kos paling mudah, MaximizeStateFidelity, dengan menggunakan pengoptimum L-BFGS dari scipy.
Kita pilih titik henti untuk kesetiaan supaya ia akan berada di atas apa yang dimiliki Circuit perbandingan tanpa menggunakan AQC. Setelah ini dicapai, Circuit yang dimampatkan mempunyai ralat Trotter yang lebih kecil dan kedalaman yang lebih rendah berbanding Circuit asal. Dengan lebih banyak masa pemprosesan, langkah pengoptimuman lanjut boleh dilakukan untuk meningkatkan kesetiaan lebih tinggi lagi.
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.
Bina Circuit akhir untuk dihantar ke Transpilerβ
final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
final_circuit.compose(subsequent_circuit, inplace=True)
final_circuit.draw("mpl", fold=-1)

Langkah 2: Transpile untuk pelaksanaan pada perkakasan sasaranβ
Dalam Langkah 2 sebuah corak Qiskit, kita men-transpile Circuit ini dan mana-mana observable yang dikehendaki untuk pelaksanaan pada peranti sasaran. Di sini kita menggunakan Backend palsu yang disediakan oleh 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)
Circuit ISA yang terhasil kemudiannya boleh dihantar untuk pelaksanaan pada Backend (langkah 3 sebuah corak Qiskit).
Langkah 3: Jalankan pada perkakasan kuantumβ
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(backend)
job = estimator.run([(isa_circuit, isa_observable)])
pub_result = job.result()[0]
Langkah 4: Bina Semulaβ
Pembinaan semula tidak diperlukan dalam kes kita. Kita boleh terus melihat keputusannya.
pub_result.data.evs[()]
np.float64(0.047998046875000006)