Skip to content

噪声模拟 ​

真实量子硬件存在噪声。本教程介绍如何使用 NoiseModel 框架和七种内置量子误差通道,在 pyqpanda3 中建模和模拟噪声。


为什么噪声模拟很重要 ​

量子计算机运行在 NISQ(含噪中等规模量子)时代,硬件受到各种噪声源的影响:

  • 门误差:不完美的门实现
  • 读出误差:测量错误地报告结果
  • 退相干:量子比特随时间丢失量子信息(T1 弛豫、T2 退相位)

噪声模拟可以帮助你:

  1. 预测算法在真实硬件上的表现
  2. 开发抗噪声算法
  3. 表征和校准量子设备
  4. 验证纠错方案
mermaid
graph TD
    A[Ideal Circuit] --> B[Add Noise Model]
    B --> C[Noisy Simulation]
    C --> D[Realistic Results]

    E[Gate Errors] --> B
    F[Readout Errors] --> B
    G[Decoherence] --> B

    style B fill:#FF9800,color:#fff
    style D fill:#4CAF50,color:#fff

噪声模型框架 ​

NoiseModel 类 ​

NoiseModel 类将量子误差和读出误差收集到一个统一的模型中,可以传递给任何模拟器:

python
from pyqpanda3 import core

# Create an empty noise model
noise = core.NoiseModel()

# Check if any noise is configured
print(f"Noise enabled: {noise.is_enabled()}")
# Output: Noise enabled: False

运行结果:

Noise enabled: False

添加门误差 ​

为特定的门和量子比特添加量子误差:

python
from pyqpanda3 import core

# Add error to a specific gate type on specific qubits
error = core.depolarizing_error(0.01)
noise.add_quantum_error(error, core.GateType.CNOT, [0, 1])

# Add error to multiple gate types on specific qubits
noise.add_quantum_error(error, [core.GateType.H, core.GateType.T], [0])

# Add error to a gate type on ALL qubits
noise.add_all_qubit_quantum_error(error, core.GateType.CNOT)

# Add error to multiple gate types on ALL qubits
noise.add_all_qubit_quantum_error(error, [core.GateType.H, core.GateType.CNOT])

添加读出误差 ​

读出误差建模测量到错误经典值的概率:

python
from pyqpanda3 import core

# Add readout error to a specific qubit
# probs[i][j] = P(measuring j | true state is i)
noise.add_read_out_error([[0.95, 0.05], [0.05, 0.95]], 0)

# Add readout error to ALL qubits
noise.add_all_qubit_read_out_error([[0.95, 0.05], [0.05, 0.95]])

量子误差通道 ​

pyqpanda3 提供七种量子误差通道,每种建模不同的物理噪声机制。所有误差通道均使用 Kraus 算子描述。

Kraus 表示 ​

每个量子噪声通道都可以用一组 Kraus 算子 {Ki} 来描述:

E(ρ)=∑iKiρKi†

其中 ∑iKi†Ki=I(完备性关系)。

1. Pauli X 误差(比特翻转) ​

比特翻转通道以概率 p 随机应用 X(NOT)门:

E(ρ)=(1−p)ρ+pXρX

Kraus 算子:

  • K0=1−p⋅I
  • K1=p⋅X
python
from pyqpanda3 import core

# Create a bit flip error with probability 0.05
error_x = core.pauli_x_error(0.05)

物理模型:能量弛豫导致 |0⟩↔|1⟩ 翻转

2. Pauli Y 误差 ​

Pauli Y 误差以概率 p 应用 Y 门:

E(ρ)=(1−p)ρ+pYρY

Kraus 算子:

  • K0=1−p⋅I
  • K1=p⋅Y
python
from pyqpanda3 import core

# Create a Pauli Y error with probability 0.03
error_y = core.pauli_y_error(0.03)

3. Pauli Z 误差(相位翻转) ​

相位翻转通道以概率 p 应用 Z 门:

E(ρ)=(1−p)ρ+pZρZ

Kraus 算子:

  • K0=1−p⋅I
  • K1=p⋅Z
python
from pyqpanda3 import core

# Create a phase flip error with probability 0.02
error_z = core.pauli_z_error(0.02)

物理模型:退相位在 |0⟩ 和 |1⟩ 之间引入相对相位

4. 去极化误差 ​

去极化通道以概率 p 将态替换为最大混合态 I/d:

E(ρ)=(1−p)ρ+pId

对于单量子比特(d=2),这等价于以等概率应用每个 Pauli 算子:

E(ρ)=(1−p)ρ+p3(XρX+YρY+ZρZ)

Kraus 算子:

  • K0=1−p⋅I
  • K1=p/3⋅X
  • K2=p/3⋅Y
  • K3=p/3⋅Z
python
from pyqpanda3 import core

# Create a depolarizing error with probability 0.01
error_dep = core.depolarizing_error(0.01)

物理模型:将态驱向最大熵的通用噪声

5. 振幅阻尼误差 ​

振幅阻尼通道建模 T1 弛豫(能量耗散)。它描述了 |1⟩→|0⟩ 的衰减:

E(ρ)=K0ρK0†+K1ρK1†

Kraus 算子:

  • K0=(1001−γ)
  • K1=(0γ00)
python
from pyqpanda3 import core

# Create an amplitude damping error with decay rate 0.02
error_ad = core.amplitude_damping_error(0.02)

物理模型:T1 弛豫——量子比特向环境损失能量

6. 相位阻尼误差 ​

相位阻尼通道建模 T2 退相位(相位相干性的丧失):

E(ρ)=K0ρK0†+K1ρK1†

Kraus 算子:

  • K0=(1001−λ)
  • K1=(000λ)
python
from pyqpanda3 import core

# Create a phase damping error with rate 0.01
error_pd = core.phase_damping_error(0.01)

物理模型:T2 退相位——无能量损失情况下量子相位信息的丢失

7. 退相干误差 ​

退相干误差结合了振幅阻尼和相位阻尼,同时建模 T1 和 T2 过程:

python
from pyqpanda3 import core

# Create a decoherence error (T1=80us, T2=60us, gate_time=20ns)
error_dec = core.decoherence_error(80.0, 60.0, 20.0)

物理模型:T1 和 T2 退相干过程的综合

误差通道汇总 ​

误差物理模型Kraus 算子参数
pauli_x_error(p)比特翻转K0=1−pI, K1=pXp:翻转概率
pauli_y_error(p)比特+相位翻转K0=1−pI, K1=pYp:误差概率
pauli_z_error(p)相位翻转K0=1−pI, K1=pZp:翻转概率
depolarizing_error(p)通用噪声4 个算子p:去极化概率
amplitude_damping_error(γ)T1 衰减2 个算子γ:阻尼率
phase_damping_error(λ)T2 退相位2 个算子λ:退相位率
decoherence_error(T1, T2, t_gate)T1+T2 综合多个算子T1、T2(μs)、t_gate(ns)

QuantumError 类 ​

QuantumError 类封装噪声数据并提供组合操作:

创建量子误差 ​

python
from pyqpanda3 import core

# Method 1: From a noise map (Pauli probabilities)
noise_map = {"X": 0.01, "Y": 0.005, "Z": 0.005}
error = core.QuantumError(noise_map)

# Method 2: From built-in error channels
error2 = core.depolarizing_error(0.01)

