Přeskočit na hlavní obsah
Tento projekt je v betě. Našel jsi chybu? Otevřít issue na GitHubu. Máš otázku nebo nápad? Zeptej se v Discussions — rádi si poslechneme tvou zpětnou vazbu!
Jaká je kvalita překladu na této stránce?

Sestavení učicího experimentu

Tento tutoriál ukazuje, jak od základu sestavit standardní učicí experiment a použít ho k naučení modelu ze simulovaných zašuměných dat.

  1. Definuj sadu hradel na kruhu qubitů

  2. Zvol 2-lokální Pauli-Lindbladův model

  3. Sestav učicí experiment

  4. Vygeneruj obvody

  5. Nastav lokální simulaci

  6. Spusť program

  7. Analyzuj data

Spuštění na skutečném hardwaru

Níže uvedené obvody se simulují lokálně, takže tento postup nevyžaduje žádné přihlašovací údaje k IBM Quantum®. Chceš-li ho místo toho spustit na skutečném zařízení:

  • Krok 1: nahraď FakeMarrakesh skutečným backendem.

  • Krok 5: předej tento backend jako režim executoru a vynech možnosti simulátoru.

1. Definuj sadu hradel na kruhu qubitů​

Sestav QiskitGateSet z Target backendu a podmnožiny jeho qubitů — zde dvanáctiqubitového kruhu zařízení FakeMarrakesh — a pak do ní přidej jedno hradlo: vrstvu šesti hradel CZ, která pokrývají tento kruh. Ve výchozím nastavení je sada hradel inicializována s přípravným hradlem P a měřicím hradlem 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']
Spuštění na skutečném hardwaru
from qiskit_ibm_runtime import QiskitRuntimeService

backend = QiskitRuntimeService().backend("ibm_marrakesh")

Zavolej draw(), abys viděl hradlo na topologii zařízení: kruh qubitů v sadě hradel a které jejich páry hradlo provazuje.

gate_set.draw()

2. Zvol 2-lokální Pauli-Lindbladův model​

Pomocí PauliLindbladModel rozhodni, které Pauli-Lindbladovy generátory smí šum mít. Tuto množinu generátorů sestav z konektivity sady hradel pomocí k_local() — zde každý 2-lokální Pauliův operátor na propojených dvojicích qubitů unitárního hradla a jednoqubitové Pauliovy operátory pro přípravu a měření.

from qiskit_noise_learning.models import PauliLindbladModel

model = PauliLindbladModel.k_local(gate_set, gate_k={"cz_gate": 2, "M": 1, "P": 1})

Zobraz počet neznámých parametrů šumového modelu každého hradla.

{name: len(generators) for name, generators in model.generators.items()}
{'M': 12, 'P': 12, 'cz_gate': 144}

3. Sestav učicí experiment​

Sestav Experiment složením fází builderu. Každá fáze čte to, co zapsaly předchozí, takže na pořadí záleží:

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

Sleduj hodnost návrhové matice:

print(f"Design matrix rank: {experiment.design_matrix.rank}")
Design matrix rank: 120

4. Vygeneruj obvody​

Zkompiluj experiment pomocí ExecutorCircuitGenerator a vygeneruj QuantumProgram — jeden parametrizovaný šablonový obvod pro každou hloubku fragmentu.

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

Nakresli šablonový obvod a prohlédni si ho.

quantum_program.items[0].circuit.draw("mpl", idle_wires=False, fold=False)

../_images/4088c7e98baeb5b56925c6c1f276159582c5f7040fbba76de438b919210bcc5f.png

5. Nastav lokální simulaci​

K definici šumového modelu pro simulaci použijeme generátory, které už v modelu jsou, s náhodnými četnostmi a sestavíme z nich 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}

Tyto mapy jsou tak široké jako zařízení, protože model je vyjádřen v indexování qubitů backend, ale simulátor chce, aby každá mapa byla tak široká jako hradlo, na které se aplikuje, s indexy Pauliových operátorů probíhajícími přes qubity hradla ve vzestupném fyzickém pořadí. Zúž je pomocí keep_qubits(), která vysleduje (trace out) vše mimo kruh:

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}

Simulátor pojmenovává šum vrstvy podle instrukce boxu, ze které byla vrstva sestavena; tu vrací to_instruction() pro libovolné hradlo v sadě hradel. Spáruj každý box s jeho mapou, použij metodu simulace stabilizátorů a nastav seed_simulator, aby byla simulovaná data reprodukovatelná:

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,
}
},
)
Spuštění na skutečném hardwaru
executor = Executor(mode=backend)

6. Spusť program​

Spusť program a poté naformátuj výsledky pomocí collect(), čímž vznikne Fit — kontejner, ze kterého analytické fáze čtou a do kterého zapisují.

Tento krok je stejný bez ohledu na to, zda executor míří na simulátor, nebo na skutečné zařízení.

job = executor.run(quantum_program)
fit = circuit_generator.collect(job.result())

7. Analyzuj data​

Sestav analytický pipeline kolem fitování modelu nezápornými nejmenšími čtverci.

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)

Vykresli naměřené střední hodnoty observabilů proti jejich nafitovaným exponenciálám, jeden podgraf na pár CZ, abys viděl, zda jsou fitované poklesy vůbec exponenciální.

fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
exponential_fit=True,
)

Zaměň exponential_fit za model_prediction, abys porovnal tatáž data s poklesy, které vyplývají z četností získaných řešením nezáporných nejmenších čtverců.

fit.plot_qubit_pair_decays(
pairs=cz_pairs,
observable_type="means",
model_prediction=True,
)