Mengurangkan kedalaman Circuit dengan operator backpropagation
Operator backpropagation adalah teknik yang melibatkan penyerapan operasi dari hujung quantum Circuit ke dalam operator Pauli, yang secara umumnya mengurangkan kedalaman Circuit dengan kos tambahan istilah dalam operator tersebut. Matlamatnya adalah untuk backpropagate sebanyak mungkin Circuit tanpa membiarkan operator membesar terlalu besar.
Salah satu cara untuk membolehkan backpropagation yang lebih dalam ke dalam Circuit, sambil mencegah operator daripada membesar terlalu besar, adalah dengan memangkas istilah yang mempunyai pekali kecil, daripada menambahkannya ke dalam operator. Memangkas istilah boleh menghasilkan lebih sedikit quantum Circuit untuk dilaksanakan, tetapi berbuat demikian mengakibatkan sedikit ralat dalam pengiraan nilai jangkaan akhir yang berkadar dengan magnitud pekali istilah yang dipangkas. Dalam tutorial ini kita akan melaksanakan corak Qiskit untuk mensimulasikan dinamik kuantum rantai spin Heisenberg menggunakan operator backpropagation:
- Langkah 1: Peta ke masalah kuantum
- Petakan Hamiltonian yang berevolusi masa ke atas quantum Circuit
- Langkah 2: Optimumkan masalah
- Potong Circuit
- Backpropagate kepingan dari Circuit ke atas observable Pauli
- Gabungkan kepingan yang tinggal ke dalam satu Circuit tunggal
- Transpile Circuit untuk Backend
- Langkah 3: Jalankan eksperimen
- Kira nilai jangkaan menggunakan Circuit yang dikurangkan dan observable yang diperluaskan dengan StatevectorEstimator untuk memudahkan dalam notebook ini
- Langkah 4: Bina semula keputusan
- T.B.
Nota: Qiskit secara longgar menerangkan lapisan sebagai partition kedalaman-1 dari Circuit merentasi semua Qubit. Pakej ini menggunakan istilah kepingan untuk menerangkan lapisan dengan kedalaman sewenang-wenangnya. Fungsi qiskit_addon_obp.backpropagate direka untuk backpropagate keseluruhan kepingan pada satu masa, jadi pilihan cara memotong quantum Circuit boleh memberi kesan besar kepada seberapa baik backpropagation berfungsi untuk masalah tertentu. Kamu akan belajar lebih lanjut tentang kepingan di bawah.
Langkah 1: Peta ke masalah kuantum​
Petakan evolusi masa model Heisenberg kuantum ke eksperimen kuantum.​
Pakej qiskit_addon_utils menyediakan beberapa fungsi yang boleh digunakan semula untuk pelbagai tujuan.
Modul qiskit_addon_utils.problem_generators menyediakan fungsi untuk menjana Hamiltonian seperti Heisenberg pada graf sambungan tertentu. Graf ini boleh sama ada rustworkx.PyGraph atau CouplingMap yang memudahkan penggunaannya dalam aliran kerja berpusatkan Qiskit.
Dalam bahagian berikut, kita mula-mula menjana CouplingMap heavy-hex yang daripadanya kita ukir rantai linear 10 Qubit. Perlu diambil perhatian bahawa indeks reduced_coupling_map yang baru ini sekali lagi bermula dari sifar.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-addon-obp qiskit-addon-utils qiskit-ibm-runtime rustworkx
from qiskit.transpiler import CouplingMap
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)
# Choose a 10-qubit linear chain on this coupling map
reduced_coupling_map = coupling_map.reduce([0, 13, 1, 14, 10, 16, 5, 12, 8, 18])
from rustworkx.visualization import graphviz_draw
graphviz_draw(reduced_coupling_map.graph, method="circo")
Seterusnya, kita menjana operator Pauli yang memodelkan Hamiltonian Heisenberg XYZ.
J_{y} \sigma_j^{y} \sigma_{k}^{y} + J_{z} \sigma_j^{z} \sigma_{k}^{z}) + \sum_{j\in V} (h_{x} \sigma_j^{x} + h_{y} \sigma_j^{y} + h_{z} \sigma_j^{z})$$ Di mana $G(V,E)$ adalah graf peta sambungan yang diberikan. ```python import numpy as np from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian # Get a qubit operator describing the Heisenberg XYZ model hamiltonian = generate_xyz_hamiltonian( reduced_coupling_map, coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2), ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9), ) print(hamiltonian) ``` ```text SparsePauliOp(['IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIIIX', 'IIIIIIIIIY', 'IIIIIIIIIZ', 'IIIIIIIIXI', 'IIIIIIIIYI', 'IIIIIIIIZI', 'IIIIIIIXII', 'IIIIIIIYII', 'IIIIIIIZII', 'IIIIIIXIII', 'IIIIIIYIII', 'IIIIIIZIII', 'IIIIIXIIII', 'IIIIIYIIII', 'IIIIIZIIII', 'IIIIXIIIII', 'IIIIYIIIII', 'IIIIZIIIII', 'IIIXIIIIII', 'IIIYIIIIII', 'IIIZIIIIII', 'IIXIIIIIII', 'IIYIIIIIII', 'IIZIIIIIII', 'IXIIIIIIII', 'IYIIIIIIII', 'IZIIIIIIII', 'XIIIIIIIII', 'YIIIIIIIII', 'ZIIIIIIIII'], coeffs=[0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 0.39269908+0.j, 0.78539816+0.j, 1.57079633+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j, 1.04719755+0.j, 0.52359878+0.j, 0.34906585+0.j]) ``` Daripada operator Qubit, kita boleh menjana quantum Circuit yang memodelkan evolusi masanya. Sekali lagi, modul [qiskit_addon_utils.problem_generators](https://qiskit.github.io/qiskit-addon-utils/stubs/qiskit_addon_utils.problem_generators.html) datang membantu dengan fungsi yang berguna untuk melakukan tepat itu: ```python from qiskit.synthesis import LieTrotter from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit circuit = generate_time_evolution_circuit( hamiltonian, time=0.2, synthesis=LieTrotter(reps=2), ) circuit.draw("mpl", style="iqp", scale=0.6) ```  ## Langkah 2: Optimumkan masalah \{#step-2-optimize-the-problem} ### Cipta kepingan Circuit untuk backpropagate \{#create-circuit-slices-to-backpropagate} Ingat, fungsi ``backpropagate`` akan backpropagate keseluruhan kepingan Circuit pada satu masa, jadi pilihan cara memotong boleh memberi kesan kepada seberapa baik backpropagation berfungsi untuk masalah tertentu. Di sini, kita akan mengumpulkan Gate yang sama jenis ke dalam kepingan menggunakan fungsi [slice_by_gate_types](https://qiskit.github.io/qiskit-addon-utils/stubs/qiskit_addon_utils.slicing.slice_by_gate_types.html). Untuk perbincangan lebih terperinci tentang pemotongan Circuit, semak [panduan cara-untuk](https://qiskit.github.io/qiskit-addon-utils/how_tos/create_circuit_slices.html) pakej [qiskit-addon-utils](https://qiskit.github.io/qiskit-addon-utils/index.html) ini. ```python from qiskit_addon_utils.slicing import slice_by_gate_types slices = slice_by_gate_types(circuit) print(f"Separated the circuit into {len(slices)} slices.") ``` ```text Separated the circuit into 18 slices. ``` ### Hadkan seberapa besar operator boleh membesar semasa backpropagation \{#constrain-how-large-the-operator-may-grow-during-backpropagation} Semasa backpropagation, bilangan istilah dalam operator secara umumnya akan mendekati $4^N$ dengan cepat, di mana $N$ adalah bilangan Qubit. Saiz operator boleh dibataskan dengan menyatakan kwarg ``operator_budget`` fungsi ``backpropagate``, yang menerima contoh [OperatorBudget](https://qiskit.github.io/qiskit-addon-obp/stubs/qiskit_addon_obp.utils.simplify.OperatorBudget.html). Di sini kita menyatakan bahawa backpropagation harus berhenti apabila bilangan kumpulan Pauli yang bertukar-tukar secara Qubit-wise dalam operator melebihi 8. ```python from qiskit_addon_obp.utils.simplify import OperatorBudget op_budget = OperatorBudget(max_qwc_groups=8) ``` ### Backpropagate kepingan dari Circuit \{#backpropagate-slices-from-the-circuit} Pertama, kita akan menyatakan observable Pauli-Z pada Qubit 0, dan kita akan backpropagate kepingan dari Circuit evolusi masa sehingga istilah dalam observable tidak lagi boleh digabungkan menjadi 8 atau kurang kumpulan Pauli yang bertukar-tukar secara Qubit-wise. Di bawah kamu akan melihat bahawa kita backpropagated 7 kepingan tetapi hanya menggunakan 6 daripada 8 kumpulan Pauli yang diperuntukkan. Ini bermakna bahawa backpropagating satu kepingan lagi akan menyebabkan bilangan kumpulan Pauli melebihi 8. Kita boleh mengesahkan bahawa ini adalah kes dengan memeriksa metadata yang dikembalikan. ```python from qiskit.quantum_info import SparsePauliOp from qiskit_addon_obp import backpropagate from qiskit_addon_utils.slicing import combine_slices # Specify a single-qubit observable observable = SparsePauliOp("IIIIIIIIIZ") # Backpropagate slices onto the observable bp_obs, remaining_slices, metadata = backpropagate(observable, slices, operator_budget=op_budget) # Recombine the slices remaining after backpropagation bp_circuit = combine_slices(remaining_slices, include_barriers=True) print(f"Backpropagated {metadata.num_backpropagated_slices} slices.") print( f"New observable has {len(bp_obs.paulis)} terms, which can be combined into {len(bp_obs.group_commuting(qubit_wise=True))} groups." ) print( f"Note that backpropagating one more slice would result in {metadata.backpropagation_history[-1].num_paulis[0]} terms " f"across {metadata.backpropagation_history[-1].num_qwc_groups} groups." ) print("The remaining circuit after backpropagation looks as follows:") bp_circuit.draw("mpl", scale=0.6) ``` ```text Backpropagated 7 slices. New observable has 18 terms, which can be combined into 8 groups. Note that backpropagating one more slice would result in 27 terms across 12 groups. The remaining circuit after backpropagation looks as follows: ```  Seterusnya, kita akan menyatakan masalah yang sama dengan kekangan yang sama pada saiz observable output. Walau bagaimanapun, kali ini, kita memperuntukkan belanjawan ralat kepada setiap kepingan menggunakan fungsi [setup_budet](https://qiskit.github.io/qiskit-addon-obp/stubs/qiskit_addon_obp.utils.truncating.setup_budget.html). Istilah Pauli dengan pekali kecil akan dipangkas dari setiap kepingan sehingga belanjawan ralat dipenuhi, dan baki belanjawan akan ditambahkan ke belanjawan kepingan berikutnya. Untuk membolehkan pemangkasan ini, kita perlu menyediakan belanjawan ralat kita seperti ini: ```python from qiskit_addon_obp.utils.truncating import setup_budget truncation_error_budget = setup_budget(max_error_per_slice=0.005) ``` Perhatikan bahawa dengan memperuntukkan ralat `5e-3` setiap kepingan untuk pemangkasan, kita dapat mengeluarkan 3 kepingan lagi dari Circuit, sambil kekal dalam belanjawan asal 8 kumpulan Pauli yang bertukar-tukar dalam observable. Secara lalai, `backpropagate` menggunakan norma L1 bagi pekali yang dipangkas untuk membataskan jumlah ralat yang ditanggung dari pemangkasan. Untuk pilihan lain rujuk [panduan cara-untuk tentang menyatakan p_norm](https://qiskit.github.io/qiskit-addon-obp/how_tos/bound_error_using_p_norm.html). Dalam contoh khusus ini di mana kita telah backpropagated 10 kepingan, jumlah ralat pemangkasan tidak sepatutnya melebihi ``(5e-3 ralat/kepingan) * (10 kepingan) = 5e-2``. Untuk perbincangan lanjut tentang mengagihkan belanjawan ralat merentasi kepingan kamu, semak [panduan cara-untuk ini](https://qiskit.github.io/qiskit-addon-obp/how_tos/truncate_operator_terms.html). ```python # Run the same experiment but truncate observable terms with small coefficients bp_obs_trunc, remaining_slices_trunc, metadata = backpropagate( observable, slices, operator_budget=op_budget, truncation_error_budget=truncation_error_budget ) # Recombine the slices remaining after backpropagation bp_circuit_trunc = combine_slices(remaining_slices_trunc, include_barriers=True) print(f"Backpropagated {metadata.num_backpropagated_slices} slices.") print( f"New observable has {len(bp_obs_trunc.paulis)} terms, which can be combined into {len(bp_obs_trunc.group_commuting(qubit_wise=True))} groups.\n" f"After truncation, the error in our observable is bounded by {metadata.accumulated_error(0):.3e}" ) print( f"Note that backpropagating one more slice would result in {metadata.backpropagation_history[-1].num_paulis[0]} terms " f"across {metadata.backpropagation_history[-1].num_qwc_groups} groups." ) print("The remaining circuit after backpropagation looks as follows:") bp_circuit_trunc.draw("mpl", scale=0.6) ``` ```text Backpropagated 10 slices. New observable has 19 terms, which can be combined into 8 groups. After truncation, the error in our observable is bounded by 4.933e-02 Note that backpropagating one more slice would result in 27 terms across 13 groups. The remaining circuit after backpropagation looks as follows: ```  ### Sekarang kita sudah mempunyai ansatz yang dikurangkan dan observable yang diperluaskan, kita boleh transpile eksperimen kita ke Backend. \{#now-that-we-have-our-reduced-ansatze-and-expanded-observables-we-can-transpile-our-experiments-to-the-backend} Di sini kita akan menggunakan [FakeMelbourneV2](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime/fake-provider-fake-melbourne-v2) 14-Qubit dari [qiskit-ibm-runtime](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime) untuk menunjukkan cara untuk transpile ke Backend QPU. ```python from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit_ibm_runtime.fake_provider import FakeMelbourneV2 # Specify a backend and a pass manager for transpilation backend = FakeMelbourneV2() pm = generate_preset_pass_manager(backend=backend, optimization_level=1) # Transpile original experiment circuit_isa = pm.run(circuit) observable_isa = observable.apply_layout(circuit_isa.layout) # Transpile backpropagated experiment bp_circuit_isa = pm.run(bp_circuit) bp_obs_isa = bp_obs.apply_layout(bp_circuit_isa.layout) # Transpile the backpropagated experiment with truncated observable terms bp_circuit_trunc_isa = pm.run(bp_circuit_trunc) bp_obs_trunc_isa = bp_obs_trunc.apply_layout(bp_circuit_trunc_isa.layout) ``` ## Langkah 3: Jalankan eksperimen kuantum \{#step-3-execute-quantum-experiments} ### Kira nilai jangkaan \{#calculate-expectation-value} Akhirnya, kita boleh menjalankan eksperimen yang backpropagated dan membandingkannya dengan eksperimen penuh menggunakan [StatevectorEstimator](https://quantum.cloud.ibm.com/docs/api/qiskit/qiskit.primitives.StatevectorEstimator) tanpa hingar. Kita dapat melihat bahawa nilai jangkaan yang backpropagated tanpa pemangkasan bersamaan dengan nilai tepat dalam had ketepatan berangka. Nilai jangkaan pada operator dengan istilah yang dipangkas mempunyai sedikit ralat pada peringkat ``1e-4``, yang berada dalam toleransi yang dijangkakan. **Nota:** Kita menggunakan primitif ``Estimator`` berasaskan statevector untuk menggambarkan kesan pemangkasan pada output. Untuk dijalankan pada Backend yang eksperimen telah di-transpile dalam Langkah 2, seseorang perlu mengimport [EstimatorV2](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime/estimator-v2) dari ``qiskit-ibm-runtime`` dan menghantar contoh Backend ke dalam konstruktor. ```python from qiskit.primitives import StatevectorEstimator as Estimator estimator = Estimator() # Run the experiments using Estimator primitive result_exact = estimator.run([(circuit_isa, observable_isa)]).result()[0].data.evs.item() result_bp = estimator.run([(bp_circuit_isa, bp_obs_isa)]).result()[0].data.evs.item() result_bp_trunc = ( estimator.run([(bp_circuit_trunc_isa, bp_obs_trunc_isa)]).result()[0].data.evs.item() ) print(f"Exact expectation value: {result_exact}") print(f"Backpropagated expectation value: {result_bp}") print(f"Backpropagated expectation value with truncation: {result_bp_trunc}") print(f" - Expected Error for truncated observable: {metadata.accumulated_error(0):.3e}") print(f" - Observed Error for truncated observable: {abs(result_exact - result_bp_trunc):.3e}") ``` ```text Exact expectation value: 0.8854160687717507 Backpropagated expectation value: 0.8854160687717532 Backpropagated expectation value with truncation: 0.8850236647156059 - Expected Error for truncated observable: 4.933e-02 - Observed Error for truncated observable: 3.924e-04 ``` <TutorialFeedback />