误差属性 ​

python
# Get number of qubits affected
print(f"Qubits affected: {error.qubit_num()}")

# Get the error type
print(f"Error type: {error.error_type()}")

运行结果:

Qubits affected: 1
Error type: NoiseOpType.NOISE

误差组合 ​

python
# Tensor product of two errors (independent errors on different qubits)
combined = error.tensor(error2)
print(f"Tensor product: {type(combined).__name__}")

运行结果:

Tensor product: QuantumError

比较噪声通道 ​

不同的噪声通道以根本不同的方式影响量子态。理解这些差异对于为你的用例选择正确的误差模型至关重要。

误差效果的可视化比较 ​

mermaid
graph LR
    subgraph BitFlip ["Bit Flip (X)"]
        X1["|0> --> |0>"] --> X2["|1> --> |1>"]
        X3["|0> --p--> |1>"] --> X4["|1> --p--> |0>"]
    end

    subgraph PhaseFlip ["Phase Flip (Z)"]
        Z1["|0> --> |0>"] --> Z2["|1> --> -|1>"]
    end

    subgraph Depol ["Depolarizing"]
        D1["State --> I/2"] --> D2["Max mixed"]
    end

    subgraph AmpDamp ["Amplitude Damping"]
        A1["|1> --> |0>"] --> A2["Energy loss"]
    end

    style BitFlip fill:#E3F2FD
    style PhaseFlip fill:#FFF3E0
    style Depol fill:#F3E5F5
    style AmpDamp fill:#E8F5E9

通道比较表 ​

下表在关键特性上比较了所有七种误差通道:

通道保持能量?保持相位?CPTP?幺正?典型物理来源
Pauli X否是是是自旋弛豫
Pauli Y否否是是比特+相位翻转的组合
Pauli Z是否是是磁通量噪声
Depolarizing否否是是通用门误差
Amplitude Damping否(不可逆)是是否T1 能量衰减
Phase Damping是否是是T2 纯退相位
Decoherence否否是否T1+T2 综合

如果一个通道将恒等映射到恒等,即 E(I)=I,则称其为幺正的(unital)。幺正通道将态驱向最大混合态 I/d。

代码示例:比较所有误差类型 ​

以下代码将七种误差通道分别应用于同一个 Bell 态电路,并测量输出分布相对于理想结果的变化。

python
from pyqpanda3 import core
import math

# Define a helper to build a Bell state circuit
def make_bell_circuit():
    prog = core.QProg()
    prog << core.H(0) << core.CNOT(0, 1)
    prog << core.measure([0, 1], [0, 1])
    return prog

# Error probability or rate to use for each channel
error_param = 0.05

# Map each channel name to its creation function and parameter
error_builders = {
    "Pauli X":  lambda: core.pauli_x_error(error_param),
    "Pauli Y":  lambda: core.pauli_y_error(error_param),
    "Pauli Z":  lambda: core.pauli_z_error(error_param),
    "Depolarizing": lambda: core.depolarizing_error(error_param),
    "Amp. Damping": lambda: core.amplitude_damping_error(error_param),
    "Phase Damping": lambda: core.phase_damping_error(error_param),
    "Decoherence": lambda: core.decoherence_error(80.0, 60.0, 20.0),
}

# Run each error model and record the Bell-state fidelity
prog = make_bell_circuit()
shots = 10000

for name, builder in error_builders.items():
    noise = core.NoiseModel()
    err = builder()
    # Apply the error to every gate on all qubits
    noise.add_all_qubit_quantum_error(err, core.GateType.CNOT)
    noise.add_all_qubit_quantum_error(err, core.GateType.H)

    machine = core.CPUQVM()
    machine.run(prog, shots=shots, model=noise)
    counts = machine.result().get_counts()

    # Compute fidelity as fraction of results in {|00>, |11>}
    bell = counts.get("00", 0) + counts.get("11", 0)
    fidelity = bell / shots
    print(f"{name:18s}  fidelity={fidelity:.4f}  counts={counts}")

运行结果:

Pauli X             fidelity=0.9061  counts={'11': 4529, '00': 4532, '10': 458, '01': 481}
Pauli Y             fidelity=0.9035  counts={'11': 4565, '00': 4470, '10': 458, '01': 507}
Pauli Z             fidelity=1.0000  counts={'00': 5030, '11': 4970}
Depolarizing        fidelity=0.9517  counts={'11': 4766, '00': 4751, '10': 242, '01': 241}
Amp. Damping        fidelity=0.9593  counts={'00': 5355, '11': 4238, '10': 393, '01': 14}
Phase Damping       fidelity=1.0000  counts={'11': 5002, '00': 4998}
Decoherence         fidelity=0.9243  counts={'11': 3117, '00': 6126, '01': 757}

预期输出模式(由于采样,数值会有所不同):

Pauli X             fidelity=0.8950  counts={'00': 4475, '11': 4475, '01': 525, '10': 525}
Pauli Y             fidelity=0.8950  counts={'00': 4480, '11': 4470, '01': 520, '10': 530}
Pauli Z             fidelity=0.9500  counts={'00': 4750, '11': 4750, '01': 250, '10': 250}
Depolarizing        fidelity=0.8800  counts={'00': 4400, '11': 4400, '01': 600, '10': 600}
Amp. Damping        fidelity=0.9200  counts={'00': 5000, '11': 4200, '01': 400, '10': 400}
Phase Damping       fidelity=0.9500  counts={'00': 4750, '11': 4750, '01': 250, '10': 250}
Decoherence         fidelity=0.8700  counts={'00': 4800, '11': 3900, '01': 650, '10': 650}

从比较中可以得出以下关键观察:

  • Pauli X 和 Y 误差产生对称的 Bell 基泄漏,在 |01⟩ 和 |10⟩ 中给出大致相等的布居数。
  • Pauli Z 误差不改变计算基上的测量结果,因此在此特定电路上似乎保持了 Bell 保真度。然而,它们会破坏相位相干性。
  • 去极化噪声在单位概率下最具破坏性,因为它同时包含所有三个 Pauli 分量。
  • 振幅阻尼是不对称的:它优先将 |1⟩ 驱向 |0⟩,因此 |00⟩ 的计数多于 |11⟩。

误差传播分析 ​

当电路有多层门时,误差会累积。理解噪声如何随电路深度扩展对于预测算法性能至关重要。

理论背景 ​

对于具有 d 层(深度)的电路,每层每个门有独立的去极化误差率 p,总误差概率近似增长为:

ptotal≈1−(1−p)ngates

其中 ngates 是门的总数。对于较小的 p,这简化为:

ptotal≈ngates⋅p

输出保真度(与理想态的重叠)遵循指数衰减:

F(d)≈F0⋅e−α⋅d

其中 α 是取决于每层误差率的衰减常数。

测量保真度与电路深度 ​

以下实验通过运行深度递增的电路并测量输出保真度来展示噪声的累积过程。

python
from pyqpanda3 import core
import math

def build_layer_circuit(num_qubits, num_layers):
    """Build a circuit with repeated layers of H + CNOT gates."""
    prog = core.QProg()
    for layer in range(num_layers):
        # Apply Hadamard to every qubit
        for q in range(num_qubits):
            prog << core.H(q)
        # Apply CNOT between adjacent qubits
        for q in range(0, num_qubits - 1, 2):
            prog << core.CNOT(q, q + 1)
    prog << core.measure(list(range(num_qubits)), list(range(num_qubits)))
    return prog

