Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Cara menyelaraskan pilihan konfigurasi

Pengiraan sempadan adalah tepat pada prinsipnya tetapi hampiran dalam amalan: mengembangkan satu sebutan ralat Pauli melalui litar menghasilkan operator dengan sebutan yang banyak secara eksponen, dan mencari norma spektrum bagi komutator yang terhasil itu sendiri adalah mahal. Pilihan di bawah mengawal kos tersebut. Ia terbahagi kepada tiga kumpulan:

  • Pilihan Ketepatan mengubah nilai berangka sempadan, dengan menukar keketatan dengan kos.

  • Skop menentukan sempadan yang mana satu dikira.

  • Pilihan Pelaksanaan mengubah cara pengiraan berjalan (bukan apa yang dikira).

PilihanLalaiMengawalKesan pada hasil
Ketepatan
evolution_max_terms1_000_000Berapa banyak sebutan operator yang kekal selepas evolusiLebih rendah: lebih murah, sempadan lebih longgar
atol_simplify1e-8Sebutan komutator yang mana dibuang sebagai boleh diabaikanLebih tinggi: lebih murah, sempadan lebih longgar
eigval_max_qubits14Selebar mana komutator boleh dikira norma spektrumnyaLebih rendah: lebih murah, sempadan lebih longgar
atol_eigenvalue1e-10Bila penyelesai eigen lelaran dianggap telah menumpuLebih tinggi: lebih murah, sempadan kurang tepat
Skop
max_num_boxesNoneBerapa banyak kotak yang sempadannya dikiraKotak melebihi had mengekalkan sempadan remeh 2.0
Pelaksanaan
timeoutNoneBajet masa jam dinding untuk keseluruhan pengiraanSebarang kerja yang tinggal mengekalkan sempadan remeh 2.0
num_processes1Berapa banyak proses pekerja mengira sempadan secara selariTiada kesan dengan sendirinya

Sesuatu sempadan hanya berguna jika ia sah: ia tidak boleh sekali-kali memperkecilkan kesan sesuatu sebutan ralat terhadap observabel. Melonggarkan mana-mana pilihan ini selain atol_eigenvalue hanya boleh menjadikan sempadan lebih besar (lebih konservatif), tidak pernah lebih kecil. Oleh itu, kos tetapan yang longgar ialah overhed persampelan yang lebih besar, bukan nilai jangkaan yang salah - atol_eigenvalue ialah pengecualian.

Takrifan litar​

Eksperimen berikut menggunakan litar Ising Trotter dan observabel yang sama seperti panduan permulaan pantas. Pada saiz ini, setiap pilihan mempunyai kesan yang kelihatan manakala setiap pengiraan masih mengambil masa kurang daripada satu saat.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_addon_slc": "qiskit-addon-slc", "samplomatic": "samplomatic"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Pauli
from qiskit_addon_slc.utils import generate_noise_model_paulis
from samplomatic.transpiler import generate_boxing_pass_manager
from samplomatic.utils import find_unique_box_instructions

def trotter_ising_circuit(num_qubits, num_steps, rx_angle, rzz_angle):
"""Trotterized transverse-field Ising evolution on a 1D chain."""
circuit = QuantumCircuit(num_qubits)
for _ in range(num_steps):
circuit.rx(rx_angle, range(num_qubits))
circuit.barrier()
for start in (0, 1): # even then odd bonds
for i in range(start, num_qubits - 1, 2):
circuit.rzz(rzz_angle, i, i + 1)
circuit.barrier()
return circuit

