janus.simulator.noise 源代码

"""
Janus 噪声模型

提供常见的量子噪声信道
"""
from __future__ import annotations
from typing import List, Optional, Tuple
import numpy as np


[文档] class NoiseChannel: """ 噪声信道基类 使用 Kraus 表示:ρ → Σ_k K_k ρ K_k† """
[文档] def __init__(self, kraus_ops: List[np.ndarray], num_qubits: int = 1): """ 初始化噪声信道 Args: kraus_ops: Kraus 算符列表 num_qubits: 作用的量子比特数 """ self._kraus_ops = [np.asarray(K, dtype=complex) for K in kraus_ops] self._num_qubits = num_qubits # 验证完备性:Σ_k K_k† K_k = I identity = np.eye(2 ** num_qubits, dtype=complex) completeness = sum(K.conj().T @ K for K in self._kraus_ops) if not np.allclose(completeness, identity, atol=1e-10): raise ValueError("Kraus operators do not satisfy completeness relation")
@property def kraus_ops(self) -> List[np.ndarray]: """获取 Kraus 算符""" return self._kraus_ops @property def num_qubits(self) -> int: """获取量子比特数""" return self._num_qubits
[文档] def compose(self, other: 'NoiseChannel') -> 'NoiseChannel': """组合两个噪声信道""" if self._num_qubits != other._num_qubits: raise ValueError("Cannot compose channels with different qubit counts") new_kraus = [] for K1 in self._kraus_ops: for K2 in other._kraus_ops: new_kraus.append(K1 @ K2) return NoiseChannel(new_kraus, self._num_qubits)
[文档] def tensor(self, other: 'NoiseChannel') -> 'NoiseChannel': """张量积两个噪声信道""" new_kraus = [] for K1 in self._kraus_ops: for K2 in other._kraus_ops: new_kraus.append(np.kron(K1, K2)) return NoiseChannel(new_kraus, self._num_qubits + other._num_qubits)
# ==================== 常见噪声信道 ====================
[文档] def depolarizing_channel(p: float, num_qubits: int = 1) -> NoiseChannel: """ 去极化信道 ρ → (1-p)ρ + p/3 (XρX + YρY + ZρZ) (单比特) ρ → (1-p)ρ + p/(4^n-1) Σ_P PρP (多比特) Args: p: 去极化概率 num_qubits: 量子比特数 Returns: NoiseChannel: 去极化信道 """ if not 0 <= p <= 1: raise ValueError(f"Probability p={p} must be in [0, 1]") dim = 2 ** num_qubits if num_qubits == 1: # 单比特去极化 I = np.eye(2, dtype=complex) X = np.array([[0, 1], [1, 0]], dtype=complex) Y = np.array([[0, -1j], [1j, 0]], dtype=complex) Z = np.array([[1, 0], [0, -1]], dtype=complex) kraus_ops = [ np.sqrt(1 - p) * I, np.sqrt(p / 3) * X, np.sqrt(p / 3) * Y, np.sqrt(p / 3) * Z ] else: # 多比特去极化 num_paulis = dim ** 2 - 1 kraus_ops = [np.sqrt(1 - p) * np.eye(dim, dtype=complex)] # 生成所有非恒等 Pauli 算符 paulis = _generate_paulis(num_qubits) for P in paulis[1:]: # 跳过恒等 kraus_ops.append(np.sqrt(p / num_paulis) * P) return NoiseChannel(kraus_ops, num_qubits)
[文档] def amplitude_damping_channel(gamma: float) -> NoiseChannel: """ 振幅阻尼信道(能量弛豫) 模拟 |1⟩ → |0⟩ 的自发衰减 Args: gamma: 衰减概率 Returns: NoiseChannel: 振幅阻尼信道 """ if not 0 <= gamma <= 1: raise ValueError(f"Gamma={gamma} must be in [0, 1]") K0 = np.array([[1, 0], [0, np.sqrt(1 - gamma)]], dtype=complex) K1 = np.array([[0, np.sqrt(gamma)], [0, 0]], dtype=complex) return NoiseChannel([K0, K1], 1)
[文档] def phase_damping_channel(gamma: float) -> NoiseChannel: """ 相位阻尼信道(纯退相干) Args: gamma: 退相干概率 Returns: NoiseChannel: 相位阻尼信道 """ if not 0 <= gamma <= 1: raise ValueError(f"Gamma={gamma} must be in [0, 1]") K0 = np.array([[1, 0], [0, np.sqrt(1 - gamma)]], dtype=complex) K1 = np.array([[0, 0], [0, np.sqrt(gamma)]], dtype=complex) return NoiseChannel([K0, K1], 1)
[文档] def bit_flip_channel(p: float) -> NoiseChannel: """ 比特翻转信道 ρ → (1-p)ρ + p XρX Args: p: 翻转概率 Returns: NoiseChannel: 比特翻转信道 """ if not 0 <= p <= 1: raise ValueError(f"Probability p={p} must be in [0, 1]") I = np.eye(2, dtype=complex) X = np.array([[0, 1], [1, 0]], dtype=complex) kraus_ops = [np.sqrt(1 - p) * I, np.sqrt(p) * X] return NoiseChannel(kraus_ops, 1)
[文档] def phase_flip_channel(p: float) -> NoiseChannel: """ 相位翻转信道 ρ → (1-p)ρ + p ZρZ Args: p: 翻转概率 Returns: NoiseChannel: 相位翻转信道 """ if not 0 <= p <= 1: raise ValueError(f"Probability p={p} must be in [0, 1]") I = np.eye(2, dtype=complex) Z = np.array([[1, 0], [0, -1]], dtype=complex) kraus_ops = [np.sqrt(1 - p) * I, np.sqrt(p) * Z] return NoiseChannel(kraus_ops, 1)
def bit_phase_flip_channel(p: float) -> NoiseChannel: """ 比特-相位翻转信道 ρ → (1-p)ρ + p YρY Args: p: 翻转概率 Returns: NoiseChannel: 比特-相位翻转信道 """ if not 0 <= p <= 1: raise ValueError(f"Probability p={p} must be in [0, 1]") I = np.eye(2, dtype=complex) Y = np.array([[0, -1j], [1j, 0]], dtype=complex) kraus_ops = [np.sqrt(1 - p) * I, np.sqrt(p) * Y] return NoiseChannel(kraus_ops, 1)
[文档] def thermal_relaxation_channel( t1: float, t2: float, time: float, excited_state_population: float = 0.0 ) -> NoiseChannel: """ 热弛豫信道 结合 T1(能量弛豫)和 T2(退相干)效应 Args: t1: T1 时间 t2: T2 时间 time: 门操作时间 excited_state_population: 热平衡时激发态布居 Returns: NoiseChannel: 热弛豫信道 """ if t2 > 2 * t1: raise ValueError(f"T2={t2} cannot be greater than 2*T1={2*t1}") # 计算概率 p_reset = 1 - np.exp(-time / t1) if t1 == t2: # 纯 T1 弛豫 gamma = p_reset return amplitude_damping_channel(gamma) # T2 退相干 exp_t2 = np.exp(-time / t2) exp_t1 = np.exp(-time / t1) # 组合 T1 和 T2 效应 p0 = 1 - excited_state_population p1 = excited_state_population # Kraus 算符 K0 = np.array([ [np.sqrt(p0) * np.sqrt(1 - p_reset), 0], [0, np.sqrt(p1) * exp_t2 / np.sqrt(exp_t1)] ], dtype=complex) K1 = np.array([ [np.sqrt(p0) * np.sqrt(p_reset), 0], [0, 0] ], dtype=complex) K2 = np.array([ [0, np.sqrt(p1) * np.sqrt(p_reset)], [0, 0] ], dtype=complex) K3 = np.array([ [0, 0], [np.sqrt(p0) * np.sqrt(1 - exp_t2**2 / exp_t1), 0] ], dtype=complex) # 过滤零算符 kraus_ops = [K for K in [K0, K1, K2, K3] if np.linalg.norm(K) > 1e-10] return NoiseChannel(kraus_ops, 1)
[文档] def readout_error_channel(p0_given_1: float, p1_given_0: float) -> Tuple[np.ndarray, np.ndarray]: """ 读出错误(经典噪声) 返回混淆矩阵,用于后处理测量结果 Args: p0_given_1: 测量 |1⟩ 得到 0 的概率 p1_given_0: 测量 |0⟩ 得到 1 的概率 Returns: Tuple[np.ndarray, np.ndarray]: (混淆矩阵, 逆混淆矩阵) """ # 混淆矩阵 M[i,j] = P(测量结果=i | 真实状态=j) confusion_matrix = np.array([ [1 - p1_given_0, p0_given_1], [p1_given_0, 1 - p0_given_1] ]) # 逆矩阵用于误差缓解 try: inverse_matrix = np.linalg.inv(confusion_matrix) except np.linalg.LinAlgError: inverse_matrix = None return confusion_matrix, inverse_matrix
# ==================== 辅助函数 ==================== def _generate_paulis(num_qubits: int) -> List[np.ndarray]: """生成所有 n-qubit Pauli 算符""" I = np.eye(2, dtype=complex) X = np.array([[0, 1], [1, 0]], dtype=complex) Y = np.array([[0, -1j], [1j, 0]], dtype=complex) Z = np.array([[1, 0], [0, -1]], dtype=complex) single_paulis = [I, X, Y, Z] if num_qubits == 1: return single_paulis paulis = [np.array([[1]], dtype=complex)] for _ in range(num_qubits): new_paulis = [] for P in paulis: for sigma in single_paulis: new_paulis.append(np.kron(P, sigma)) paulis = new_paulis return paulis
[文档] class NoiseModel: """ 噪声模型 定义电路中各种门的噪声 Example: noise_model = NoiseModel() noise_model.add_all_qubit_quantum_error( depolarizing_channel(0.01), ['cx'] ) noise_model.add_readout_error(0.02, 0.03) """
[文档] def __init__(self): self._gate_errors = {} # gate_name -> NoiseChannel self._qubit_gate_errors = {} # (gate_name, qubit) -> NoiseChannel self._readout_error = None self._readout_error_qubits = {} # qubit -> (p0_given_1, p1_given_0)
[文档] def add_quantum_error( self, error: NoiseChannel, gate_names: List[str], qubits: Optional[List[int]] = None ): """ 添加量子错误 Args: error: 噪声信道 gate_names: 门名称列表 qubits: 特定量子比特(None 表示所有) """ for gate in gate_names: if qubits is None: self._gate_errors[gate] = error else: for q in qubits: self._qubit_gate_errors[(gate, q)] = error
[文档] def add_all_qubit_quantum_error( self, error: NoiseChannel, gate_names: List[str] ): """为所有量子比特添加量子错误""" self.add_quantum_error(error, gate_names, None)
[文档] def add_readout_error( self, p0_given_1: float, p1_given_0: float, qubits: Optional[List[int]] = None ): """ 添加读出错误 Args: p0_given_1: 测量 |1⟩ 得到 0 的概率 p1_given_0: 测量 |0⟩ 得到 1 的概率 qubits: 特定量子比特(None 表示所有) """ if qubits is None: self._readout_error = (p0_given_1, p1_given_0) else: for q in qubits: self._readout_error_qubits[q] = (p0_given_1, p1_given_0)
[文档] def get_gate_error( self, gate_name: str, qubits: List[int] ) -> Optional[NoiseChannel]: """获取门的噪声信道""" # 先检查特定量子比特的错误 for q in qubits: if (gate_name, q) in self._qubit_gate_errors: return self._qubit_gate_errors[(gate_name, q)] # 再检查全局门错误 return self._gate_errors.get(gate_name)
[文档] def get_readout_error(self, qubit: int) -> Optional[Tuple[float, float]]: """获取读出错误""" if qubit in self._readout_error_qubits: return self._readout_error_qubits[qubit] return self._readout_error