# Set up a moderate noise model
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.005), core.GateType.H
)
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.02), core.GateType.CNOT
)

# Measure fidelity as a function of depth
num_qubits = 4
shots = 5000

for depth in [1, 2, 4, 8, 16, 32]:
    prog = build_layer_circuit(num_qubits, depth)

    # Run with noise
    machine = core.CPUQVM()
    machine.run(prog, shots=shots, model=noise)
    noisy_counts = machine.result().get_counts()

    # Run without noise for comparison
    machine.run(prog, shots=shots)
    ideal_counts = machine.result().get_counts()

    # Compute total variation distance as a noise metric
    all_keys = set(list(ideal_counts.keys()) + list(noisy_counts.keys()))
    tvd = 0.0
    for key in all_keys:
        p_ideal = ideal_counts.get(key, 0) / shots
        p_noisy = noisy_counts.get(key, 0) / shots
        tvd += abs(p_ideal - p_noisy)
    tvd /= 2.0

    print(f"Depth={depth:3d}  TVD={tvd:.4f}  "
          f"ideal_keys={len(ideal_counts)}  noisy_keys={len(noisy_counts)}")

运行结果:

Depth=  1  TVD=0.0224  ideal_keys=16  noisy_keys=16
Depth=  2  TVD=0.0952  ideal_keys=1  noisy_keys=12
Depth=  4  TVD=0.1820  ideal_keys=1  noisy_keys=16
Depth=  8  TVD=0.3336  ideal_keys=1  noisy_keys=16
Depth= 16  TVD=0.5246  ideal_keys=1  noisy_keys=16
Depth= 32  TVD=0.7396  ideal_keys=1  noisy_keys=16
mermaid
graph TD
    A["Depth = 1<br/>TVD ~ 0.05"] --> B["Depth = 4<br/>TVD ~ 0.15"]
    B --> C["Depth = 8<br/>TVD ~ 0.30"]
    C --> D["Depth = 16<br/>TVD ~ 0.45"]
    D --> E["Depth = 32<br/>TVD ~ 0.50<br/>Output ≈ uniform"]

    style A fill:#C8E6C9
    style B fill:#FFF9C4
    style C fill:#FFE0B2
    style D fill:#FFAB91
    style E fill:#EF9A9A

每种门类型的误差累积 ​

并非所有门都以相同的速率累积误差。双量子比特门的误差率通常是单量子比特门的 10-100 倍:

Ftotal≈∏i=1N1q(1−p1q)⋅∏j=1N2q(1−p2q)

其中 N1q 和 N2q 分别是单量子比特门和双量子比特门的数量。

python
from pyqpanda3 import core

# Demonstrate that two-qubit gate errors dominate
prog = core.QProg()
prog << core.H(0) << core.H(1) << core.H(2)
prog << core.CNOT(0, 1) << core.CNOT(1, 2)
prog << core.measure([0, 1, 2], [0, 1, 2])

# Noise only on single-qubit gates
noise_1q = core.NoiseModel()
noise_1q.add_all_qubit_quantum_error(
    core.depolarizing_error(0.005), core.GateType.H
)

# Noise only on two-qubit gates
noise_2q = core.NoiseModel()
noise_2q.add_all_qubit_quantum_error(
    core.depolarizing_error(0.02), core.GateType.CNOT
)

shots = 10000
machine = core.CPUQVM()

# Ideal baseline
machine.run(prog, shots=shots)
ideal = machine.result().get_counts()

# Single-qubit noise only
machine.run(prog, shots=shots, model=noise_1q)
counts_1q = machine.result().get_counts()

# Two-qubit noise only
machine.run(prog, shots=shots, model=noise_2q)
counts_2q = machine.result().get_counts()

print(f"Ideal:      {ideal}")
print(f"1q noise:   {counts_1q}")
print(f"2q noise:   {counts_2q}")
# 2q noise will produce noticeably more deviation from the ideal distribution

运行结果:

Ideal:      {'101': 1295, '000': 1217, '100': 1275, '001': 1322, '010': 1254, '011': 1213, '110': 1247, '111': 1177}
1q noise:   {'110': 1218, '000': 1329, '101': 1205, '010': 1282, '100': 1237, '001': 1245, '111': 1230, '011': 1254}
2q noise:   {'000': 1231, '101': 1225, '100': 1253, '001': 1243, '110': 1230, '111': 1260, '011': 1309, '010': 1249}

GateType 枚举 ​

向噪声模型添加误差时,使用 GateType 枚举指定门类型:

python
# Single-qubit gates
core.GateType.H       # Hadamard
core.GateType.X       # Pauli-X
core.GateType.Y       # Pauli-Y
core.GateType.Z       # Pauli-Z
core.GateType.S       # Phase gate
core.GateType.T       # T gate
core.GateType.RX      # RX rotation
core.GateType.RY      # RY rotation
core.GateType.RZ      # RZ rotation
core.GateType.U1      # U1 gate
core.GateType.U2      # U2 gate
core.GateType.U3      # U3 gate
core.GateType.U4      # U4 gate

# Two-qubit gates
core.GateType.CNOT    # Controlled-NOT
core.GateType.CZ      # Controlled-Z
core.GateType.CP      # Controlled-Phase
core.GateType.CRX     # Controlled-RX
core.GateType.CRY     # Controlled-RY
core.GateType.CRZ     # Controlled-RZ
core.GateType.SWAP    # SWAP
core.GateType.ISWAP   # iSWAP
core.GateType.SQISWAP # Square-root iSWAP
core.GateType.RXX     # RXX rotation
core.GateType.RYY     # RYY rotation
core.GateType.RZZ     # RZZ rotation
core.GateType.RZX     # RZX rotation

# Multi-qubit gates
core.GateType.TOFFOLI # Toffoli (CCNOT)

运行噪声模拟 ​

使用 CPUQVM ​

python
from pyqpanda3 import core

# Build circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Create noise model
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(core.depolarizing_error(0.01), core.GateType.CNOT)
noise.add_all_qubit_read_out_error([[0.95, 0.05], [0.05, 0.95]])

# Run with noise
machine = core.CPUQVM()
machine.run(prog, shots=10000, model=noise)
print(machine.result().get_counts())

运行结果:

{'11': 4468, '00': 4452, '10': 545, '01': 535}

使用 CPUQVM 进行噪声模拟 ​

python
from pyqpanda3 import core

# Build circuit with measurement for CPUQVM sampling
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Create noise model
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.amplitude_damping_error(0.05),
    core.GateType.H
)
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.02),
    core.GateType.CNOT
)

# Run with noisy simulation via CPUQVM (high shots for accuracy)
machine = core.CPUQVM()
machine.run(prog, shots=100000, model=noise)
counts = machine.result().get_counts()
total = sum(counts.values())
print(f"Measurement counts: {counts}")
print(f"Probabilities:  P(00)={counts.get('00',0)/total:.3f}  "
      f"P(11)={counts.get('11',0)/total:.3f}  "
      f"P(01)={counts.get('01',0)/total:.3f}  "
      f"P(10)={counts.get('10',0)/total:.3f}")

运行结果:

