"""
Janus 状态向量模拟器
基于状态向量的量子电路模拟器
"""
from __future__ import annotations
from typing import List, Optional, Union, Dict, Any
import numpy as np
from .statevector import Statevector
from .result import SimulatorResult, Counts
from .exceptions import SimulatorError, InvalidCircuitError, ParameterBindingError
[文档]
class StatevectorSimulator:
"""
状态向量模拟器
使用完整状态向量进行精确模拟,适用于小规模量子电路(< 25 qubits)
Features:
- 精确模拟(无采样误差)
- 支持参数化电路
- 支持初始状态设置
- 支持部分测量
- 支持期望值计算
Example:
from janus.circuit import Circuit
from janus.simulator import StatevectorSimulator
# 创建 Bell 态电路
qc = Circuit(2)
qc.h(0)
qc.cx(0, 1)
# 模拟
sim = StatevectorSimulator()
result = sim.run(qc, shots=1000)
print(result.counts) # {'00': ~500, '11': ~500}
"""
[文档]
def __init__(
self,
seed: Optional[Union[int, np.random.Generator]] = None,
precision: str = 'double'
):
"""
初始化模拟器
Args:
seed: 随机数种子
precision: 精度 ('single' 或 'double')
"""
self._seed = seed
self._precision = precision
self._dtype = np.complex128 if precision == 'double' else np.complex64
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 seed(self) -> Optional[Union[int, np.random.Generator]]:
"""获取随机数种子"""
return self._seed
[文档]
def run(
self,
circuit,
shots: int = 1024,
initial_state: Optional[Union[Statevector, np.ndarray, str]] = None,
parameter_binds: Optional[Dict] = None,
measure_qubits: Optional[List[int]] = None,
return_statevector: bool = True
) -> SimulatorResult:
"""
运行模拟
Args:
circuit: 要模拟的电路
shots: 测量次数
initial_state: 初始状态(默认 |0...0⟩)
parameter_binds: 参数绑定字典
measure_qubits: 要测量的量子比特(默认全部)
return_statevector: 是否返回状态向量
Returns:
SimulatorResult: 模拟结果
"""
# 绑定参数
if parameter_binds:
circuit = self._bind_parameters(circuit, parameter_binds)
# 验证电路
self._validate_circuit(circuit)
# 准备初始状态
statevector = self._prepare_initial_state(circuit.n_qubits, initial_state)
statevector.seed(self._rng)
# 演化电路
statevector = statevector.evolve_circuit(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 = statevector.sample_counts(shots, measure_qubits)
# 构建结果
result = SimulatorResult(
counts=dict(counts),
statevector=statevector.data if return_statevector else None,
shots=shots,
metadata={
'num_qubits': circuit.n_qubits,
'circuit_depth': circuit.depth,
'measured_qubits': measure_qubits,
'simulator': 'statevector'
}
)
return result
[文档]
def run_batch(
self,
circuits: List,
shots: int = 1024,
**kwargs
) -> List[SimulatorResult]:
"""
批量运行多个电路
Args:
circuits: 电路列表
shots: 每个电路的测量次数
**kwargs: 传递给 run() 的其他参数
Returns:
List[SimulatorResult]: 结果列表
"""
return [self.run(circuit, shots=shots, **kwargs) for circuit in circuits]
[文档]
def statevector(
self,
circuit,
initial_state: Optional[Union[Statevector, np.ndarray, str]] = None,
parameter_binds: Optional[Dict] = None
) -> Statevector:
"""
获取电路的最终状态向量(不进行测量)
Args:
circuit: 要模拟的电路
initial_state: 初始状态
parameter_binds: 参数绑定
Returns:
Statevector: 最终状态向量
"""
if parameter_binds:
circuit = self._bind_parameters(circuit, parameter_binds)
self._validate_circuit(circuit)
sv = self._prepare_initial_state(circuit.n_qubits, initial_state)
return sv.evolve_circuit(circuit)
[文档]
def expectation_value(
self,
circuit,
observable: np.ndarray,
qargs: Optional[List[int]] = None,
initial_state: Optional[Union[Statevector, np.ndarray, str]] = None,
parameter_binds: Optional[Dict] = None
) -> complex:
"""
计算可观测量的期望值
Args:
circuit: 量子电路
observable: 可观测量矩阵
qargs: 可观测量作用的量子比特
initial_state: 初始状态
parameter_binds: 参数绑定
Returns:
complex: 期望值
"""
sv = self.statevector(circuit, initial_state, parameter_binds)
return sv.expectation_value(observable, qargs)
[文档]
def probabilities(
self,
circuit,
qargs: Optional[List[int]] = None,
initial_state: Optional[Union[Statevector, np.ndarray, str]] = None,
parameter_binds: Optional[Dict] = None
) -> np.ndarray:
"""
计算测量概率分布
Args:
circuit: 量子电路
qargs: 要测量的量子比特
initial_state: 初始状态
parameter_binds: 参数绑定
Returns:
np.ndarray: 概率分布
"""
sv = self.statevector(circuit, initial_state, parameter_binds)
return sv.probabilities(qargs)
def _prepare_initial_state(
self,
num_qubits: int,
initial_state: Optional[Union[Statevector, np.ndarray, str]]
) -> Statevector:
"""准备初始状态"""
if initial_state is None:
return Statevector.from_int(0, num_qubits)
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 initial_state.copy()
elif isinstance(initial_state, str):
sv = Statevector.from_label(initial_state)
if sv.num_qubits != num_qubits:
raise SimulatorError(
f"Initial state label has {sv.num_qubits} qubits, "
f"but circuit has {num_qubits} qubits"
)
return sv
elif isinstance(initial_state, np.ndarray):
return Statevector(initial_state, num_qubits)
else:
raise SimulatorError(f"Invalid initial state type: {type(initial_state)}")
def _validate_circuit(self, circuit):
"""验证电路"""
from janus.circuit.parameter import Parameter, ParameterExpression
# 检查是否有未绑定的参数
for inst in circuit.instructions:
for param in inst.operation.params:
if isinstance(param, Parameter):
raise ParameterBindingError(
f"Circuit contains unbound parameter '{param.name}' in gate {inst.name}. "
"Please provide parameter_binds."
)
elif isinstance(param, ParameterExpression) and not param.is_real():
raise ParameterBindingError(
f"Circuit contains unbound parameter expression in gate {inst.name}. "
"Please provide parameter_binds."
)
def _bind_parameters(self, circuit, parameter_binds: Dict):
"""绑定参数到电路"""
from janus.circuit.parameter import Parameter, ParameterExpression
# 将字符串键转换为 Parameter 对象
converted_binds = {}
for key, value in parameter_binds.items():
if isinstance(key, Parameter):
converted_binds[key] = value
elif isinstance(key, str):
# 查找电路中对应名称的参数
for param in circuit.parameters:
if param.name == key:
converted_binds[param] = value
break
else:
# 如果找不到,保留字符串键(可能电路有自己的处理方式)
converted_binds[key] = value
else:
converted_binds[key] = value
# 使用电路的 bind_parameters 方法
if hasattr(circuit, 'bind_parameters'):
return circuit.bind_parameters(converted_binds)
# 手动绑定作为后备
import copy
bound_circuit = copy.deepcopy(circuit)
param_map = {p.name if isinstance(p, Parameter) else str(p): v
for p, v in converted_binds.items()}
for inst in bound_circuit._instructions:
new_params = []
for param in inst.operation._params:
if isinstance(param, Parameter):
if param.name in param_map:
new_params.append(param_map[param.name])
else:
raise ParameterBindingError(
f"No binding provided for parameter {param.name}"
)
elif isinstance(param, ParameterExpression):
expr_param_map = {}
for p in param.parameters:
if p.name in param_map:
expr_param_map[p] = param_map[p.name]
bound_value = param.bind(expr_param_map)
if isinstance(bound_value, (int, float)):
new_params.append(float(bound_value))
elif isinstance(bound_value, ParameterExpression) and bound_value.is_real():
new_params.append(float(bound_value))
else:
new_params.append(bound_value)
else:
new_params.append(param)
inst.operation._params = new_params
return bound_circuit