janus.simulator.noisy_simulator 源代码

"""
Janus 噪声模拟器

基于密度矩阵的带噪声量子电路模拟器
"""
from __future__ import annotations
from typing import List, Optional, Union, Dict
import numpy as np

from .density_matrix import DensityMatrix
from .statevector import Statevector
from .result import SimulatorResult, Counts
from .noise import NoiseModel, NoiseChannel
from .exceptions import SimulatorError, ParameterBindingError


[文档] class NoisySimulator: """ 噪声模拟器 使用密度矩阵进行带噪声的量子电路模拟 Example: from janus.simulator import NoisySimulator from janus.simulator.noise import NoiseModel, depolarizing_channel # 创建噪声模型 noise_model = NoiseModel() noise_model.add_all_qubit_quantum_error( depolarizing_channel(0.01), ['cx'] ) # 模拟 sim = NoisySimulator(noise_model) result = sim.run(circuit, shots=1000) """
[文档] def __init__( self, noise_model: Optional[NoiseModel] = None, seed: Optional[Union[int, np.random.Generator]] = None ): """ 初始化噪声模拟器 Args: noise_model: 噪声模型 seed: 随机数种子 """ self._noise_model = noise_model self._seed = seed if seed is not None: if isinstance(seed, np.random.Generator): self._rng = seed else: self._rng = np.random.default_rng(seed) else: self._rng = np.random.default_rng()
@property def noise_model(self) -> Optional[NoiseModel]: """获取噪声模型""" return self._noise_model @noise_model.setter def noise_model(self, value: NoiseModel): """设置噪声模型""" self._noise_model = value
[文档] def run( self, circuit, shots: int = 1024, initial_state: Optional[Union[DensityMatrix, Statevector, np.ndarray]] = None, parameter_binds: Optional[Dict] = None, measure_qubits: Optional[List[int]] = None ) -> SimulatorResult: """ 运行噪声模拟 Args: circuit: 要模拟的电路 shots: 测量次数 initial_state: 初始状态 parameter_binds: 参数绑定 measure_qubits: 要测量的量子比特 Returns: SimulatorResult: 模拟结果 """ # 绑定参数 if parameter_binds: circuit = self._bind_parameters(circuit, parameter_binds) # 准备初始状态 dm = self._prepare_initial_state(circuit.n_qubits, initial_state) dm.seed(self._rng) # 演化电路(带噪声) dm = self._evolve_with_noise(dm, circuit) # 确定测量的量子比特 if measure_qubits is None: if circuit.measured_qubits is not None: measure_qubits = circuit.measured_qubits else: measure_qubits = list(range(circuit.n_qubits)) # 采样测量(可能带读出错误) counts = self._sample_with_readout_error(dm, shots, measure_qubits) # 构建结果 result = SimulatorResult( counts=dict(counts), statevector=None, # 噪声模拟不返回状态向量 shots=shots, metadata={ 'num_qubits': circuit.n_qubits, 'circuit_depth': circuit.depth, 'measured_qubits': measure_qubits, 'simulator': 'noisy', 'purity': dm.purity() } ) return result
[文档] def density_matrix( self, circuit, initial_state: Optional[Union[DensityMatrix, Statevector, np.ndarray]] = None, parameter_binds: Optional[Dict] = None ) -> DensityMatrix: """ 获取电路的最终密度矩阵 Args: circuit: 要模拟的电路 initial_state: 初始状态 parameter_binds: 参数绑定 Returns: DensityMatrix: 最终密度矩阵 """ if parameter_binds: circuit = self._bind_parameters(circuit, parameter_binds) dm = self._prepare_initial_state(circuit.n_qubits, initial_state) return self._evolve_with_noise(dm, circuit)
def _prepare_initial_state( self, num_qubits: int, initial_state: Optional[Union[DensityMatrix, Statevector, np.ndarray]] ) -> DensityMatrix: """准备初始状态""" if initial_state is None: sv = Statevector.from_int(0, num_qubits) return DensityMatrix.from_statevector(sv) elif isinstance(initial_state, DensityMatrix): if initial_state.num_qubits != num_qubits: raise SimulatorError( f"Initial state has {initial_state.num_qubits} qubits, " f"but circuit has {num_qubits} qubits" ) return initial_state.copy() elif isinstance(initial_state, Statevector): if initial_state.num_qubits != num_qubits: raise SimulatorError( f"Initial state has {initial_state.num_qubits} qubits, " f"but circuit has {num_qubits} qubits" ) return DensityMatrix.from_statevector(initial_state) elif isinstance(initial_state, np.ndarray): if initial_state.ndim == 1: return DensityMatrix.from_statevector(Statevector(initial_state)) else: return DensityMatrix(initial_state) else: raise SimulatorError(f"Invalid initial state type: {type(initial_state)}") def _evolve_with_noise(self, dm: DensityMatrix, circuit) -> DensityMatrix: """带噪声演化""" from janus.circuit.parameter import is_parameterized for inst in circuit.instructions: if is_parameterized(inst.operation): raise ParameterBindingError( f"Circuit contains unbound parameter in gate {inst.name}" ) # 应用门 matrix = inst.operation.to_matrix() dm.evolve(matrix, inst.qubits) # 应用噪声 if self._noise_model is not None: error = self._noise_model.get_gate_error(inst.name, inst.qubits) if error is not None: # 对每个量子比特应用单比特噪声 if error.num_qubits == 1: for q in inst.qubits: dm.apply_channel(error.kraus_ops, [q]) else: # 多比特噪声直接应用到所有相关量子比特 dm.apply_channel(error.kraus_ops, inst.qubits) return dm def _sample_with_readout_error( self, dm: DensityMatrix, shots: int, measure_qubits: List[int] ) -> Counts: """带读出错误的采样""" # 先进行理想采样 counts = dm.sample_counts(shots, measure_qubits) # 如果没有噪声模型或没有读出错误,直接返回 if self._noise_model is None: return counts # 应用读出错误 new_counts = {} for bitstring, count in counts.items(): # 对每个采样结果应用读出错误 for _ in range(count): noisy_bits = list(bitstring) for i, q in enumerate(measure_qubits): error = self._noise_model.get_readout_error(q) if error is not None: p0_given_1, p1_given_0 = error bit_idx = len(bitstring) - 1 - i if noisy_bits[bit_idx] == '0': if self._rng.random() < p1_given_0: noisy_bits[bit_idx] = '1' else: if self._rng.random() < p0_given_1: noisy_bits[bit_idx] = '0' noisy_bitstring = ''.join(noisy_bits) new_counts[noisy_bitstring] = new_counts.get(noisy_bitstring, 0) + 1 return Counts(new_counts) def _bind_parameters(self, circuit, parameter_binds: Dict): """绑定参数""" from janus.circuit.parameter import Parameter if hasattr(circuit, 'bind_parameters'): return circuit.bind_parameters(parameter_binds) import copy bound_circuit = copy.deepcopy(circuit) for inst in bound_circuit.instructions: new_params = [] for param in inst.operation.params: if isinstance(param, Parameter): if param in parameter_binds: new_params.append(parameter_binds[param]) elif param.name in parameter_binds: new_params.append(parameter_binds[param.name]) else: raise ParameterBindingError( f"No binding provided for parameter {param.name}" ) else: new_params.append(param) inst.operation.params = new_params return bound_circuit