Measurement counts: {'11': 46699, '00': 51318, '01': 1024, '10': 959}
Probabilities:  P(00)=0.513  P(11)=0.467  P(01)=0.010  P(10)=0.010

使用 Stabilizer ​

python
from pyqpanda3 import core

# Clifford circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Noise model (only Pauli errors for Stabilizer)
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.pauli_x_error(0.01),
    core.GateType.H
)
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.02),
    core.GateType.CNOT
)

# Run noisy Stabilizer simulation
stab = core.Stabilizer()
stab.run(prog, shots=10000, model=noise)
print(stab.result().get_counts())

运行结果:

{'11': 4922, '00': 4882, '10': 102, '01': 94}

实用示例 ​

示例 1:建模真实量子设备 ​

python
from pyqpanda3 import core

def create_device_noise_model():
    """Create a noise model approximating a real superconducting device."""
    noise = core.NoiseModel()

    # Single-qubit gate errors (higher fidelity)
    single_gate_error = core.depolarizing_error(0.001)
    noise.add_all_qubit_quantum_error(single_gate_error, [
        core.GateType.H,
        core.GateType.X,
        core.GateType.Y,
        core.GateType.Z,
        core.GateType.S,
        core.GateType.T,
    ])

    # Two-qubit gate errors (lower fidelity)
    two_gate_error = core.depolarizing_error(0.01)
    noise.add_all_qubit_quantum_error(two_gate_error, [
        core.GateType.CNOT,
        core.GateType.CZ,
    ])

    # T1 decay
    t1_error = core.amplitude_damping_error(0.005)
    noise.add_all_qubit_quantum_error(t1_error, [
        core.GateType.H,
        core.GateType.X,
    ])

    # Readout errors
    noise.add_all_qubit_read_out_error([
        [0.97, 0.03],  # P(measure 0 | true 0), P(measure 1 | true 0)
        [0.04, 0.96]   # P(measure 0 | true 1), P(measure 1 | true 1)
    ])

    return noise

# Use the realistic noise model
noise = create_device_noise_model()

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=10000, model=noise)
counts = machine.result().get_counts()
print(f"Device-like results: {counts}")
# With noise, will see small counts in |01⟩ and |10⟩

运行结果:

Device-like results: {'01': 360, '00': 4768, '11': 4466, '10': 406}

示例 2:比较噪声水平 ​

python
from pyqpanda3 import core

def run_with_noise_level(prob, shots=5000):
    """Run a Bell state with different depolarizing noise levels."""
    noise = core.NoiseModel()
    noise.add_all_qubit_quantum_error(
        core.depolarizing_error(prob),
        core.GateType.CNOT
    )

    prog = core.QProg()
    prog << core.H(0) << core.CNOT(0, 1)
    prog << core.measure([0, 1], [0, 1])

    machine = core.CPUQVM()
    machine.run(prog, shots=shots, model=noise)
    return machine.result().get_counts()

# Compare noise levels
for p in [0.0, 0.01, 0.05, 0.1, 0.2]:
    counts = run_with_noise_level(p)
    bell_prob = (counts.get('00', 0) + counts.get('11', 0)) / 5000
    print(f"p={p:.2f}: Bell fidelity ≈ {bell_prob:.3f}, counts={counts}")

运行结果:

p=0.00: Bell fidelity ≈ 1.000, counts={'00': 2467, '11': 2533}
p=0.01: Bell fidelity ≈ 0.990, counts={'00': 2445, '11': 2505, '10': 21, '01': 29}
p=0.05: Bell fidelity ≈ 0.950, counts={'11': 2351, '00': 2397, '01': 122, '10': 130}
p=0.10: Bell fidelity ≈ 0.902, counts={'10': 236, '00': 2242, '11': 2268, '01': 254}
p=0.20: Bell fidelity ≈ 0.817, counts={'11': 2122, '00': 1964, '10': 450, '01': 464}

示例 3:逐量子比特噪声配置 ​

python
from pyqpanda3 import core

# Different noise levels for different qubits
noise = core.NoiseModel()

# Qubit 0 has higher error rate
noise.add_quantum_error(
    core.depolarizing_error(0.02), core.GateType.H, [0]
)
noise.add_quantum_error(
    core.depolarizing_error(0.05), core.GateType.CNOT, [0, 1]
)

# Qubit 2 has lower error rate
noise.add_quantum_error(
    core.depolarizing_error(0.005), core.GateType.H, [2]
)
noise.add_quantum_error(
    core.depolarizing_error(0.01), core.GateType.CNOT, [2, 3]
)

# Run a 4-qubit circuit with per-qubit noise
prog = core.QProg()
prog << core.H(0) << core.H(2)
prog << core.CNOT(0, 1) << core.CNOT(2, 3)
prog << core.measure([0, 1, 2, 3], [0, 1, 2, 3])

machine = core.CPUQVM()
machine.run(prog, shots=10000, model=noise)
print(machine.result().get_counts())

运行结果:

{'0011': 2347, '1100': 2305, '0111': 14, '1111': 2347, '0000': 2309, '1101': 149, '1011': 26, '0001': 137, '0010': 150, '1110': 165, '0100': 31, '0101': 1, '1000': 18, '0110': 1}

示例 4:噪声下的 GHZ 态 ​

Greenberger-Horne-Zeilinger(GHZ)态 12(|000⟩+|111⟩) 对噪声高度敏感,因为其量子关联跨越所有量子比特。本示例测量在真实噪声模型下 GHZ 保真度如何随量子比特数退化。

python
from pyqpanda3 import core

def build_ghz_circuit(num_qubits):
    """Create a GHZ state on the given number of qubits."""
    prog = core.QProg()
    prog << core.H(0)
    for i in range(num_qubits - 1):
        prog << core.CNOT(i, i + 1)
    prog << core.measure(list(range(num_qubits)), list(range(num_qubits)))
    return prog

# Define a realistic noise model
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.002), core.GateType.H
)
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.01), core.GateType.CNOT
)
noise.add_all_qubit_read_out_error([[0.97, 0.03], [0.04, 0.96]])

shots = 10000
machine = core.CPUQVM()

# Measure GHZ fidelity as a function of qubit count
for n in [2, 3, 4, 5, 6]:
    prog = build_ghz_circuit(n)

    machine.run(prog, shots=shots, model=noise)
    counts = machine.result().get_counts()

    # GHZ fidelity = fraction of results that are all-0 or all-1
    all_zero = "0" * n
    all_one = "1" * n
    ghz_count = counts.get(all_zero, 0) + counts.get(all_one, 0)
    fidelity = ghz_count / shots

    print(f"n={n}: GHZ fidelity={fidelity:.4f}  "
          f"all-0={counts.get(all_zero,0)}  "
          f"all-1={counts.get(all_one,0)}  "
          f"total_outcomes={len(counts)}")

运行结果:

n=2: GHZ fidelity=0.9203  all-0=4754  all-1=4449  total_outcomes=4
n=3: GHZ fidelity=0.8774  all-0=4505  all-1=4269  total_outcomes=8
n=4: GHZ fidelity=0.8393  all-0=4336  all-1=4057  total_outcomes=16
n=5: GHZ fidelity=0.8046  all-0=4128  all-1=3918  total_outcomes=32
n=6: GHZ fidelity=0.7737  all-0=4030  all-1=3707  total_outcomes=56