num_qubits = 10
circuit = trotter_ising_circuit(
num_qubits, num_steps=4, rx_angle=np.pi / 16, rzz_angle=-np.pi / 3
)
observable = Pauli("I" * num_qubits).compose("Z", [num_qubits // 2])

boxing_pass = generate_boxing_pass_manager(
inject_noise_targets="all",
inject_noise_strategy="individual_modification",
inject_noise_site="after",
twirling_strategy="active",
remove_barriers="never",
)
boxed_circuit = boxing_pass.run(circuit)
noise_model_paulis = generate_noise_model_paulis(
find_unique_box_instructions(boxed_circuit)
)

print(f"noisy layers: {len(noise_model_paulis)}")
print(
f"Pauli error terms: {sum(len(p) for p in noise_model_paulis.values())}"
)
noisy layers: 2
Pauli error terms: 198

Pembantu kecil meringkaskan setiap set sempadan dalam satu baris, supaya kesan sesuatu pilihan muncul sebagai beberapa nombor dan bukannya timbunan tatasusunan.

Setiap sempadan terletak antara 0 dan sempadan remeh 2.0. Ringkasan melaporkan purata sempadan dan sisihan piawainya, diikuti dengan cara sebutan terbahagi kepada kumpulan berikut:

  • Sebutan yang dibatasi tepat oleh 0 kerana ia mengkomut dengan observabel yang telah berevolusi
  • Sebutan dengan sempadan yang dikira antara 0 dan 2.0
  • Sebutan yang kekal pada 2.0 remeh

Perhatikan bahawa purata yang lebih rendah bermaksud lebih ketat, dan lebih ketat bermaksud overhed persampelan yang lebih kecil kemudian.

Sapuan ke atas satu pilihan menandakan lalai pilihan itu dengan *:

import inspect
import time

from qiskit_addon_slc.bounds import compute_forward_bounds

def summarize(rates, label, elapsed):
"""Prints a one-line summary of a set of bounds."""
# The bounds are floating-point results, so a term counts as bounded by 0, or as left at the
# trivial 2.0, when it is within rounding error of that value.
exact = np.isclose(rates, 0.0, rtol=0.0, atol=1e-12)
trivial = np.isclose(rates, 2.0, rtol=0.0, atol=1e-12)
computed = ~exact & ~trivial
print(
f"{label:28} mean {rates.mean():.4f} ± {rates.std():.3f} │ "
f"at 0: {exact.mean():4.0%} computed: {computed.mean():4.0%} "
f"at 2.0: {trivial.mean():4.0%} │ "
f"{elapsed:4.2f}s"
)

def forward(label, **kwargs):
"""Computes the forward bounds, summarizes them and returns all their rates."""
start = time.perf_counter()
bounds = compute_forward_bounds(
boxed_circuit, noise_model_paulis, observable, **kwargs
)
elapsed = time.perf_counter() - start
rates = np.concatenate([bound.rates for bound in bounds.values()])
summarize(rates, label, elapsed)
return rates

def sweep(option, values):
"""Computes the forward bounds for each value of one option, marking the default with `*`."""
default = (
inspect.signature(compute_forward_bounds).parameters[option].default
)
for value in values:
marker = "*" if value == default else " "
forward(f"{marker} {option}={value:g}", **{option: value})

baseline = forward(" defaults")
defaults mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.29s

Ketepatan​

evolution_max_terms​

Mengembangkan sebutan ralat Pauli melalui get bukan Clifford menjadikannya hasil tambah Pauli, dan hasil tambah itu bertambah besar dengan kedalaman litar. evolution_max_terms menghadkan berapa banyak sebutan itu disimpan. Norma-1 bagi apa sahaja yang dibuang ditambah kepada sempadan, jadi tiada apa yang hilang secara senyap.

Sapuan bermula daripada lebih ketat berbanding lalai hingga ke pemotongan melampau. Menurunkan had menjadikan pengiraan lebih murah dan sempadan lebih longgar.

sweep("evolution_max_terms", (10_000_000, 1_000_000, 1000, 100, 10, 2))
evolution_max_terms=1e+07 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.38s
* evolution_max_terms=1e+06 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.31s
evolution_max_terms=1000 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.30s
evolution_max_terms=100 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.29s
evolution_max_terms=10 mean 0.3927 ± 0.711 │ at 0: 59% computed: 31% at 2.0: 9% │ 0.28s
evolution_max_terms=2 mean 0.5245 ± 0.792 │ at 0: 59% computed: 23% at 2.0: 18% │ 0.21s

Menaikkan had melepasi lalainya tidak mengubah apa-apa di sini. Bagi litar bersaiz ini, lalai sudah pun menyimpan setiap sebutan, jadi sempadan adalah seketat yang boleh dicapai oleh pilihan ini. Itulah situasi lazim. Mengetatkan pilihan ketepatan hanya berbaloi apabila lalainya benar-benar menghad, dan cara untuk mengetahuinya ialah eksperimen di atas. Jalankan semula dengan nilai yang lebih ketat dan lihat sama ada sempadan bergerak.

Amaran: Rutin perambatan asas menganggap evolution_max_terms sebagai kapasiti untuk pra-peruntukan, bukan sebagai had atas untuk disemak. Memasukkan sesuatu yang kononnya tanpa had, seperti numpy.iinfo(numpy.uint).max, meminta pengagih memori sebanyak terabait dan menghentikan proses. Kekalkan pada nombor yang realistik. Lalai satu juta sudah memadai.

atol_simplify​

Selepas komutator dibentuk, sebutan dengan pekali di bawah atol_simplify dibuang. Seperti had evolusi, norma-1 yang hilang dengan cara ini ditambah kepada sempadan.

sweep("atol_simplify", (0.0, 1e-8, 1e-4, 1e-2, 1e-1))
atol_simplify=0 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.32s
* atol_simplify=1e-08 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.31s
atol_simplify=0.0001 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.33s
atol_simplify=0.01 mean 0.3656 ± 0.685 │ at 0: 59% computed: 35% at 2.0: 6% │ 0.31s
atol_simplify=0.1 mean 0.3837 ± 0.697 │ at 0: 59% computed: 31% at 2.0: 10% │ 0.31s

eigval_max_qubits​

Sempadan paling ketat yang tersedia ialah norma spektrum komutator, yang memerlukan pengiraan nilai eigen. Itu menjadi mahal apabila komutator melebar, jadi eigval_max_qubits menetapkan lebar melebihi yang mana percubaan ditinggalkan dan digantikan dengan ketaksamaan segi tiga. Sempadan itu, 2∑i∣ci∣2 \sum_i |c_i| ke atas pekali komutator cic_i, adalah sah tetapi lebih longgar.

Menetapkannya kepada sifar memaksa penggunaan alternatif di mana-mana, yang menunjukkan manfaat penyelesai eigen dalam satu nombor.

sweep("eigval_max_qubits", (20, 14, 8, 4, 2, 0))
eigval_max_qubits=20 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.31s
* eigval_max_qubits=14 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.30s
eigval_max_qubits=8 mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.32s
eigval_max_qubits=4 mean 0.3742 ± 0.694 │ at 0: 59% computed: 35% at 2.0: 6% │ 0.30s
eigval_max_qubits=2 mean 0.4983 ± 0.809 │ at 0: 59% computed: 23% at 2.0: 18% │ 0.27s
eigval_max_qubits=0 mean 0.5081 ± 0.810 │ at 0: 59% computed: 21% at 2.0: 19% │ 0.27s

Walaupun penyelesai eigen dimatikan, purata kekal jauh di bawah 2.0 remeh. Bahagian sebutan yang dibatasi oleh 0 tidak berubah: sebutan yang mengkomut tepat dengan observabel yang telah berevolusi mempunyai komutator sifar, yang dikenali sebelum sebarang pengiraan nilai eigen dipertimbangkan. Bagi yang lain, sempadan ketaksamaan segi tiga mencapai 2.0 untuk sesetengahnya dan dihadkan di situ, tetapi bagi banyak yang lain ia masih lebih kecil, jadi ia mengekalkan sempadan yang dikira di bawah 2.0.

atol_eigenvalue​

Apabila norma spektrum dikira, atol_eigenvalue ialah toleransi penumpuan bagi penyelesai eigen lelaran. Walau bagaimanapun, kebanyakan komutator tidak pernah sampai kepada penyelesai itu:

  • Komutator yang bertindak pada paling banyak empat qubit didiagonalkan secara tepat, terus.

  • Komutator yang lebih lebar mula-mula dikurangkan kepada bilangan qubit terkecil yang diperlukan oleh sebutan Paulinya, dan jika bentuk terkurang itu bertindak pada paling banyak lapan qubit, ia didiagonalkan secara tepat.

Hanya komutator yang masih memerlukan lebih daripada lapan qubit selepas pengurangan itu pergi kepada penyelesai lelaran, iaitu satu-satunya tempat toleransi ini terpakai. Litar bersaiz seperti yang digunakan dalam panduan ini tidak pernah sampai sejauh itu, jadi sapuan ke atas pilihan ini akan menunjukkan sempadan yang sama bagi setiap nilai. Ia penting untuk kon cahaya yang lebar pada peranti besar.

Tidak seperti pilihan ketepatan yang lain, melonggarkan atol_eigenvalue tidak selamat dalam satu arah. Penyelesai eigen lelaran menghampiri nilai eigen ekstrem dari dalam spektrum, jadi anggaran yang belum menumpu sepenuhnya memperkecilkan norma spektrum, dan juga sempadan. Lalai disengajakan ketat atas sebab itu. Jika penyelesai gagal menumpu, alternatif ketaksamaan segi tiga mengambil alih, yang sah semula.

Skop​

max_num_boxes​

Kadangkala had yang berguna bukan ketepatan tetapi kedalaman. max_num_boxes berhenti menjana pengiraan sempadan melepasi bilangan kotak tertentu, dan setiap lapisan di luarnya diberikan sempadan remeh 2.0 sebagai ganti.

Had itu mengira arahan BoxOp yang bising (yang membawa anotasi InjectNoise) dan bukannya, sebagai contoh, kedalaman dalam get. Itu mengekalkannya terikat kepada struktur litar yang kelihatan oleh pengguna dan mengelakkan gandingan dengan rujukan anotasi yang dijana secara automatik, yang boleh berubah antara jalankan transpilasi.

Ini pilihan semula jadi bagi litar yang dua separuhnya dikendalikan oleh sempadan hadapan dan belakang masing-masing: kira setiap satu hanya sedalam yang akan digunakan.

from qiskit.circuit import BoxOp
from samplomatic import InjectNoise

# The limit counts the noisy boxes encountered while iterating the circuit, not the unique ones:
# a repeated layer is one noise model but several boxes. Boxes without an `InjectNoise`
# annotation carry no error terms and do not count.
num_boxes = sum(
1
for inst in boxed_circuit.data
if isinstance(inst.operation, BoxOp)
and any(
isinstance(annotation, InjectNoise)
for annotation in inst.operation.annotations
)
)
print(
f"the circuit has {num_boxes} noisy boxes drawn from "
f"{len(noise_model_paulis)} distinct noise models\n"
)

for limit in (None, 6, 4, 2, 1):
marker = "*" if limit is None else " "
forward(f"{marker} max_num_boxes={limit}", max_num_boxes=limit)
the circuit has 9 noisy boxes drawn from 2 distinct noise models

* max_num_boxes=None mean 0.3639 ± 0.684 │ at 0: 59% computed: 36% at 2.0: 5% │ 0.33s
max_num_boxes=6 mean 0.7486 ± 0.935 │ at 0: 53% computed: 18% at 2.0: 30% │ 0.18s
max_num_boxes=4 mean 1.1506 ± 0.980 │ at 0: 40% computed: 5% at 2.0: 55% │ 0.11s
max_num_boxes=2 mean 1.5707 ± 0.821 │ at 0: 21% computed: 0% at 2.0: 79% │ 0.05s
max_num_boxes=1 mean 1.8157 ± 0.579 │ at 0: 9% computed: 0% at 2.0: 91% │ 0.03s

Pelaksanaan​

timeout​

timeout ialah bajet masa jam dinding dalam saat. Apabila ia tamat, sempadan yang telah dikira dikekalkan dan semua yang belum selesai mengekalkan sempadan remeh 2.0, jadi hasilnya sentiasa boleh digunakan, cuma lebih longgar jika dihentikan lebih awal.

Ia bukan tarikh akhir yang tegar: tugas yang sedang berjalan dibenarkan untuk selesai, jadi panggilan boleh melebihi bajet sebanyak tempoh satu tugas.

num_processes​

Sempadan bagi sebutan ralat yang berbeza adalah bebas, jadi num_processes mengagihkannya ke atas proses pekerja. Dengan sendirinya, ini hanya menjejaskan berapa lama pengiraan mengambil masa, tidak pernah hasilnya.

Nota: timeout yang digabungkan dengan num_processes menjadikan hasil bergantung pada masa: tugas mana yang selesai sebelum bajet tamat tidak deterministik. Sempadan kekal sah, tetapi ia tidak lagi boleh dihasilkan semula dari satu larian ke larian yang lain.

Di mana hendak bermula​

Lalai dipilih untuk memberikan sempadan yang ketat pada litar bersaiz yang mampu ditanggung. Apabila pengiraan terlalu perlahan, cuba gunakan pilihan mengikut urutan kasar ini:

  1. num_processes: Peningkatan kelajuan percuma, tanpa kos ketepatan.

  2. max_num_boxes: Jika anda tahu lebih awal sedalam mana dalam litar yang anda ambil kisah.

  3. eigval_max_qubits: Melangkau langkah paling mahal bagi komutator terlebar, yang biasanya segelintir kecil daripada sebutan.

  4. evolution_max_terms dan atol_simplify: Ini menjejaskan ketepatan secara menyeluruh, jadi laraskan yang terakhir, sambil menyemak dengan sapuan seperti yang di atas untuk menentukan sejauh mana sempadan bergerak.

  5. timeout: Penghentian tegar dan bukan bantuan penalaan, untuk ketika pengiraan mesti selesai menjelang tarikh akhir, walau apa pun kualitinya.

Semakin longgar sempadan, semakin besar overhed persampelan yang akan dilaporkan oleh compute_local_scales bagi toleransi pincang tertentu. Overhed itu ialah kuantiti yang patut dipantau semasa penalaan: ia memberitahu anda apa kos sebenar hampiran tersebut.