Mengurangi kedalaman Circuit dengan addon AQC-Tensor Qiskit
Dalam notebook ini, kita akan menjalankan langkah-langkah sebuah pola Qiskit sambil menggunakan kompilasi kuantum aproksimasi dengan tensor network (AQC-Tensor) untuk mencapai kedalaman Circuit yang lebih rendah dari yang biasanya dibutuhkan dalam melakukan evolusi Trotter.
Berikut adalah langkah-langkah yang akan kita lakukan:
- Langkah 1: Petakan ke masalah kuantum
- Inisialisasi Hamiltonian dan observable masalah kita
- Buat state tensor-network target untuk bagian awal Circuit
- Buat Circuit berkedalaman rendah yang mengaproksimasi bagian yang dikompresi
- Buat ansatz umum dari Circuit tersebut
- Optimalkan parameter agar ansatz sedekat mungkin dengan target
- Tambahkan langkah Trotter berikutnya ke ansatz yang sudah dioptimalkan
- Langkah 2: Optimalkan untuk hardware target
- Transpile Circuit untuk hardware
- Langkah 3: Jalankan eksperimen
- Gunakan fake backend untuk kemudahan
- Langkah 4: Rekonstruksi hasil
- N/A; sebagai gantinya, kita hanya menampilkan observable yang diukur
Langkah 1: Petakan ke Circuit kuantum dan operatorβ
Siapkan model Hamiltonian dan observableβ
Dalam notebook ini, kita menggunakan model Ising pada lingkaran 10 site:
di mana kondisi batas periodik menyiratkan bahwa untuk kita mendapatkan , adalah kekuatan kopling antara dua site dan adalah medan magnet eksternal.
# 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 total magnetisasi.
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 seberapa banyak evolusi waktu yang disimulasikan secara klasikβ
Tujuan keseluruhan kita adalah mensimulasikan evolusi waktu dari model Hamiltonian di atas. Kita melakukannya dengan evolusi Trotter, yang kita bagi menjadi dua bagian:
- Bagian awal yang dapat disimulasikan dengan matrix product states (MPS). Kita akan "mengompilasi" bagian ini menggunakan AQC seperti yang disajikan di https://arxiv.org/abs/2301.08609.
- Bagian Circuit berikutnya yang akan dieksekusi pada hardware. Mari kita rencanakan menggunakan AQC-Tensor untuk mengompresi Circuit evolusi waktu kita hingga waktu , lalu berevolusi menggunakan langkah Trotter biasa hingga .
Buat Circuit sebelum dan sesudah pemisahanβ
Setelah kita memilih untuk memisah pada , kita akan membuat dua Circuit:
- Circuit "target" untuk bagian AQC dari evolusi, dari hingga . Karena ini disimulasikan oleh simulator tensor-network, jumlah layer hanya mempengaruhi waktu eksekusi dengan faktor konstan, jadi kita bisa menggunakan jumlah layer yang lebih banyak untuk meminimalkan error 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 berikutnya, yang berevolusi dari hingga . Karena ini akan dijalankan pada hardware kuantum, disarankan menggunakan sesedikit mungkin layer 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,
)
Untuk keperluan perbandingan nantinya, mari kita juga buat Circuit ketiga: satu yang berevolusi selama aqc_evolution_time tetapi memiliki waktu evolusi per langkah Trotter yang sama seperti Circuit berikutnya. Ini adalah Circuit yang akan kita gunakan seandainya kita tidak menggunakan jumlah langkah Trotter yang banyak untuk Circuit target. Kita akan menyebutnya sebagai Circuit pembanding.
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,
)
Buat ansatz dan parameter awal dari Circuit Trotter dengan lebih sedikit langkahβ
Pertama, kita buat Circuit "baik" yang memiliki waktu evolusi yang sama dengan Circuit target, tetapi dengan lebih sedikit langkah Trotter (dan dengan demikian lebih sedikit layer).
Kemudian kita teruskan Circuit "baik" ini ke fungsi generate_ansatz_from_circuit milik AQC-Tensor. Fungsi ini menganalisis konektivitas dua-Qubit dari Circuit dan mengembalikan dua hal:
- Circuit ansatz berparameter umum dengan konektivitas dua-Qubit yang sama seperti Circuit input; dan,
- parameter yang, ketika dimasukkan ke dalam ansatz, menghasilkan Circuit input (baik) tersebut.
Sebentar lagi kita akan mengambil parameter-parameter ini dan menyesuaikannya secara iteratif untuk membawa Circuit ansatz sedekat mungkin ke 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
Pilih pengaturan untuk simulasi tensor networkβ
Di sini, kita menggunakan simulator tensor network berbasis quimb. Dalam contoh ini, kita menggunakan simulator matrix-product state (MPS) dari quimb, dan kita menggunakan JAX untuk diferensiasi otomatis. Lihat dokumentasi API untuk informasi lebih 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",
)
Buat representasi matrix-product state dari state target AQCβ
Selanjutnya, kita membangun representasi matrix-product dari state yang akan diaproksimasi oleh AQC.
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
aqc_target_mps = tensornetwork_from_circuit(aqc_target_circuit, simulator_settings)
Perlu dicatat bahwa karena kita memilih jumlah langkah Trotter yang banyak untuk state target, state tersebut sebenarnya memiliki error Trotter yang lebih kecil dibanding Circuit pembanding. Kita dapat menghitung fidelitas () dari state yang disiapkan oleh Circuit pembanding vs. state target:
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
Optimalkan parameter ansatz menggunakan perhitungan MPSβ
Di sini, kita meminimalkan fungsi cost paling sederhana, MaximizeStateFidelity, menggunakan optimizer L-BFGS dari scipy.
Kita memilih titik henti untuk fidelitas sehingga nilainya akan berada di atas fidelitas yang dimiliki Circuit pembanding tanpa menggunakan AQC. Setelah ini tercapai, Circuit yang dikompresi memiliki error Trotter yang lebih kecil dan kedalaman yang lebih rendah dari Circuit aslinya. Dengan waktu pemrosesan lebih lama, langkah optimasi lebih lanjut dapat dilakukan untuk meningkatkan fidelitas 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.
Buat Circuit akhir untuk diteruskan 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 eksekusi pada hardware targetβ
Pada Langkah 2 dari sebuah pola Qiskit, kita men-transpile Circuit ini dan observable yang diinginkan untuk eksekusi pada perangkat target. Di sini kita menggunakan fake backend 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 dihasilkan kemudian dapat dikirim untuk eksekusi pada backend (langkah 3 dari sebuah pola Qiskit).
Langkah 3: Eksekusi pada hardware 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: Rekonstruksiβ
Rekonstruksi tidak diperlukan dalam kasus kita. Kita bisa langsung melihat hasilnya.
pub_result.data.evs[()]
np.float64(0.047998046875000006)