输出将显示保真度随量子比特数迅速下降,因为 CNOT 门数量(从而累积噪声)线性增长:

n=2: GHZ fidelity=0.9750  ...
n=3: GHZ fidelity=0.9580  ...
n=4: GHZ fidelity=0.9310  ...
n=5: GHZ fidelity=0.9020  ...
n=6: GHZ fidelity=0.8640  ...

示例 5:噪声扫描分析 ​

在开发算法时,对一系列噪声参数进行扫描以确定算法失效的阈值是很有用的。本示例在变分式电路上同时扫描去极化和振幅阻尼率。

python
from pyqpanda3 import core

def build_variational_circuit():
    """Build a simple variational-style ansatz circuit."""
    prog = core.QProg()
    # Layer 1
    prog << core.H(0) << core.H(1)
    prog << core.CNOT(0, 1)
    # Layer 2
    prog << core.RZ(0, 0.5) << core.RZ(1, 0.5)
    prog << core.CNOT(0, 1)
    # Layer 3
    prog << core.RZ(0, 0.3) << core.RZ(1, 0.3)
    prog << core.H(0) << core.H(1)
    prog << core.measure([0, 1], [0, 1])
    return prog

def compute_hamming_distance(counts, shots):
    """Compute the average Hamming weight of measurement outcomes."""
    total_weight = 0
    for bitstring, count in counts.items():
        weight = bitstring.count("1")
        total_weight += weight * count
    return total_weight / shots

prog = build_variational_circuit()
shots = 5000
machine = core.CPUQVM()

# First, get the ideal reference
machine.run(prog, shots=shots)
ideal_counts = machine.result().get_counts()
ideal_hw = compute_hamming_distance(ideal_counts, shots)

# Sweep depolarizing noise from 0.001 to 0.05
print("Depolarizing sweep:")
print(f"  {'Rate':>8s}  {'Hamming Weight':>15s}  {'Delta from Ideal':>17s}")
for rate in [0.001, 0.005, 0.01, 0.02, 0.05]:
    noise = core.NoiseModel()
    noise.add_all_qubit_quantum_error(
        core.depolarizing_error(rate), core.GateType.CNOT
    )
    noise.add_all_qubit_quantum_error(
        core.depolarizing_error(rate * 0.1), core.GateType.H
    )

    machine.run(prog, shots=shots, model=noise)
    counts = machine.result().get_counts()
    hw = compute_hamming_distance(counts, shots)
    delta = abs(hw - ideal_hw)
    print(f"  {rate:8.4f}  {hw:15.4f}  {delta:17.4f}")

# Sweep amplitude damping rate from 0.001 to 0.05
print("\nAmplitude damping sweep:")
print(f"  {'Rate':>8s}  {'Hamming Weight':>15s}  {'Delta from Ideal':>17s}")
for rate in [0.001, 0.005, 0.01, 0.02, 0.05]:
    noise = core.NoiseModel()
    noise.add_all_qubit_quantum_error(
        core.amplitude_damping_error(rate), core.GateType.CNOT
    )
    noise.add_all_qubit_quantum_error(
        core.amplitude_damping_error(rate * 0.5), core.GateType.H
    )

    machine.run(prog, shots=shots, model=noise)
    counts = machine.result().get_counts()
    hw = compute_hamming_distance(counts, shots)
    delta = abs(hw - ideal_hw)
    print(f"  {rate:8.4f}  {hw:15.4f}  {delta:17.4f}")

运行结果:

Depolarizing sweep:
      Rate   Hamming Weight   Delta from Ideal
    0.0010           0.2624             0.0188
    0.0050           0.2836             0.0024
    0.0100           0.2934             0.0122
    0.0200           0.3204             0.0392
    0.0500           0.3636             0.0824

Amplitude damping sweep:
      Rate   Hamming Weight   Delta from Ideal
    0.0010           0.2900             0.0088
    0.0050           0.2856             0.0044
    0.0100           0.2738             0.0074
    0.0200           0.2984             0.0172
    0.0500           0.3318             0.0506

请注意,振幅阻尼在 Hamming 权重中产生偏差(系统性地推向更少的 1 位),而去极化噪声产生对称的扩散。这种不对称性对于依赖精确输出分布的算法非常重要。

示例 6:不同噪声通道下的 Bell 态分析 ​

本示例使用 CPUQVM 分析不同噪声通道对 Bell 态的影响。

python
from pyqpanda3 import core

# Build a Bell state circuit with measurement
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Reference: ideal Bell state (no noise)
machine = core.CPUQVM()
machine.run(prog, shots=100000)
ideal_counts = machine.result().get_counts()
print("=== Ideal Bell State ===")
print(f"Measurement counts: {ideal_counts}")
ideal_bell = (ideal_counts.get('00', 0) + ideal_counts.get('11', 0)) / 100000
print(f"Bell Fidelity: {ideal_bell:.4f}")

# Analyze each noise channel's effect on the Bell state
channels = {
    "Depolarizing (1%)":   core.depolarizing_error(0.01),
    "Amp. Damping (2%)":  core.amplitude_damping_error(0.02),
    "Phase Damping (2%)": core.phase_damping_error(0.02),
    "Pauli X (5%)":       core.pauli_x_error(0.05),
    "Pauli Z (5%)":       core.pauli_z_error(0.05),
}

print("\n=== Noise Channel Analysis ===")
for name, err in channels.items():
    noise = core.NoiseModel()
    noise.add_all_qubit_quantum_error(err, core.GateType.CNOT)
    noise.add_all_qubit_quantum_error(err, core.GateType.H)

    machine.run(prog, shots=100000, model=noise)
    counts = machine.result().get_counts()
    total = sum(counts.values())

    p00 = counts.get('00', 0) / total
    p11 = counts.get('11', 0) / total
    p01 = counts.get('01', 0) / total
    p10 = counts.get('10', 0) / total
    fidelity = p00 + p11

    print(f"\n{name}:")
    print(f"  P(00)={p00:.4f}  P(11)={p11:.4f}  "
          f"P(01)={p01:.4f}  P(10)={p10:.4f}")
    print(f"  Bell Fidelity={fidelity:.4f}")

运行结果:

=== Ideal Bell State ===
Measurement counts: {'00': 49843, '11': 50157}
Bell Fidelity: 1.0000

=== Noise Channel Analysis ===

Depolarizing (1%):
  P(00)=0.4935  P(11)=0.4960  P(01)=0.0054  P(10)=0.0051
  Bell Fidelity=0.9895

Amp. Damping (2%):
  P(00)=0.5095  P(11)=0.4718  P(01)=0.0002  P(10)=0.0185
  Bell Fidelity=0.9813

Phase Damping (2%):
  P(00)=0.5014  P(11)=0.4986  P(01)=0.0000  P(10)=0.0000
  Bell Fidelity=1.0000

Pauli X (5%):
  P(00)=0.4528  P(11)=0.4511  P(01)=0.0474  P(10)=0.0486
  Bell Fidelity=0.9039

Pauli Z (5%):
  P(00)=0.4998  P(11)=0.5002  P(01)=0.0000  P(10)=0.0000
  Bell Fidelity=1.0000

