執行並解碼邏輯程式設計程式

使用 Microsoft Quantum Development Kit(QDK)將邏輯 Q# 或 OpenQASM 程式編譯為 Quantum Intermediate Representation(QIR),然後使用 qdk.simulation.run_qir 讓程式透過 qodec 執行。 建立雜訊模型,然後選擇內建的症候群解碼器或選用的 deq 電路級解碼器。

Prerequisites

開始前請完成以下任務:

範例中使用Q#一個名為C4、包含protocol程式碼指令的qodec。 若要建立,請參見 「開發並驗證 QEC 協議」。

import qodec
from qdk import ec

c4 = qodec.Code(
    "C4",
    stabilizers=["X_0 X_1 X_2 X_3", "Z_0 Z_1 Z_2 Z_3"],
    x=["X_0 X_1", "X_0 X_2"],
    z=["Z_0 Z_2", "Z_0 Z_1"],
)

protocol = ec.build_qodec(
    c4,
    strategy="bare-css/v1",
    strict=False,
)

report = ec.audit(protocol)
if report.errors or report.warnings:
    raise ValueError(str(report))

在執行前先審核 qodec 。 執行階段信任 qodec 的檢查、讀值、旗標和影格方程式,因此無效宣告可能導致錯誤的邏輯結果或解碼器故障。

此工作流程使用 qdk.simulation.run_qir 搭配 qodec。 該 qodec 工具使用獨立的 StimPython 套件 來解析 Stim 格式的 gadget 電路。 它不會呼叫 qdk.stim.run。 在 LinuxArm64 或 WindowsArm64 上,從原始碼安裝 Stim,然後在執行帶有 Jupyter-format 電路的 Python 之前重新啟動 qodec 或 Stim 核心。

將qodec呼叫與QIR指令匹配

將 QIR 程式中的每個量子呼叫與 qodec 的最上層指令集中的一項指令相匹配。 指令助記符必須與被叫者名稱完全一致 QIR 。

下表顯示範例對應:

來源呼叫 必填 qodec 助記鍵
Q# X(q) 或 OpenQASMx q; __quantum__qis__x__body
Q# H(q) 或 OpenQASMh q; __quantum__qis__h__body
Q# CNOT(a, b) 或 OpenQASMcx a, b; __quantum__qis__cx__body
Q# Adjoint S(q) 或 OpenQASMsdg q; __quantum__qis__s__adj
Q# M(q) 或 OpenQASMc = measure q; __quantum__qis__m__body
Q# 內建操作 Foo Foo
OpenQASM 內在閘門或稱為 def 的閘門 foo foo

QIR 參數依序綁定於 qodec 指令元素:

  1. 量子位元指標參數會綁定到區塊運算元。
  2. 標量引數會繫結至指令參數。
  3. 結果指標參數會接收指令結果及任何回傳的旗標。

如果量子調用與頂層指令集中的指令不匹配,編譯器會引發錯誤。

在 Q# 中宣告邏輯指令

qodec 由 C4 程式碼建構,並提供如 prepare_z_all、measure_z_all、syndrome 和 cx_all 等自訂指令。 宣告名稱相同的 Q# 內在操作。

使用自適應目標設定檔初始化 Q#,因為自訂測量操作需要。

from qdk import TargetProfile, qsharp

qsharp.init(target_profile=TargetProfile.Adaptive_RI)

將 C4 指令宣告為 Q# 作業。

qsharp.eval("""
@Measurement()
operation prepare_z_all(block : Qubit) : Result { body intrinsic; }

@Measurement()
operation prepare_x_all(block : Qubit) : Result { body intrinsic; }

@Measurement()
operation measure_z_all(block : Qubit) : (Result, Result) { body intrinsic; }

@Measurement()
operation measure_x_all(block : Qubit) : (Result, Result) { body intrinsic; }

operation cx_all(control : Qubit, target : Qubit) : Unit { body intrinsic; }
operation syndrome(block : Qubit) : Unit { body intrinsic; }
""")

在此程式中,Q#Qubit 各自代表一個編碼區塊。 該 C4 區塊有兩個邏輯量子位元,因此每次測量操作會回傳兩個邏輯結果。 每個準備操作回傳一個拒絕標記。

編譯一個邏輯Q#實驗

定義狀態準備與測量(SPAM)實驗。

