Buat eksperimen pembelajaran
Tutorial ini menunjukkan cara membuat eksperimen pembelajaran standar dari nol, lalu memakainya untuk mempelajari sebuah model dari data noisy hasil simulasi.
-
Definisikan gate set pada sebuah ring qubit
-
Pilih model Pauli-Lindblad 2-local
-
Bangun eksperimen pembelajaran
-
Buat circuit
-
Siapkan simulasi lokal
-
Jalankan programnya
-
Analisis datanya
Circuit di bawah ini disimulasikan secara lokal, jadi panduan ini tidak butuh kredensial IBM Quantum®. Kalau mau menjalankannya di perangkat asli:
-
Langkah 1: ganti
FakeMarrakeshdengan backend asli. -
Langkah 5: berikan backend itu sebagai mode executor, dan hapus opsi simulator.
1. Definisikan gate set pada sebuah ring qubit
Bangun QiskitGateSet dari Target sebuah backend dan subset qubit-nya — di sini sebuah ring dua belas qubit dari FakeMarrakesh — lalu tambahkan satu gate ke dalamnya: sebuah layer berisi enam gate CZ yang mencakup ring tersebut. Secara default, gate set diinisialisasi dengan gate persiapan P dan gate pengukuran M.
from qiskit_ibm_runtime.fake_provider import FakeMarrakesh
from qiskit_noise_learning.gate_sets import QiskitGateSet
backend = FakeMarrakesh()
qubit_subset = [*range(25, 30), *range(37, 39), *range(45, 50)]
cz_pairs = [(25, 26), (27, 28), (29, 38), (37, 45), (46, 47), (48, 49)]
gate_set = QiskitGateSet(backend.num_qubits, target=backend.target, qubit_subset=qubit_subset)
with gate_set.build_new_gate("cz_gate", latex_str=r"\mathrm{CZ}") as builder:
for pair in cz_pairs:
builder.circuit.cz(*pair)
list(gate_set)
['M', 'P', 'cz_gate']
from qiskit_ibm_runtime import QiskitRuntimeService
backend = QiskitRuntimeService().backend("ibm_marrakesh")
Panggil draw() untuk melihat gate pada topologi perangkat: ring qubit di dalam gate set, dan pasangan mana saja di antaranya yang dientangle oleh gate tersebut.
gate_set.draw()
2. Pilih model Pauli-Lindblad 2-local
Tentukan generator Pauli-Lindblad mana saja yang boleh dimiliki noise dengan PauliLindbladModel. Bangun himpunan generator itu dari konektivitas gate set dengan k_local() — di sini setiap Pauli 2-local pada pasangan qubit terhubung dari gate unitary, dan Pauli single-qubit untuk persiapan dan pengukuran.
from qiskit_noise_learning.models import PauliLindbladModel
model = PauliLindbladModel.k_local(gate_set, gate_k={"cz_gate": 2, "M": 1, "P": 1})
Tampilkan jumlah parameter yang belum diketahui untuk model noise dari setiap gate.
{name: len(generators) for name, generators in model.generators.items()}
{'M': 12, 'P': 12, 'cz_gate': 144}
3. Bangun eksperimen pembelajaran
Susun sebuah Experiment dengan menggabungkan tahap-tahap builder. Setiap tahap membaca apa yang ditulis tahap sebelumnya, jadi urutan itu penting:
from qiskit_noise_learning.experiment_builder import (
BindFragmentDepths,
CompleteSequences,
EvenDepthVanillaPaths,
Experiment,
GenerateInstructionSequences,
IdentifyRelations,
MergeInstructionSequences,
SPAMPaths,
VanillaInstructionSequences,
)
experiment_builder = (
# Add standard vanilla learning paths and instruction sequences, and identify relations
EvenDepthVanillaPaths()
+ VanillaInstructionSequences()
+ IdentifyRelations()
# Add paths for learning SPAM, then generate and merge instruction sequences for measuring them
+ SPAMPaths()
+ GenerateInstructionSequences()
+ MergeInstructionSequences()
# Finalize by completing the instruction sequences and setting experiment depths
+ CompleteSequences()
+ BindFragmentDepths([2, 16, 32, 64])
)
experiment = experiment_builder.run(
Experiment(fidelity_model=model, shots=20, randomizations=50)
)
print(f"Number of paths: {len(experiment.paths)}")
print(f"Number of instruction sequences: {len(experiment.instruction_sequences)}")
Number of paths: 156
Number of instruction sequences: 37
Amati rank design matrix:
print(f"Design matrix rank: {experiment.design_matrix.rank}")
Design matrix rank: 120
4. Buat circuit
Kompilasi eksperimen dengan ExecutorCircuitGenerator, yang menghasilkan sebuah QuantumProgram — satu template circuit berparameter untuk setiap kedalaman fragmen.
from qiskit_noise_learning.circuit_generator import ExecutorCircuitGenerator
circuit_generator = ExecutorCircuitGenerator(gate_set)
quantum_program = circuit_generator.generate(experiment)
print(f"Number of template circuits: {len(quantum_program.items)}")
Number of template circuits: 5
Gambar sebuah template circuit untuk diperiksa.
quantum_program.items[0].circuit.draw("mpl", idle_wires=False, fold=False)
5. Siapkan simulasi lokal
Untuk mendefinisikan model noise bagi simulasi, kita memakai generator yang sudah ada di model dengan rate acak untuk membangun sebuah PauliLindbladMap.
import numpy as np
from qiskit.quantum_info import PauliLindbladMap
rng = np.random.default_rng(1234)
true_maps = {
name: PauliLindbladMap.from_terms(
[
PauliLindbladMap.GeneratorTerm(rate, generator)
for generator, rate in zip(generators, rng.uniform(2e-4, 1.5e-3, len(generators)))
]
)
for name, generators in model.generators.items()
if name != "P"
}
{name: noise_map.num_qubits for name, noise_map in true_maps.items()}
{'M': 156, 'cz_gate': 156}
Map-map itu selebar perangkat, karena model dinyatakan dalam pengindeksan qubit backend, padahal simulator menginginkan setiap map selebar gate yang dikenainya, dengan indeks Pauli berjalan di atas qubit gate tersebut dalam urutan fisik menaik. Persempit dengan keep_qubits(), yang men-trace out semua yang ada di luar ring:
noise_dict = {
name: noise_map.keep_qubits(qubit_subset) for name, noise_map in true_maps.items()
}
{name: noise_map.num_qubits for name, noise_map in noise_dict.items()}
{'M': 12, 'cz_gate': 12}
Simulator menamai noise sebuah layer berdasarkan instruksi box tempat layer itu dibangun, yang dikembalikan oleh to_instruction() untuk gate mana pun di gate set. Pasangkan setiap box dengan map-nya, gunakan metode simulasi stabilizer, dan atur seed_simulator agar data hasil simulasi bisa direproduksi:
from qiskit_aer import AerSimulator
from qiskit_ibm_runtime import Executor
executor = Executor(
mode=AerSimulator(method="stabilizer"),
options={
"simulator": {
"layer_noise_model": [
(gate_set[name].to_instruction(), noise_map)
for name, noise_map in noise_dict.items()
],
"seed_simulator": 42,
}
},
)
executor = Executor(mode=backend)
6. Jalankan programnya
Jalankan programnya, lalu format hasilnya dengan collect(), untuk menghasilkan sebuah Fit — wadah yang dibaca dan ditulis oleh tahap-tahap analisis.
Langkah ini sama saja, entah executor diarahkan ke simulator atau ke perangkat asli.
job = executor.run(quantum_program)
fit = circuit_generator.collect(job.result())
7. Analisis datanya
Bangun pipeline analisis seputar fitting least squares nonnegatif untuk model tersebut.
from qiskit_noise_learning.analysis import (
ComputeObservables, # computes observables from raw data
CurveFitObservables, # performs exponential fitting
LeastSquaresSolve, # solves model with (nonnegative) least squares
)
analyzer = ComputeObservables() + CurveFitObservables() + LeastSquaresSolve()
fit = analyzer.run(fit)
/opt/hostedtoolcache/Python/3.15.1/x64/lib/python3.15/site-packages/qiskit_noise_learning/analysis/model_solve.py:250: UserWarning: 7 of 156 row(s) of the linear system have a non-positive or non-finite uncertainty, so they carry no usable statistical weight. Positions in LinearSystemData.row_labels: 144, 145, 148, 149, 151, 152, 154.
system = LinearSystemData.from_fit(fit)
Plot rata-rata observable hasil ukur terhadap eksponensial hasil fit-nya, satu subplot per pasangan CZ, untuk melihat apakah peluruhan yang di-fit itu memang eksponensial.
fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
exponential_fit=True,
)
Ganti exponential_fit dengan model_prediction untuk membandingkan data yang sama dengan peluruhan yang tersirat dari rate hasil penyelesaian non-negative least squares.
fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
model_prediction=True,
)