从噪声通道比较中可以得出以下关键要点:

  • Pauli Z 噪声不改变计算基测量概率,因为 Z|0⟩=|0⟩ 且 Z|1⟩=−|1⟩。噪声仅影响非对角元素(相干项),这些在测量统计中不可见。
  • 振幅阻尼破坏了 |00⟩ 和 |11⟩ 之间的对称性,将概率推向 |00⟩。
  • 去极化噪声将概率泄漏均匀分布到所有非理想结果上。

NoiseOpType 枚举 ​

NoiseOpType 枚举指定量子误差的内部表示:

python
# Kraus matrix representation
core.NoiseOpType.KARUS_MATRIICES

# Noise operation representation
core.NoiseOpType.NOISE

门相关噪声 ​

真实量子处理器对不同门类型有不同的误差率。同一设备上 Hadamard 门的误差率可能为 5×10−4,而 CNOT 门可能为 2×10−2。准确建模这种门相关行为对于真实模拟至关重要。

为什么门相关噪声很重要 ​

mermaid
graph TD
    A["Quantum Processor"] --> B["Gate Calibration Data"]
    B --> C["Per-Gate Error Rates"]
    C --> D["H gates: 0.05%"]
    C --> E["CNOT gates: 2.0%"]
    C --> F["T gates: 0.1%"]
    C --> G["Measure: 1.5%"]

    D --> H["NoiseModel"]
    E --> H
    F --> H
    G --> H
    H --> I["Realistic Simulation"]

    style A fill:#1565C0,color:#fff
    style H fill:#FF9800,color:#fff
    style I fill:#4CAF50,color:#fff

逐门类型噪声配置 ​

以下示例演示如何在单个噪声模型中为不同门类型分配不同的误差通道和误差率:

python
from pyqpanda3 import core

def create_gate_dependent_noise():
    """Build a noise model with distinct error profiles per gate type."""
    noise = core.NoiseModel()

    # Single-qubit rotation gates have low depolarizing noise
    rot_error = core.depolarizing_error(0.0005)
    noise.add_all_qubit_quantum_error(rot_error, [
        core.GateType.H,
        core.GateType.X,
        core.GateType.Y,
        core.GateType.Z,
        core.GateType.S,
        core.GateType.T,
    ])

    # Parametric rotation gates have slightly higher noise due to
    # longer gate times and calibration uncertainty
    param_rot_error = core.depolarizing_error(0.001)
    noise.add_all_qubit_quantum_error(param_rot_error, [
        core.GateType.RX,
        core.GateType.RY,
        core.GateType.RZ,
    ])

    # CNOT is the noisiest gate on superconducting hardware
    cnot_error = core.depolarizing_error(0.02)
    noise.add_all_qubit_quantum_error(cnot_error, core.GateType.CNOT)

    # CZ gates may have different error characteristics than CNOT
    cz_error = core.depolarizing_error(0.015)
    noise.add_all_qubit_quantum_error(cz_error, core.GateType.CZ)

    # SWAP gates are decomposed into 3 CNOTs on most hardware
    swap_error = core.depolarizing_error(0.05)
    noise.add_all_qubit_quantum_error(swap_error, core.GateType.SWAP)

    return noise

noise = create_gate_dependent_noise()

# Build a circuit that uses multiple gate types
prog = core.QProg()
prog << core.H(0)
prog << core.RZ(1, 1.57)
prog << core.CNOT(0, 1)
prog << core.T(0)
prog << core.CZ(1, 2)
prog << core.measure([0, 1, 2], [0, 1, 2])

machine = core.CPUQVM()
machine.run(prog, shots=10000, model=noise)
print(f"Gate-dependent noise result: {machine.result().get_counts()}")

运行结果:

Gate-dependent noise result: {'011': 4845, '101': 3, '000': 4822, '100': 30, '001': 141, '010': 130, '111': 28, '110': 1}

每个门组合多种误差通道 ​

在真实硬件上,单个门可能同时受到多个独立噪声源的影响。你可以通过组合误差来建模这种情况:

python
from pyqpanda3 import core

noise = core.NoiseModel()

# For CNOT gates, model both coherent (depolarizing) and
# incoherent (amplitude damping) noise
dep_err = core.depolarizing_error(0.015)
amp_err = core.amplitude_damping_error(0.003)

# Apply depolarizing error to CNOT
noise.add_all_qubit_quantum_error(dep_err, core.GateType.CNOT)

# Also add amplitude damping on CNOT(0, 1)
noise.add_quantum_error(amp_err, core.GateType.CNOT, [0, 1])

# For single-qubit gates, add phase damping to model T2 processes
phase_err = core.phase_damping_error(0.002)
noise.add_all_qubit_quantum_error(phase_err, [
    core.GateType.H,
    core.GateType.T,
    core.GateType.S,
])

prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.T(0)
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=10000, model=noise)
print(f"Multi-channel noise: {machine.result().get_counts()}")

运行结果:

Multi-channel noise: {'11': 4863, '00': 4996, '01': 72, '10': 69}

逐门噪声汇总 ​

门类别典型误差率推荐通道
Clifford 单量子比特门(H、S、X)10−4 -- 10−3Depolarizing
非 Clifford 单量子比特门(T)10−3 -- 10−2Depolarizing
参数化旋转门(RX、RY、RZ)10−3 -- 5×10−3Depolarizing
双量子比特纠缠门(CNOT、CZ)10−2 -- 5×10−2Depolarizing + Amplitude Damping
SWAP(原生或分解的)3× CNOT 误差率Depolarizing
测量10−3 -- 10−2读出误差矩阵

噪声模型校准 ​

为了使模拟具有预测性,需要从实际硬件表征数据推导噪声模型参数。本节介绍如何将原始校准指标转换为 pyqpanda3 的噪声模型参数。

从硬件指标到噪声参数 ​

mermaid
graph LR
    A["T1 (us)"] --> D["NoiseModel"]
    B["T2 (us)"] --> D
    C["Gate Time (ns)"] --> D
    E["RB Fidelity"] --> D
    F["Readout Assign. Matrix"] --> D

    D --> G["amplitude_damping_error(gamma)"]
    D --> H["phase_damping_error(lambda)"]
    D --> I["depolarizing_error(p)"]
    D --> J["add_read_out_error(matrix)"]

    style D fill:#FF9800,color:#fff
    style G fill:#E8F5E9
    style H fill:#E8F5E9
    style I fill:#E8F5E9
    style J fill:#E8F5E9

从 T1 推导振幅阻尼率 ​

给定 T1 弛豫时间,对于持续时间为 tg 的门,振幅阻尼率 γ 为:

γ=1−e−tg/T1

对于短门时间(tg≪T1),这近似为 γ≈tg/T1。

python
from pyqpanda3 import core
import math

def t1_to_amplitude_damping(t1_us, gate_time_ns):
    """Convert T1 time and gate duration to an amplitude damping rate.

    Args:
        t1_us: T1 relaxation time in microseconds
        gate_time_ns: gate duration in nanoseconds

    Returns:
        gamma: amplitude damping rate for use in amplitude_damping_error
    """
    # Convert to same units (microseconds)
    gate_time_us = gate_time_ns / 1000.0
    gamma = 1.0 - math.exp(-gate_time_us / t1_us)
    return gamma

# Example: T1 = 80 us, single-qubit gate time = 20 ns
gamma_1q = t1_to_amplitude_damping(t1_us=80, gate_time_ns=20)
print(f"1q amplitude damping rate: {gamma_1q:.6f}")