qsharp.eval("""
operation TestSpamZ() : (Result[], Result[]) {
    use block = Qubit();
    let reject = prepare_z_all(block);
    let (left, right) = measure_z_all(block);
    ([reject], [left, right])
}
""")

將 TestSpamZ 作業編譯為 QIR。

qir = str(qsharp.compile("TestSpamZ()"))

QIR 會保留對 prepare_z_all 和 measure_z_all 的呼叫。 當程式執行時,qodec 執行階段環境會將這些名稱與頂端指令集比對,並用其 gadget 替換每個邏輯呼叫。

使用內建解碼器執行

打電話run_qir並傳遞qodec。 若 decoder 為 None,則執行階段會使用內建的最小權重 Pauli 解碼器。

from qdk.simulation import run_qir

results = run_qir(
    qir,
    qodec=protocol,
    type="stabilizer",
    shots=100,
    seed=42,
)

print(results[:5])

要執行 qodec,請使用以下模擬器選項:

type 數值 Behavior
None 或 "stabilizer" 使用穩定器後端
"cpu" 對支援的程式使用狀態向量後端
"gpu" 不支援搭配 qodec

執行時會在每個程式量子位元首次使用前就先做準備,除非第一條指令建立其區塊。 準備指令有輸出區塊、無輸入區塊,以及一個使邏輯 Z穩定的動作。

單量子位元 Pauli 解碼器的修正與 qodec 影格更新使用無 Pauli 噪音的影格,而不是有雜訊的物理閘。

設定模擬器雜訊

請定義模擬器操作的雜訊,而非 qodec 指令名稱。 執行時會將底層指令轉換成一個或多個模擬器操作,因此這些操作會適用噪音設定。

C4逐步解說使用以下映射:

底層指令 模擬器運作 NoiseConfig 欄位
R 準備好或重置為 Z+ mresetz
H 哈達馬爾 h
CX Controlled X cx
M Z-基底測量 mresetz

建立一個簡單的1%雜訊模型:

from qdk.simulation import NoiseConfig

noise = NoiseConfig()
for gate in (noise.h, noise.cx):
    gate.set_depolarizing(0.01)
noise.mresetz.x = 0.01

執行含雜訊的實驗:

results = run_qir(
    qir,
    qodec=protocol,
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

噪聲mresetz在測量或準備後作用於量子位元。 它不會翻轉模擬器已經記錄的測量結果位元。 要研究記錄的位元翻轉,可以使用 qodec 讀出故障模型和 gadget 分析。

控制拍攝失敗

用 on_shot_failure 來選擇當 qodec 旗標、解碼器或讀出未產生可接受的 shot 時,執行階段的反應。

Value Behavior
"discard" 將失敗的鏡頭從退回清單中刪除。 此值為預設值。
"raise" 第一次嘗試失敗時就停止。
"retry" 重新開始失敗的射擊,最多可以再嘗試 max_retries 次。

在此 "discard" 策略中,參數 shots 會計算嘗試次數,因此傳回的清單項目數可能少於 shots。

只有當邏輯程式沒有收到該標記時,旗標才會觸發該射擊策略。 若操作 Q#@Measurement() 為旗標回傳額外的 Result,程式會接收旗標並決定是否拒絕該射擊。

在範例 TestSpamZ 中,程式回傳第一個陣列中的準備旗標。 所以設定 on_shot_failure="discard" 不會移除回傳旗標為 One 的列。

選擇解碼器

要選擇錯誤的解碼方式,請使用 decoder 參數為每個編碼層傳遞解碼器準備可呼叫物件。

QDK 具有下列解碼器:

譯碼器 用它來做
預設校驗子解碼器 從綜合徵證據推斷最小權重 Pauli 修正。 請使用 decoder=None。
幀解碼器 追蹤無噪音的影格,卻不推斷實體故障。 請使用 prepare_frame_decoder。
deq 解碼器 使用 deq 解碼電路層級故障模型。 請使用 prepare_deq_decoder。

使用預設 deq 配置

安裝 deq 和 deq-runtime,然後傳遞 prepare_deq_decoder。

from qdk.simulation.decoders import prepare_deq_decoder

results = run_qir(
    qir,
    qodec=protocol,
    decoder=prepare_deq_decoder,
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

預設情況下,該 deq 介面卡使用中繼信念傳播與視窗協調器。 要更改這些設定,請使用執行時工廠。

配置一個單體式 deq 執行時

若要直接選擇 deq 設定,請將執行時工廠傳給 prepare_deq_decoder。

from functools import partial
from deq.runtime import Runtime
from qdk.simulation import decoders


def make_runtime(seed: int) -> Runtime:
    return Runtime(
        decoder="black-box-relay-bp",
        decoder_config={"parallel": 1, "seed": seed},
        coordinator="monolithic",
        controller="jit",
    )


results = run_qir(
    qir,
    qodec=protocol,
    decoder=partial(
        decoders.prepare_deq_decoder,
        runtime_factory=make_runtime,
    ),
    noise=noise,
    type="stabilizer",
    shots=1000,
    seed=42,
    on_shot_failure="discard",
)

每次工廠函式呼叫時都要傳回新的 Runtime。 QDK 會啟動並關閉每個執行階段。

Note

deq轉接器需要:

  • 一個已編碼的層
  • 一個與測量無關的Clifford執行軌跡
  • 穩定器後端
  • 一個沒有量子位元損失的雜訊模型

deq 轉接器不支援重試政策。 不支援的節目串流會產生錯誤,而不會退回到其他解碼器。

拒絕低信賴度 deq 結果

deq 配接器會為每個邏輯讀數回傳一個分數。 分數越低,表示對所選修正的偏好越強。 這些分數並不是經過校正的失效機率。

要拒絕低信心結果,請在準備解碼器時傳入 max_readout_score,如下範例所示:

from functools import partial
from qdk.simulation import decoders

scored_decoder = partial(
    decoders.prepare_deq_decoder,
    max_readout_score=0.2,
)

results = run_qir(
    qir,
    qodec=protocol,
    decoder=scored_decoder,
    noise=noise,
    type="stabilizer",
    shots=1000,
    on_shot_failure="discard",
)

只有當每個回傳的邏輯讀數分數都在或低於閾值時,執行階段才會接受 shot。 這個門檻不適用於原始旗標或未使用的中間讀數。

基於分數的剔除可以降低被接受的投籃的邏輯錯誤率。 但同時也減少了被接受的鏡頭數量,並增加了解碼工作。

編譯 OpenQASM 程式

標準OpenQASM運算使用與標準QIR運算相同的Q#助記法規則。

from qdk import TargetProfile, openqasm

source = """
OPENQASM 3.0;
include "stdgates.inc";
qubit q;
bit c;
x q;
c = measure q;
"""

qir = openqasm.compile(
    source,
    target_profile=TargetProfile.Adaptive_RI,
)

print(qir)

要透過 qodec 執行此程式,請確保 qodec 的頂端指令集具有 __quantum__qis__x__body 和 __quantum__qis__m__body,且區塊運算元相容且有一個測量結果。

OpenQASM一個名為 foo 的內在函式或子程式使用助記符 foo。 量子位元參數會繫結至區塊操作數。 float、int 與 bool 引數會依宣告順序繫結至指令參數。

OpenQASM 對 qodec 通話有以下限制:

  • 自訂內建函式無法回傳 QIRResult. 要得到一個測量結果,請使用標準 measure 陳述式。
  • OpenQASM 程式無法執行自訂測量、從一次呼叫中接收多個結果,或接收回傳的標記。 在這種情況下,請使用 Q#@Measurement() 運算。
  • 執行階段控制程式無法接收的任何旗標 OpenQASM,這些旗標可能會使一次拍攝遭到拒絕。

如需詳細的對應範例,請參閱以下 QDK 筆記本:

審查要求與限制

在進行大型實驗前,請先檢視這些要求、限制與結果差異。

要求:

  • 每個 QIR 量子呼叫都必須對應到頂層 qodec 指令。
  • 執行前請審核該協定。 qodec執行時信任你寫的方程式,不會檢查它們。

Limitations:

  • GPU 模擬不支援 qodec 執行。
  • 預設的小工具故障集合會呈指數成長,因此精確距離搜尋可能需要很長時間。
  • deq 和 Stim 套件有平台限制。 欲了解更多資訊,請參閱 安裝 QDK 以進行錯誤修正。

結果差異:

  • 精確的輸出數量會因解碼器而異。
  • 丟棄與重試政策可能會改變回傳的結果分布。

若要完整體驗含雜訊掃描、deq 解碼及基於置信度的拒判的 Q# 實驗,請參閱 QEC 協議攻略。