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).
| Pilihan | Lalai | Mengawal | Kesan pada hasil |
|---|---|---|---|
| Ketepatan | |||
evolution_max_terms | 1_000_000 | Berapa banyak sebutan operator yang kekal selepas evolusi | Lebih rendah: lebih murah, sempadan lebih longgar |
atol_simplify | 1e-8 | Sebutan komutator yang mana dibuang sebagai boleh diabaikan | Lebih tinggi: lebih murah, sempadan lebih longgar |
eigval_max_qubits | 14 | Selebar mana komutator boleh dikira norma spektrumnya | Lebih rendah: lebih murah, sempadan lebih longgar |
atol_eigenvalue | 1e-10 | Bila penyelesai eigen lelaran dianggap telah menumpu | Lebih tinggi: lebih murah, sempadan kurang tepat |
| Skop | |||
max_num_boxes | None | Berapa banyak kotak yang sempadannya dikira | Kotak melebihi had mengekalkan sempadan remeh 2.0 |
| Pelaksanaan | |||
timeout | None | Bajet masa jam dinding untuk keseluruhan pengiraan | Sebarang kerja yang tinggal mengekalkan sempadan remeh 2.0 |
num_processes | 1 | Berapa banyak proses pekerja mengira sempadan secara selari | Tiada 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,
ke atas pekali komutator , 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:
-
num_processes: Peningkatan kelajuan percuma, tanpa kos ketepatan. -
max_num_boxes: Jika anda tahu lebih awal sedalam mana dalam litar yang anda ambil kisah. -
eigval_max_qubits: Melangkau langkah paling mahal bagi komutator terlebar, yang biasanya segelintir kecil daripada sebutan. -
evolution_max_termsdanatol_simplify: Ini menjejaskan ketepatan secara menyeluruh, jadi laraskan yang terakhir, sambil menyemak dengan sapuan seperti yang di atas untuk menentukan sejauh mana sempadan bergerak. -
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.