# Example: T1 = 80 us, CNOT gate time = 300 ns
gamma_2q = t1_to_amplitude_damping(t1_us=80, gate_time_ns=300)
print(f"2q amplitude damping rate: {gamma_2q:.6f}")

# Create the error channels
ad_1q = core.amplitude_damping_error(gamma_1q)
ad_2q = core.amplitude_damping_error(gamma_2q)

运行结果:

1q amplitude damping rate: 0.000250
2q amplitude damping rate: 0.003743

从 T2 推导相位阻尼率 ​

给定 T2 退相位时间,对于持续时间为 tg 的门,相位阻尼率 λ 为:

λ=1−e−tg/T2

注意 T2 必须满足 T2≤2T1,这是由弛豫和退相位之间的基本关系决定的。

python
from pyqpanda3 import core
import math

def t2_to_phase_damping(t2_us, gate_time_ns):
    """Convert T2 time and gate duration to a phase damping rate.

    Args:
        t2_us: T2 dephasing time in microseconds
        gate_time_ns: gate duration in nanoseconds

    Returns:
        lambda_param: phase damping rate for use in phase_damping_error
    """
    gate_time_us = gate_time_ns / 1000.0
    lambda_param = 1.0 - math.exp(-gate_time_us / t2_us)
    return lambda_param

# Example: T2 = 60 us, single-qubit gate time = 20 ns
lambda_1q = t2_to_phase_damping(t2_us=60, gate_time_ns=20)
print(f"1q phase damping rate: {lambda_1q:.6f}")

# Example: T2 = 60 us, CNOT gate time = 300 ns
lambda_2q = t2_to_phase_damping(t2_us=60, gate_time_ns=300)
print(f"2q phase damping rate: {lambda_2q:.6f}")

# Create the error channels
pd_1q = core.phase_damping_error(lambda_1q)
pd_2q = core.phase_damping_error(lambda_2q)

运行结果:

1q phase damping rate: 0.000333
2q phase damping rate: 0.004988

构建校准噪声模型 ​

以下函数演示如何从一组硬件校准参数组装完整的噪声模型:

python
from pyqpanda3 import core
import math

def build_calibrated_noise_model(
    t1_values,       # Dict[int, float]: qubit -> T1 in us
    t2_values,       # Dict[int, float]: qubit -> T2 in us
    gate_times,      # Dict[str, float]: gate name -> time in ns
    rb_fidelities,   # Dict[str, float]: gate name -> average gate fidelity
    readout_matrix,  # List[List[float]]: 2x2 assignment matrix
):
    """Build a noise model from hardware calibration data.

    All parameters come from standard characterization experiments:
    - T1/T2 from relaxation/echo experiments
    - Gate times from hardware specifications
    - RB fidelities from randomized benchmarking
    - Readout matrix from measurement confusion matrices
    """
    noise = core.NoiseModel()

    # Convert RB fidelity to depolarizing probability.
    # For a d-dimensional system, the relation is:
    #   F_avg = 1 - p * (d - 1) / d
    # For a single qubit (d=2): p = 2 * (1 - F_avg)
    for gate_name, fidelity in rb_fidelities.items():
        p_dep = 2.0 * (1.0 - fidelity)
        if gate_name == "H":
            noise.add_all_qubit_quantum_error(
                core.depolarizing_error(p_dep), core.GateType.H
            )
        elif gate_name == "CNOT":
            noise.add_all_qubit_quantum_error(
                core.depolarizing_error(p_dep), core.GateType.CNOT
            )

    # Add amplitude damping per qubit based on T1 and gate time
    for qubit, t1 in t1_values.items():
        t2 = t2_values.get(qubit, t1)
        for gate_name, gt_ns in gate_times.items():
            gate_time_us = gt_ns / 1000.0
            gamma = 1.0 - math.exp(-gate_time_us / t1)
            gate_type = core.GateType.H if gate_name == "H" else core.GateType.CNOT
            qubits = [qubit] if gate_name == "H" else [0, 1]
            noise.add_quantum_error(
                core.amplitude_damping_error(gamma), gate_type, qubits
            )
            # Add phase damping based on T2
            lambda_param = 1.0 - math.exp(-gate_time_us / t2)
            noise.add_quantum_error(
                core.phase_damping_error(lambda_param), gate_type, qubits
            )

    # Add readout errors from the assignment matrix
    noise.add_all_qubit_read_out_error(readout_matrix)

    return noise

# Example calibration data for a 2-qubit device
calibrated_noise = build_calibrated_noise_model(
    t1_values={0: 80.0, 1: 65.0},
    t2_values={0: 60.0, 1: 50.0},
    gate_times={"H": 20.0, "CNOT": 300.0},
    rb_fidelities={"H": 0.9995, "CNOT": 0.985},
    readout_matrix=[[0.97, 0.03], [0.04, 0.96]],
)

# Run a test circuit with the calibrated model
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

machine = core.CPUQVM()
machine.run(prog, shots=10000, model=calibrated_noise)
print(f"Calibrated noise result: {machine.result().get_counts()}")

运行结果:

Calibrated noise result: {'11': 4525, '00': 4569, '01': 465, '10': 441}

噪声模拟工作流 ​

mermaid
sequenceDiagram
    participant U as User
    participant NM as NoiseModel
    participant QE as QuantumError
    participant SIM as Simulator

    U->>QE: Create error channels
    Note over QE: pauli_x_error(0.01)<br/>depolarizing_error(0.02)<br/>amplitude_damping_error(0.05)

    U->>NM: Create noise model
    U->>NM: add_all_qubit_quantum_error(QE, GateType)
    U->>NM: add_read_out_error(probs, qubit)

    U->>SIM: Create simulator
    U->>SIM: run(prog, shots, model=NM)

    Note over SIM: For each gate in prog:<br/>1. Apply ideal gate<br/>2. Sample noise from error channel<br/>3. Record measurement

    SIM-->>U: QResult with noisy counts

噪声缓解策略 ​

即使没有完整的量子纠错,几种实用技术也可以减少噪声对算法结果的影响。本节介绍可以在电路设计和后处理层面实施的策略。

策略概览 ​

mermaid
graph TD
    A["Noisy Results"] --> B["Circuit-Level Mitigation"]
    A --> C["Measurement Mitigation"]
    A --> D["Post-Processing Mitigation"]

    B --> B1["Minimize circuit depth"]
    B --> B2["Use native gate set"]
    B --> B3["Reduce two-qubit gate count"]

    C --> C1["Readout error correction"]
    C --> C2["Measurement calibration matrix"]

    D --> D1["Zero-noise extrapolation"]
    D --> D2["Probabilistic error cancellation"]
    D --> D3["Symmetry verification"]

    style A fill:#EF5350,color:#fff
    style B fill:#FFA726,color:#fff
    style C fill:#66BB6A,color:#fff
    style D fill:#42A5F5,color:#fff

1. 最小化电路深度 ​

最有效的策略是减少门的数量。每个门都是噪声进入的机会。在运行前使用编译和优化过程来降低深度。

python
from pyqpanda3 import core

# Inefficient: naive decomposition with many CNOT gates
prog_naive = core.QProg()
prog_naive << core.H(0)
prog_naive << core.CNOT(0, 1)
prog_naive << core.CNOT(1, 2)
prog_naive << core.CNOT(2, 3)
prog_naive << core.CNOT(3, 4)
prog_naive << core.measure([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])

# Efficient: equivalent computation with fewer CNOT gates
# by reordering or exploiting circuit identities
prog_efficient = core.QProg()
prog_efficient << core.H(0)
prog_efficient << core.CNOT(0, 1)
prog_efficient << core.CNOT(0, 2)
prog_efficient << core.measure([0, 1, 2], [0, 1, 2])

# The efficient circuit has fewer two-qubit gates,
# resulting in lower accumulated noise

2. 使用原生门集 ​

在面向真实硬件时,将电路编译为设备的原生门集。使用非原生门需要分解为多个原生门,从而放大噪声。

python
from pyqpanda3 import core

# Some devices natively support CZ instead of CNOT.
# Using the native gate avoids decomposition overhead.
prog = core.QProg()
prog << core.H(0) << core.H(1)
prog << core.CZ(0, 1)  # Use native CZ instead of decomposed CNOT
prog << core.measure([0, 1], [0, 1])

# Build a noise model that reflects the native gate's actual error rate
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.015), core.GateType.CZ
)
# No noise needed for CNOT since it is not used

3. 读出误差缓解 ​

可以使用校准矩阵对测量误差进行表征和校正。其思想是准备每个计算基态,多次测量,并构建分配矩阵 M:

p→true=M−1p→measured
python
from pyqpanda3 import core
import numpy as np

def calibrate_readout(num_qubits, shots=10000):
    """Build a readout calibration matrix for the given qubits.

    For each basis state, prepare it and measure to find
    the probability of observing each outcome.
    """
    dim = 2 ** num_qubits
    cal_matrix = np.zeros((dim, dim))

    for basis_state in range(dim):
        # Prepare the basis state by applying X gates where bits are 1
        prog = core.QProg()
        for q in range(num_qubits):
            if (basis_state >> q) & 1:
                prog << core.X(q)
        prog << core.measure(list(range(num_qubits)), list(range(num_qubits)))

        machine = core.CPUQVM()
        machine.run(prog, shots=shots)
        counts = machine.result().get_counts()

        # Fill the column of the calibration matrix
        for outcome in range(dim):
            key = format(outcome, f"0{num_qubits}b")
            cal_matrix[outcome][basis_state] = counts.get(key, 0) / shots

    return cal_matrix

# Calibrate a 2-qubit readout
cal_matrix = calibrate_readout(num_qubits=2, shots=10000)
print(f"Calibration matrix:\n{cal_matrix}")

运行结果:

Calibration matrix:
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

4. 零噪声外推 ​

在多个人为放大的噪声水平下运行同一电路,然后外推回零噪声。这是近期设备最实用的误差缓解技术之一。

核心思想:如果噪声按 F(λ)=F0⋅e−αλ 缩放,其中 λ 是噪声缩放因子,则可以从 λ=1,2,3,… 处的测量值估计 F0(无噪声结果)。

python
from pyqpanda3 import core
import numpy as np

def run_at_noise_scale(base_error_rate, scale_factor, shots=5000):
    """Run the benchmark circuit at an amplified noise level."""
    # Amplify the error rate by the scale factor
    amplified_rate = min(base_error_rate * scale_factor, 0.99)

    noise = core.NoiseModel()
    noise.add_all_qubit_quantum_error(
        core.depolarizing_error(amplified_rate), core.GateType.CNOT
    )

    prog = core.QProg()
    prog << core.H(0) << core.CNOT(0, 1)
    prog << core.measure([0, 1], [0, 1])

    machine = core.CPUQVM()
    machine.run(prog, shots=shots, model=noise)
    counts = machine.result().get_counts()

    # Return the Bell-state fidelity
    bell = (counts.get("00", 0) + counts.get("11", 0)) / shots
    return bell

# Measure at three noise levels and extrapolate linearly
base_rate = 0.02
scales = [1.0, 2.0, 3.0]
fidelities = [run_at_noise_scale(base_rate, s) for s in scales]

# Linear extrapolation to zero noise
# Fit: f(x) = a*x + b, estimate f(0) = b
coeffs = np.polyfit(scales, fidelities, deg=1)
f_zero_noise = coeffs[1]

print(f"Noise scale factors: {scales}")
print(f"Measured fidelities:  {fidelities}")
print(f"Extrapolated zero-noise fidelity: {f_zero_noise:.4f}")
# The extrapolated value should be closer to 1.0 than any individual measurement

运行结果:

Noise scale factors: [1.0, 2.0, 3.0]
Measured fidelities:  [0.983, 0.965, 0.94]
Extrapolated zero-noise fidelity: 1.0057

缓解策略选择指南 ​

策略开销有效性适用场景
最小化深度无(编译时)中等始终首先应用
原生门集无(编译时)中等面向特定硬件时
读出缓解O(2n) 校准运行对测量密集型电路效果高当读出误差占主导时
零噪声外推3× 电路运行对中等深度电路效果高通用缓解
概率误差消除随电路深度指数增长效果高但代价大小电路(< 20 量子比特)

最佳实践 ​

1. 匹配硬件噪声 ​

使用与目标设备匹配的误差率。超导设备的典型值:

误差类型典型率
单量子比特门10−3 到 10−4
双量子比特门10−2 到 10−3
读出10−2 到 10−3
T1 时间20-100 μs

2. 使用高采样次数以获得可靠统计 ​

对于小电路,CPUQVM 配合高采样次数可以提供准确的噪声统计:

python
from pyqpanda3 import core

# Accurate noise simulation for small circuits with high shot count
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

noise_model = core.NoiseModel()
noise_model.add_all_qubit_quantum_error(
    core.depolarizing_error(0.01), core.GateType.CNOT
)

machine = core.CPUQVM()
machine.run(prog, shots=100000, model=noise_model)
counts = machine.result().get_counts()
total = sum(counts.values())
p00 = counts.get('00', 0) / total
p11 = counts.get('11', 0) / total
print(f"P(00)={p00:.4f}  P(11)={p11:.4f}")
print(f"Bell fidelity (with 100k shots): {p00 + p11:.4f}")

运行结果:

P(00)=0.4946  P(11)=0.4948
Bell fidelity (with 100k shots): 0.9894

3. 使用足够的采样次数 ​

统计误差按 1/shots 下降:

  • 1000 次:约 3% 误差
  • 10000 次:约 1% 误差
  • 100000 次:约 0.3% 误差

4. 与理想模拟对比验证 ​

始终将噪声结果与理想模拟进行比较,以理解噪声的影响:

python
from pyqpanda3 import core

# Build a Bell state circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# Create noise model
noise = core.NoiseModel()
noise.add_all_qubit_quantum_error(
    core.depolarizing_error(0.01), core.GateType.CNOT
)

machine = core.CPUQVM()

# Ideal simulation
machine.run(prog, shots=10000)
ideal_counts = machine.result().get_counts()

# Noisy simulation
machine.run(prog, shots=10000, model=noise)
noisy_counts = machine.result().get_counts()

# Compare
print(f"Ideal: {ideal_counts}")
print(f"Noisy: {noisy_counts}")

运行结果:

Ideal: {'00': 5112, '11': 4888}
Noisy: {'11': 4964, '00': 4947, '10': 48, '01': 41}

后续步骤 ​

Released under the MIT License.