numpy后端¶
文件位置:numpy.py
这个文件定义了Numpy后端类(NumpyBackend),它继承自Backend抽象类,实现了使用NumPy进行量子电路模拟所需的各种方法。以下是主要方法的功能说明:
- 基础设置方法:
set_dtype(): 设置数值计算的数据类型set_device(): 设置计算设备(仅支持CPU)set_threads(): 设置线程数(NumPy不支持多线程)
- 状态初始化方法:
zero_state(): 创建零态zero_density_matrix(): 创建零密度矩阵identity_density_matrix(): 创建单位密度矩阵plus_state(): 创建叠加态plus_density_matrix(): 创建叠加态的密度矩阵
- 矩阵操作方法:
matrix(): 将门转换为计算基下的矩阵表示matrix_parametrized(): 将参数化门转换为矩阵表示matrix_fused(): 计算融合门的矩阵表示
- 量子态演化方法:
apply_gate(): 对量子态应用量子门apply_gate_density_matrix(): 对密度矩阵应用量子门apply_gate_half_density_matrix(): 对密度矩阵应用半量子门apply_channel(): 应用量子通道到状态向量apply_channel_density_matrix(): 应用量子通道到密度矩阵
- 测量和坍缩方法:
collapse_state(): 根据测量结果坍缩状态向量collapse_density_matrix(): 根据测量结果坍缩密度矩阵
- 误差模拟方法:
reset_error_density_matrix(): 模拟重置误差thermal_error_density_matrix(): 模拟热噪声误差depolarizing_error_density_matrix(): 模拟去极化误差
- 电路执行方法:
execute_circuit(): 执行单个量子电路execute_circuits(): 并行执行多个量子电路execute_circuit_repeated(): 重复执行电路以获取统计结果
- 计算和测量方法:
calculate_probabilities(): 计算测量概率calculate_probabilities_density_matrix(): 计算密度矩阵的测量概率sample_shots(): 生成采样结果samples_to_binary(): 将采样结果转换为二进制表示samples_to_decimal(): 将采样结果转换为十进制表示calculate_frequencies(): 计算频率分布
- 线性代数运算方法:
calculate_vector_norm(): 计算向量范数calculate_matrix_norm(): 计算矩阵范数calculate_overlap(): 计算态之间的重叠calculate_overlap_density_matrix(): 计算密度矩阵之间的重叠calculate_eigenvalues(): 计算矩阵特征值calculate_eigenvectors(): 计算矩阵特征向量calculate_expectation_state(): 计算期望值calculate_expectation_density_matrix(): 计算密度矩阵的期望值calculate_matrix_exp(): 计算矩阵指数calculate_matrix_log(): 计算矩阵对数calculate_matrix_power(): 计算矩阵幂calculate_matrix_sqrt(): 计算矩阵平方根calculate_singular_value_decomposition(): 计算奇异值分解
这些方法共同构成了一个完整的量子电路模拟后端,支持状态向量模拟和密度矩阵模拟,可以处理噪声和测量等操作。
通过execute_circuit()方法执行量子电路¶
execute_circuit(circuit)接受量子电路,并执行量子电路 在circuit.py文件中,定义了execute()方法,该方法调用NumpyBackend的execute_circuit()方法执行量子电路。
def execute(self, initial_state=None, nshots: int = 1000, **kwargs):
if self.compiled:
state = self.compiled.executor(initial_state, nshots)
self._final_state = self.compiled.result(state, nshots)
return self._final_state
backend = _Global.backend()
transpiler = _Global.transpiler()
transpiled_circuit, _ = transpiler(self)
if self.accelerators:
return backend.execute_distributed_circuit(
transpiled_circuit, initial_state, nshots
)
args = [transpiled_circuit, initial_state, nshots]
if backend.name == "hamming_weight":
weight = kwargs["weight"]
args = args[:1] + [weight] + args[1:]
return backend.execute_circuit(*args)
在使用qibo时,你可以使用以下方法来执行多个电路:
from qibo import gates, circuits, backends
# 创建量子电路
circuit = circuits.Circuit(2)
circuit.add(gates.H(0))
circuit.add(gates.CNOT(0, 1))
# 创建Numpy后端
backend = backends.NumpyBackend()
# 执行量子电路
result = backend.execute(circuit)
print(result)
通过这种方式,你可以使用NumpyBackend来执行量子电路,并获取计算结果。
也可以直接调用circuit中的execute方法来执行电路:
import qibo
from qibo import gates, circuits, backends
# 通过以下行,我们设置所需的后端
qibo.set_backend(backend="numpy")
# 创建量子电路
circuit = circuits.Circuit(2)
circuit.add(gates.H(0))
circuit.add(gates.CNOT(0, 1))
# 执行量子电路
result = circuit.execute() # 或者 result = circuit()
print(result)
通过这种方式,你可以直接在量子电路对象上调用execute方法来执行电路,并获取计算结果。
这是由于定义了__call__方法,使得对象可以像函数一样被调用。 当对象被调用时,Python会自动调用__call__方法,并传入参数。
def __call__(self, initial_state=None, nshots=1000, **kwargs):
"""Equivalent to ``circuit.execute``."""
return self.execute(initial_state=initial_state, nshots=nshots, **kwargs)
NumpyBackend 类关系图与模块作用简介¶
关系图¶
plaintext
NumpyBackend (Numpy后端核心类,封装量子计算所需的数值计算与量子操作)
├── __init__ (初始化类,加载基础配置与依赖方法)
│ └── set_dtype (设置数据类型,如complex128/float64)
│ └── cast (数据类型转换,统一输入输出数据格式)
│ └── zeros (创建全零数组/矩阵,用于初始化量子态等场景)
│ └── identity_density_matrix (生成单位密度矩阵,表示纯态的密度矩阵形式)
│ └── matrix (获取量子门的固定矩阵表示,如Hadamard门矩阵)
│ └── apply_gate (将量子门作用于量子态向量,更新量子态)
│ └── execute_circuit (执行完整量子电路,输出计算结果)
│ └── calculate_probabilities (从量子态计算各测量结果的概率分布)
│ └── sample_shots (根据概率分布采样测量结果,模拟量子测量)
│ └── aggregate_shots (聚合多次测量的结果,统计总样本数)
│ └── samples_to_binary (将十进制测量结果转为二进制比特串)
│ └── samples_to_decimal (将二进制比特串测量结果转为十进制)
│ └── calculate_frequencies (统计测量结果的频率分布)
│ └── update_frequencies (基于新采样结果更新已有频率分布)
│ └── sample_frequencies (采样并直接生成测量结果的频率分布)
│ └── apply_bitflips (模拟比特翻转噪声,改变量子态测量结果)
│ └── calculate_vector_norm (计算量子态向量的范数,验证归一化)
│ └── calculate_matrix_norm (计算矩阵范数,用于量子门/密度矩阵分析)
│ └── calculate_overlap (计算两个量子态的重叠度,衡量相似性)
│ └── calculate_overlap_density_matrix (计算两个密度矩阵的重叠度)
│ └── calculate_eigenvalues (计算矩阵特征值,如哈密顿量的能量本征值)
│ └── calculate_eigenvectors (计算矩阵特征向量,如能量本征态)
│ └── calculate_expectation_state (计算哈密顿量在量子态上的期望值)
│ └── calculate_expectation_density_matrix (计算哈密顿量在密度矩阵上的期望值)
│ └── calculate_matrix_exp (计算矩阵指数,用于生成演化算符)
│ └── calculate_matrix_log (计算矩阵对数,用于量子态逆演化等场景)
│ └── calculate_matrix_power (计算矩阵幂,如平方根、负幂等)
│ └── calculate_matrix_sqrt (计算矩阵平方根,用于量子信道构造)
│ └── calculate_singular_value_decomposition (矩阵奇异值分解,用于降维/分析)
│ └── assert_allclose (验证两个数值/矩阵是否近似相等,用于结果校验)
├── qubits (存储量子比特相关配置,如数量、索引等)
├── connectivity (存储量子比特连接关系,用于门操作合法性校验)
├── natives (存储后端原生支持的操作类型,标记兼容的量子门/算法)
├── set_dtype (设置数据类型,如complex128/float64)
│ └── cast (数据类型转换,确保输入符合目标 dtype)
├── set_device (设置计算设备,Numpy后端仅支持CPU)
├── set_threads (设置计算线程数,Numpy后端仅支持单线程)
├── cast (数据类型转换,统一输入输出数据格式)
│ └── is_sparse (先判断输入是否为稀疏矩阵,再决定转换逻辑)
│ └── to_numpy (若输入为稀疏矩阵,先转为密集矩阵再转换类型)
├── is_sparse (检查输入是否为稀疏矩阵,区分稀疏/密集计算逻辑)
├── to_numpy (将稀疏矩阵转为Numpy密集矩阵,适配密集计算接口)
├── compile (编译量子电路函数,Numpy后端暂直接返回原函数)
├── zeros (创建全零数组/矩阵,用于初始化量子态等场景)
├── random_choice (从给定数组随机采样,用于测量结果生成)
├── zero_state (生成零态向量,即所有量子比特处于|0⟩的叠加态)
├── zero_density_matrix (生成零密度矩阵,用于初始化混合态)
├── identity_density_matrix (生成单位密度矩阵,表示纯态的密度矩阵形式)
├── plus_state (生成均匀叠加态向量,如|+⟩⊗n的张量积形式)
├── plus_density_matrix (生成均匀叠加态的密度矩阵)
├── matrix (获取量子门的固定矩阵表示,如Hadamard门矩阵)
│ └── cast (将生成的门矩阵转换为后端指定数据类型)
├── matrix_parametrized (获取参数化量子门的矩阵,如RY门(依赖角度参数))
│ └── cast (将参数化门矩阵转换为后端指定数据类型)
├── matrix_fused (融合多个量子门的矩阵,减少张量积计算次数)
│ └── cast (融合后的矩阵转换为指定数据类型)
│ └── is_sparse (判断输入门矩阵是否为稀疏,决定融合逻辑)
│ └── to_numpy (若输入为稀疏矩阵,先转为密集矩阵再融合)
│ └── block_diag (构造分块对角矩阵,用于多门并行融合)
│ └── np.kron (通过张量积合并多门矩阵,生成融合矩阵)
│ └── np.transpose (调整矩阵维度顺序,确保融合后维度匹配)
├── apply_gate (将量子门作用于量子态向量,更新量子态)
│ └── einsum_utils.control_order (调整控制比特顺序,适配 einsum 索引规则)
│ └── np.einsum (通过爱因斯坦求和约定,高效执行门-态乘法)
│ └── np.concatenate (拼接门作用后的子态,重构完整量子态)
│ └── np.transpose (调整量子态维度顺序,确保门作用维度匹配)
│ └── einsum_utils.reverse_order (反转比特顺序,适配不同索引习惯)
├── apply_gate_density_matrix (将量子门作用于密度矩阵,更新混合态)
│ └── cast (将密度矩阵转换为指定数据类型,适配门矩阵格式)
│ └── np.einsum (通过 einsum 执行门-密度矩阵的双向乘法(UρU†))
│ └── np.conj (计算门矩阵的共轭,用于构造U†)
│ └── einsum_utils.apply_gate_density_matrix_string (生成 einsum 求和字符串)
│ └── einsum_utils.control_order_density_matrix (调整控制比特顺序,适配密度矩阵维度)
├── apply_gate_half_density_matrix (将量子门作用于半密度矩阵,适配特定噪声模型)
│ └── cast (转换半密度矩阵数据类型,适配门矩阵)
│ └── np.einsum (通过 einsum 执行门与半密度矩阵的乘法)
│ └── einsum_utils.apply_gate_density_matrix_string (生成适配半密度矩阵的 einsum 字符串)
├── apply_channel (模拟量子通道对量子态的影响,含噪声建模)
│ └── sample_shots (通过采样模拟通道噪声导致的测量结果波动)
│ └── apply_gate (先应用理想门操作,再叠加通道噪声)
├── apply_channel_density_matrix (模拟量子通道对密度矩阵的影响)
│ └── cast (转换密度矩阵数据类型,适配通道操作)
│ └── apply_gate_density_matrix (先应用理想门操作,再叠加通道噪声)
├── _append_zeros (辅助方法:在量子态向量中插入零元素,适配扩展比特数场景)
│ └── np.expand_dims (扩展态向量维度,为插入零做准备)
│ └── np.concatenate (拼接零向量与原态向量,生成扩展后态)
├── collapse_state (对量子态向量执行测量塌缩,得到确定测量结果)
│ └── cast (转换量子态数据类型,适配塌缩计算)
│ └── samples_to_binary (将塌缩后的十进制结果转为二进制比特串)
│ └── _append_zeros (扩展塌缩后的态向量,匹配原比特数维度)
├── collapse_density_matrix (对密度矩阵执行测量塌缩,更新混合态)
│ └── cast (转换密度矩阵数据类型,适配塌缩计算)
│ └── samples_to_binary (将塌缩后的十进制结果转为二进制比特串)
│ └── _append_zeros (扩展塌缩后的密度矩阵,匹配原比特数维度)
├── reset_error_density_matrix (模拟重置误差:将部分比特重置为|0⟩,更新密度矩阵)
│ └── cast (转换密度矩阵数据类型,适配误差计算)
│ └── partial_trace (对非重置比特执行部分迹,保留目标比特信息)
│ └── zero_density_matrix (生成重置比特的零密度矩阵,替换原态)
│ └── np.tensordot (张量点积:合并保留比特与重置比特的密度矩阵)
│ └── np.transpose (调整密度矩阵维度顺序,确保合并维度匹配)
│ └── apply_gate_density_matrix (对重置后的密度矩阵应用补偿门操作)
├── thermal_error_density_matrix (模拟热噪声:引入热激发导致的态混淆,更新密度矩阵)
│ └── cast (转换密度矩阵数据类型,适配热噪声计算)
│ └── apply_gate (通过门操作模拟热噪声对态的影响)
├── depolarizing_error_density_matrix (模拟退极化噪声:降低态纯度,更新密度矩阵)
│ └── cast (转换密度矩阵数据类型,适配退极化计算)
│ └── partial_trace (对噪声影响的比特执行部分迹,简化计算)
│ └── identity_density_matrix (生成单位矩阵,用于构造退极化项)
│ └── np.tensordot (张量点积:合并理想态与退极化项)
│ └── np.transpose (调整密度矩阵维度顺序,确保合并维度匹配)
├── execute_circuit (执行完整量子电路:初始化态→应用所有门→输出结果)
│ └── cast (转换初始态/门矩阵数据类型,统一计算格式)
│ └── zero_state (默认初始化量子态为零态向量)
│ └── zero_density_matrix (若电路需混合态,初始化密度矩阵为零态)
│ └── apply_gate (对量子态向量依次应用电路中的所有量子门)
│ └── apply_gate_density_matrix (对密度矩阵依次应用电路中的所有量子门)
│ └── CircuitResult (封装电路执行结果,含态向量/测量数据)
│ └── QuantumState (封装输出的量子态,提供概率计算等接口)
│ └── execute_circuit_repeated (若需多次执行,调用重复执行接口)
├── execute_circuits (并行执行多个量子电路,提升批量计算效率)
│ └── parallel_circuits_execution (调用并行计算逻辑,分发电路任务)
├── execute_circuit_repeated (多次重复执行同一量子电路,统计平均结果)
│ └── zero_state (每次执行前初始化量子态为零态向量)
│ └── zero_density_matrix (若需混合态,每次初始化密度矩阵为零态)
│ └── apply_gate (每次执行时对态向量应用电路门操作)
│ └── apply_gate_density_matrix (每次执行时对密度矩阵应用电路门操作)
│ └── CircuitResult (封装单次执行结果,汇总为批量结果)
│ └── MeasurementOutcomes (封装所有重复执行的测量结果,便于统计)
│ └── aggregate_shots (聚合多次执行的测量样本,计算总样本数)
│ └── calculate_frequencies (统计多次执行的测量结果频率分布)
├── execute_distributed_circuit (分布式执行量子电路,暂未实现)
├── calculate_symbolic (将量子态向量转换为符号化字符串,便于可视化)
│ └── to_numpy (先将态向量转为Numpy数组,再提取数值生成符号)
├── calculate_symbolic_density_matrix (将密度矩阵转换为符号化字符串)
│ └── to_numpy (先将密度矩阵转为Numpy数组,再提取数值生成符号)
├── _order_probabilities (根据量子比特顺序重新排列概率分布,匹配测量比特序)
│ └── np.transpose (调整概率数组维度顺序,对齐比特索引)
├── calculate_probabilities (从量子态向量计算各测量结果的概率(|ψ|²))
│ └── cast (转换量子态数据类型,适配概率计算)
│ └── np.abs (计算态向量各元素的绝对值,用于求模平方)
│ └── np.sum (对未测量比特的维度求和,得到测量比特的概率)
│ └── _order_probabilities (按比特序重新排列概率分布)
├── calculate_probabilities_density_matrix (从密度矩阵计算测量概率(Tr(ρ|i⟩⟨i|)))
│ └── np.reshape (重塑密度矩阵维度,适配概率计算格式)
│ └── np.transpose (调整密度矩阵维度顺序,对齐比特索引)
│ └── np.einsum (通过 einsum 计算迹,得到各测量结果概率)
│ └── _order_probabilities (按比特序重新排列概率分布)
├── set_seed (设置随机数种子,确保测量采样结果可复现)
├── sample_shots (根据概率分布采样指定次数,生成测量结果)
│ └── random_choice (调用随机采样函数,按概率选择测量结果)
├── aggregate_shots (将多次采样的结果合并,统计总样本数)
│ └── cast (转换样本数据类型,统一合并格式)
├── samples_to_binary (将十进制测量结果转为二进制比特串,如5→101)
│ └── np.arange (生成比特位索引,用于逐位提取二进制值)
│ └── np.right_shift (右移十进制数,提取对应比特位的值)
│ └── np.mod (对右移后的值取模2,得到0/1比特值)
├── samples_to_decimal (将二进制比特串转为十进制数,如101→5)
│ └── np.arange (生成比特权重(2^n),用于计算十进制值)
│ └── np.matmul (通过矩阵乘法,将比特值与权重相乘求和)
├── calculate_frequencies (统计测量结果中各值出现的频率(次数/总样本))
│ └── np.unique (识别唯一的测量结果,并统计各结果出现次数)
├── update_frequencies (用新采样的结果更新已有频率分布,累加次数)
│ └── sample_shots (生成新的采样结果,用于更新频率)
│ └── np.unique (统计新结果的次数,与原频率合并)
├── sample_frequencies (直接采样并生成测量结果的频率分布,跳过中间样本存储)
│ └── zeros (初始化频率数组,用于存储各结果的次数)
│ └── update_frequencies (基于采样结果更新频率数组)
├── apply_bitflips (模拟比特翻转噪声:随机翻转部分比特的测量结果)
│ └── cast (转换测量结果数据类型,适配翻转计算)
│ └── np.random.random (生成随机数,判断是否翻转对应比特)
├── calculate_vector_norm (计算量子态向量的p-范数,验证态的归一化(||ψ||=1))
│ └── cast (转换向量数据类型,适配范数计算)
│ └── np.linalg.norm (调用Numpy范数函数,计算指定范数)
├── calculate_matrix_norm (计算矩阵的p-范数,用于分析门/密度矩阵的性质)
│ └── cast (转换矩阵数据类型,适配范数计算)
│ └── np.linalg.norm (调用Numpy范数函数,计算指定范数)
├── calculate_overlap (计算两个量子态的重叠度(|⟨ψ|φ⟩|²),衡量态的相似性)
│ └── cast (统一两个态的数据类型,适配内积计算)
│ └── np.conj (计算第一个态的共轭,用于内积计算)
│ └── np.sum (对共轭态与第二个态的乘积求和,得到内积)
├── calculate_overlap_density_matrix (计算两个密度矩阵的重叠度(Tr(√(√ρσ√ρ))²))
│ └── cast (统一两个密度矩阵的数据类型,适配迹计算)
│ └── np.conj (计算第一个密度矩阵的共轭,用于重叠度公式)
│ └── np.trace (计算矩阵乘积的迹,得到重叠度核心项)
│ └── np.matmul (执行密度矩阵间的乘法,构造迹计算的矩阵)
├── calculate_eigenvalues (计算矩阵的特征值,如哈密顿量的能量本征值)
│ └── is_sparse (判断矩阵是否为稀疏,选择稀疏/密集特征值算法)
│ └── calculate_eigenvectors (若需特征向量,同步调用特征向量计算接口)
│ └── np.linalg.eigvalsh (对Hermitian矩阵,调用高效实特征值算法)
│ └── np.linalg.eigvals (对非Hermitian矩阵,调用通用特征值算法)
├── calculate_eigenvectors (计算矩阵的特征向量,如能量本征态)
│ └── is_sparse (判断矩阵是否为稀疏,选择稀疏/密集特征向量算法)
│ └── to_numpy (若为稀疏矩阵,先转为密集矩阵再计算)
│ └── scipy.sparse.linalg.eigsh (对稀疏Hermitian矩阵,调用高效特征向量算法)
│ └── np.linalg.eigh (对密集Hermitian矩阵,调用高效实特征向量算法)
│ └── np.linalg.eig (对非Hermitian矩阵,调用通用特征向量算法)
├── calculate_expectation_state (计算哈密顿量H在量子态ψ上的期望值(⟨ψ|H|ψ⟩))
│ └── np.conj (计算ψ的共轭,用于期望值公式)
│ └── np.sum (对共轭态、H、ψ的乘积求和,得到期望值)
│ └── np.square (对中间结果求平方,适配部分期望值计算场景)
│ └── np.abs (对结果取绝对值,确保期望值为实数)
├── calculate_expectation_density_matrix (计算H在密度矩阵ρ上的期望值(Tr(Hρ)))
│ └── cast (统一H与ρ的数据类型,适配迹计算)
│ └── np.real (取迹结果的实部,确保期望值为实数)
│ └── np.trace (计算H与ρ乘积的迹,得到期望值)
├── calculate_matrix_exp (计算矩阵指数(e^A),用于生成量子演化算符(e^(-iHt)))
│ └── cast (转换矩阵数据类型,适配指数计算)
│ └── is_sparse (判断矩阵是否为稀疏,选择稀疏/密集指数算法)
│ └── scipy.sparse.linalg.expm (对稀疏矩阵,调用稀疏矩阵指数算法)
│ └── scipy.linalg.expm (对密集矩阵,调用密集矩阵指数算法)
│ └── np.transpose (调整矩阵维度顺序,适配指数计算)
│ └── np.conj (计算矩阵共轭,用于构造Hermitian矩阵的指数)
├── calculate_matrix_log (计算矩阵对数(log(A)),用于量子态逆演化等场景)
│ └── cast (转换矩阵数据类型,适配对数计算)
│ └── to_numpy (若为稀疏矩阵,先转为密集矩阵再计算)
│ └── logm (调用Scipy矩阵对数函数,计算矩阵对数)
│ └── np.diag (提取对角矩阵元素,用于对角矩阵的对数计算优化)
│ └── np.log (对对角元素求对数,快速计算对角矩阵的对数)
│ └── np.transpose (调整矩阵维度顺序,适配对数计算)
│ └── np.conj (计算矩阵共轭,用于构造Hermitian矩阵的对数)
├── calculate_matrix_power (计算矩阵幂(A^k),k可为整数/分数/负数)
│ └── np.linalg.det (计算矩阵行列式,判断矩阵是否奇异(行列式为0))
│ └── calculate_negative_power_singular_matrix (对奇异矩阵,计算负幂的特殊逻辑)
│ └── fractional_matrix_power (对分数幂,调用专用分数矩阵幂算法)
├── calculate_matrix_sqrt (计算矩阵平方根(A^(1/2)),基于矩阵幂接口实现)
│ └── calculate_matrix_power (调用矩阵幂接口,传入幂次1/2)
├── calculate_singular_value_decomposition (对矩阵做SVD分解(A=UΣV^H),用于降维/矩阵分析)
│ └── np.linalg.svd (调用Numpy SVD函数,执行奇异值分解)
├── calculate_jacobian_matrix (计算量子电路参数的雅可比矩阵,用于参数优化)
└── assert_allclose (验证两个数值/矩阵是否近似相等,用于结果校验与测试)
└── to_numpy (将输入转为Numpy数组,统一校验格式)
└── np.testing.assert_allclose (调用Numpy断言函数,判断是否在误差范围内相等)
模块作用简介¶
初始化与配置
__init__: 初始化NumpyBackend类,设置基本属性和参数。set_dtype: 设置数据类型(如complex128、float64等)。set_device: 设置计算设备(仅支持 CPU)。set_threads: 设置线程数(仅支持单线程)。set_seed: 设置随机数种子。
基础工具方法
cast: 将输入数据转换为目标数据类型(实现位置:e:\量子计算模拟器\qibo\numpy.py第80-90行)。is_sparse: 检查输入是否为稀疏矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第92-93行)。to_numpy: 将稀疏矩阵转换为密集矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第95-98行)。zeros: 创建全零数组或矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第103-106行)。random_choice: 从给定数组中随机采样(实现位置:e:\量子计算模拟器\qibo\numpy.py第108-109行)。_order_probabilities: 根据量子比特顺序重新排列概率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第653-661行)。
量子态生成
zero_state: 生成零态向量(实现位置:e:\量子计算模拟器\qibo\numpy.py第111-114行)。zero_density_matrix: 生成零密度矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第116-119行)。identity_density_matrix: 生成单位密度矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第121-125行)。plus_state: 生成均匀叠加态(实现位置:e:\量子计算模拟器\qibo\numpy.py第127-130行)。plus_density_matrix: 生成均匀叠加态的密度矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第132-135行)。
量子门操作
matrix: 获取量子门的矩阵表示(实现位置:e:\量子计算模拟器\qibo\numpy.py第137-143行)。matrix_parametrized: 获取参数化量子门的矩阵表示(实现位置:e:\量子计算模拟器\qibo\numpy.py第145-158行)。matrix_fused: 融合多个量子门的矩阵表示(实现位置:e:\量子计算模拟器\qibo\numpy.py第160-195行)。apply_gate: 应用量子门到量子态(实现位置:e:\量子计算模拟器\qibo\numpy.py第197-221行)。apply_gate_density_matrix: 应用量子门到密度矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第223-268行)。apply_gate_half_density_matrix: 应用量子门到半密度矩阵(实现位置:e:\量子计算模拟器\qibo\numpy.py第270-287行)。
量子通道与噪声模拟
apply_channel: 模拟量子通道对量子态的影响(实现位置:e:\量子计算模拟器\qibo\numpy.py第289-295行)。apply_channel_density_matrix: 模拟量子通道对密度矩阵的影响(实现位置:e:\量子计算模拟器\qibo\numpy.py第297-302行)。reset_error_density_matrix: 模拟重置误差(实现位置:e:\量子计算模拟器\qibo\numpy.py第349-368行)。thermal_error_density_matrix: 模拟热噪声(实现位置:e:\量子计算模拟器\qibo\numpy.py第370-374行)。depolarizing_error_density_matrix: 模拟退极化噪声(实现位置:e:\量子计算模拟器\qibo\numpy.py第376-408行)。
测量与塌缩
collapse_state: 对量子态进行测量并塌缩(实现位置:e:\量子计算模拟器\qibo\numpy.py第315-328行)。collapse_density_matrix: 对密度矩阵进行测量并塌缩(实现位置:e:\量子计算模拟器\qibo\numpy.py第330-347行)。calculate_probabilities: 计算量子态的概率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第663-668行)。calculate_probabilities_density_matrix: 计算密度矩阵的概率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第670-679行)。sample_shots: 根据概率分布采样测量结果(实现位置:e:\量子计算模拟器\qibo\numpy.py第684-687行)。aggregate_shots: 聚合多次测量结果(实现位置:e:\量子计算模拟器\qibo\numpy.py第689-690行)。samples_to_binary: 将十进制测量结果转换为二进制形式(实现位置:e:\量子计算模拟器\qibo\numpy.py第692-696行)。samples_to_decimal: 将二进制测量结果转换为十进制形式(实现位置:e:\量子计算模拟器\qibo\numpy.py第698-703行)。
频率与统计
calculate_frequencies: 计算测量结果的频率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第705-710行)。update_frequencies: 更新频率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第712-716行)。sample_frequencies: 采样并生成频率分布(实现位置:e:\量子计算模拟器\qibo\numpy.py第718-730行)。
数值计算
calculate_vector_norm: 计算向量范数(实现位置:e:\量子计算模拟器\qibo\numpy.py第744-746行)。calculate_matrix_norm: 计算矩阵范数(实现位置:e:\量子计算模拟器\qibo\numpy.py第748-750行)。calculate_overlap: 计算两个量子态之间的重叠(实现位置:e:\量子计算模拟器\qibo\numpy.py第752-755行)。calculate_overlap_density_matrix: 计算两个密度矩阵之间的重叠(实现位置:e:\量子计算模拟器\qibo\numpy.py第757-760行)。calculate_eigenvalues: 计算矩阵的特征值(实现位置:e:\量子计算模拟器\qibo\numpy.py第762-771行)。calculate_eigenvectors: 计算矩阵的特征向量(实现位置:e:\量子计算模拟器\qibo\numpy.py第773-783行)。calculate_expectation_state: 计算哈密顿量在量子态上的期望值(实现位置:e:\量子计算模拟器\qibo\numpy.py第785-791行)。calculate_expectation_density_matrix: 计算哈密顿量在密度矩阵上的期望值(实现位置:e:\量子计算模拟器\qibo\numpy.py第793-798行)。calculate_matrix_exp: 计算矩阵指数(实现位置:e:\量子计算模拟器\qibo\numpy.py第800-818行)。calculate_matrix_log: 计算矩阵对数(实现位置:e:\量子计算模拟器\qibo\numpy.py第820-832行)。calculate_matrix_power: 计算矩阵幂(实现位置:e:\量子计算模拟器\qibo\numpy.py第834-854行)。calculate_matrix_sqrt: 计算矩阵平方根(实现位置:e:\量子计算模拟器\qibo\numpy.py第856-857行)。calculate_singular_value_decomposition: 计算奇异值分解(实现位置:e:\量子计算模拟器\qibo\numpy.py第859-860行)。
电路执行
execute_circuit: 执行量子电路(实现位置:e:\量子计算模拟器\qibo\numpy.py第410-508行)。execute_circuits: 并行执行多个量子电路(实现位置:e:\量子计算模拟器\qibo\numpy.py第510-517行)。execute_circuit_repeated: 多次重复执行量子电路(实现位置:e:\量子计算模拟器\qibo\numpy.py第519-614行)。execute_distributed_circuit: 分布式执行量子电路(未实现,位置:e:\量子计算模拟器\qibo\numpy.py第616-619行)。
符号化与验证
calculate_symbolic: 将量子态符号化为字符串形式(实现位置:e:\量子计算模拟器\qibo\numpy.py第621-634行)。calculate_symbolic_density_matrix: 将密度矩阵符号化为字符串形式(实现位置:e:\量子计算模拟器\qibo\numpy.py第636-651行)。assert_allclose: 验证两个值是否接近(实现位置:e:\量子计算模拟器\qibo\numpy.py第871-878行)。
其他
_append_zeros: 辅助方法,用于在状态向量中插入零(实现位置:e:\量子计算模拟器\qibo\numpy.py第304-313行)。compile: 编译函数(当前实现直接返回输入函数,位置:e:\量子计算模拟器\qibo\numpy.py第100-101行)。
NumpyBackend 类功能总结¶
功能总结¶
NumpyBackend 类是量子计算框架 qibo 的后端实现之一(实现位置:e:\量子计算模拟器\qibo\numpy.py 第19-878行),基于 numpy(引用位置:e:\量子计算模拟器\qibo\numpy.py 第0-0行)和 scipy 提供量子态模拟、量子门操作、测量和噪声模拟等功能。它主要用于在经典计算机上模拟量子计算过程,支持以下核心功能:
量子态初始化与操作
- 生成零态、均匀叠加态、单位密度矩阵等初始量子态。
- 支持对量子态和密度矩阵进行量子门操作(如单比特门、双比特门、参数化门等)。
量子门与通道
- 将量子门转换为矩阵表示,并应用到量子态或密度矩阵。
- 支持带控制的量子门操作。
- 模拟量子通道(如退极化噪声、热噪声、重置误差等)。
测量与采样
- 对量子态或密度矩阵进行测量,计算概率分布。
- 支持多次采样以获取统计结果(如频率分布、样本集合)。
- 支持测量塌缩后的量子态更新。
电路执行
- 执行量子电路,支持多次重复执行以模拟噪声环境。
- 支持分布式执行(未实现)。
数值计算
- 提供矩阵运算工具(如矩阵指数、矩阵对数、特征值分解、奇异值分解等)。
- 计算量子态之间的重叠、期望值等。
符号化与验证
- 将量子态或密度矩阵符号化为字符串形式。
- 验证两个量子态或结果是否接近。
最核心的函数¶
以下是 NumpyBackend 类(实现位置:e:\量子计算模拟器\qibo\numpy.py 第19-878行)中最核心的函数及其作用:
1. 量子态生成¶
zero_state:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第111-114行 - 功能:生成零态向量(所有量子比特处于|0⟩态的张量积形式)。
- 核心性:量子电路模拟中最基础的初始态来源,几乎所有电路执行都需先调用此函数初始化。
- 实现位置:
zero_density_matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第116-119行 - 功能:生成零密度矩阵(对应零态向量的密度矩阵形式,即|0⟩⟨0|⊗n)。
- 核心性:混合态模拟的基础初始输入,用于需要考虑噪声的量子计算场景。
- 实现位置:
identity_density_matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第121-125行 - 功能:生成单位密度矩阵(对应完全混合态,迹为1的对角矩阵)。
- 核心性:用于模拟最大混乱度的混合态,是噪声模型中"完全退极化"场景的基础。
- 实现位置:
2. 量子门操作¶
matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第137-143行 - 功能:将非参数化量子门(如Hadamard、CNOT门)转换为对应的矩阵表示。
- 核心性:所有量子门作用于量子态的前提——只有先将门转为矩阵,才能通过矩阵乘法更新量子态。
- 实现位置:
matrix_parametrized:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第145-158行 - 功能:将参数化量子门(如RY、RZ门,依赖角度参数)转换为矩阵表示。
- 核心性:支持变分量子算法(如VQE、QAOA)的关键,可根据输入参数动态生成门矩阵。
- 实现位置:
apply_gate:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第197-221行 - 功能:将量子门矩阵应用到量子态向量,通过张量积和矩阵乘法更新态。
- 核心性:量子计算"状态演化"的核心逻辑,直接决定量子门操作的正确性。
- 实现位置:
apply_gate_density_matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第223-268行 - 功能:将量子门矩阵应用到密度矩阵(通过UρU†公式更新,U为门矩阵,U†为共轭转置)。
- 核心性:混合态演化的核心,是噪声模拟中"门作用于混合态"的关键步骤。
- 实现位置:
3. 测量与采样¶
calculate_probabilities:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第663-668行 - 功能:从量子态向量计算各测量结果的概率(对态向量元素取模平方|ψ_i|²,再按比特序排列)。
- 核心性:量子测量的基础——所有采样、频率统计都需先基于此函数得到概率分布。
- 实现位置:
sample_shots:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第684-687行 - 功能:根据概率分布采样指定次数(shots)的测量结果,模拟真实量子计算机的测量随机性。
- 核心性:连接"理论概率"与"实验样本"的关键,是模拟量子测量统计特性的核心。
- 实现位置:
collapse_state:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第315-328行 - 功能:对量子态向量执行测量并塌缩——根据测量结果保留对应量子态分量,其他分量置零并重新归一化。
- 核心性:模拟量子测量"波函数塌缩"特性的核心,支持需要"测量后继续演化"的电路场景。
- 实现位置:
4. 电路执行¶
execute_circuit:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第410-508行 - 功能:执行完整量子电路——初始化量子态→按顺序应用所有量子门→计算测量概率/采样结果→封装输出。
- 核心性:量子电路模拟的"总入口",用户无需手动调用态初始化、门应用等零散函数,直接输入电路即可得到结果。
- 实现位置:
execute_circuit_repeated:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第519-614行 - 功能:多次重复执行同一量子电路,聚合所有次的测量结果(如统计总频率、平均期望值)。
- 核心性:噪声模拟和统计分析的关键——通过多次重复执行,模拟噪声对结果的影响,降低随机误差。
- 实现位置:
5. 数值计算¶
calculate_matrix_exp:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第800-818行 - 功能:计算矩阵指数(e^A),支持稀疏/密集矩阵,对Hermitian矩阵有优化。
- 核心性:量子动力学模拟的基础——用于生成量子演化算符(如e^(-iHt),H为哈密顿量,t为演化时间)。
- 实现位置:
calculate_matrix_log:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第820-832行 - 功能:计算矩阵对数(log(A)),支持对角矩阵快速计算和一般矩阵的数值解法。
- 核心性:支持量子态逆演化、熵计算等高级场景,如从演化后的密度矩阵反推初始态。
- 实现位置:
calculate_eigenvalues:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第762-771行 - 功能:计算矩阵的特征值,对Hermitian矩阵调用高效实特征值算法,对非Hermitian矩阵调用通用算法。
- 核心性:量子力学分析的基础——如计算哈密顿量的能量本征值、密度矩阵的纯度(特征值之和的平方)。
- 实现位置:
calculate_singular_value_decomposition:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第859-860行 - 功能:对矩阵执行奇异值分解(SVD,A=UΣV^H),返回左奇异向量、奇异值、右奇异向量。
- 核心性:量子态降维、量子信道容量分析的关键,如通过SVD提取量子态的主要分量。
- 实现位置:
6. 噪声模拟¶
reset_error_density_matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第349-368行 - 功能:模拟量子比特"重置误差"——将指定比特强行重置为|0⟩态,同时引入一定概率的错误(如重置为|1⟩)。
- 核心性:真实量子硬件中常见噪声的模拟核心,如量子计算机读取后重置比特的误差。
- 实现位置:
depolarizing_error_density_matrix:- 实现位置:
e:\量子计算模拟器\qibo\numpy.py第376-408行 - 功能:模拟"退极化噪声"——通过混合单位矩阵和泡利矩阵项,降低密度矩阵的纯度(即增加混乱度)。
- 核心性:最基础的量子噪声模型之一,可模拟量子态与环境相互作用导致的信息丢失。
- 实现位置:
总结¶
NumpyBackend 类(实现位置:e:\量子计算模拟器\qibo\numpy.py 第19-878行)的核心功能在于提供高效的量子态模拟和操作能力,最核心的函数可归纳为以下几类,共同支撑从量子态初始化到测量、噪声模拟的完整流程:
| 功能类别 | 核心函数列表 |
|---|---|
| 量子态生成 | zero_state(111-114行)、zero_density_matrix(116-119行) |
| 量子门操作 | matrix(137-143行)、apply_gate(197-221行)、apply_gate_density_matrix(223-268行) |
| 测量与采样 | calculate_probabilities(663-668行)、sample_shots(684-687行)、collapse_state(315-328行) |
| 电路执行 | execute_circuit(410-508行)、execute_circuit_repeated(519-614行) |
| 数值计算 | calculate_matrix_exp(800-818行)、calculate_eigenvalues(762-771行)、calculate_singular_value_decomposition(859-860行) |
| 噪声模拟 | reset_error_density_matrix(349-368行)、depolarizing_error_density_matrix(376-408行) |
class NumpyBackend(Backend):¶
它继承自Backend抽象类,实现了使用NumPy进行量子电路模拟所需的各种方法。
初始化¶
def __init__(self):
"""初始化NumpyBackend类,设置基本属性和参数"""
super().__init__()
self.np = np # 导入numpy库
self.name = "numpy" # 设置后端名称
self.matrices = NumpyMatrices(self.dtype) # 初始化矩阵类
self.tensor_types = np.ndarray # 设置张量类型
self.versions = {"qibo": __version__, "numpy": self.np.__version__} # 设置版本信息
self.numeric_types = ( # 设置支持的数值类型
int,
float,
complex,
np.int32,
np.int64,
np.float32,
np.float64,
np.complex64,
np.complex128,
)
在NumpyBackend类的__init__方法中,super().__init__()的作用是调用父类Backend的初始化方法,确保父类的属性被正确初始化。让我详细解释这个过程:
super().__init__()的作用¶
继承链初始化:
super().__init__()调用父类(Backend)的__init__方法- 确保在子类(NumpyBackend)的初始化过程中,父类的初始化逻辑也被执行
- 这是Python面向对象编程中标准的继承初始化模式
父类初始化的数据: 根据Backend类的定义,
super().__init__()会初始化以下属性:self.name = "backend" # 后端名称,默认为"backend" self.platform = None # 平台信息,初始为None self.dtype = "complex128" # 默认数据类型为complex128 self.matrices = None # 矩阵操作对象,初始为None self.device = "/CPU:0" # 计算设备,默认为CPU self.nthreads = 1 # 线程数,默认为1 self.supports_multigpu = False # 多GPU支持,默认为False self.oom_error = MemoryError # 内存不足错误类型
数据初始化流程¶
父类初始化阶段:
- 首先执行Backend类的
__init__方法 - 设置上述默认属性值
- 这些属性构成了所有后端类的基础配置
- 首先执行Backend类的
子类重写阶段: 在NumpyBackend中,部分父类属性被重写为特定于numpy后端的值:
self.name = "numpy" # 将后端名称改为"numpy" self.matrices = NumpyMatrices(self.dtype) # 初始化numpy矩阵操作对象 self.tensor_types = np.ndarray # 设置张量类型为numpy数组
新增属性阶段: NumpyBackend还添加了一些特定属性:
self.np = np # 保存numpy库引用 self.versions = {"qibo": __version__, "numpy": self.np.__version__} # 版本信息 self.numeric_types = ( # 支持的数值类型 int, float, complex, # Python基本类型 np.int32, np.int64, # Numpy整数类型 np.float32, np.float64, # Numpy浮点类型 np.complex64, np.complex128, # Numpy复数类型 )
数据流向总结¶
继承的数据:
- 从Backend类继承基础配置属性
- 这些属性定义了后端的基本行为和限制
修改的数据:
- name:从"backend"改为"numpy"
- matrices:从None改为NumpyMatrices实例
- 添加了tensor_types属性
新增的数据:
- np:numpy库引用
- versions:版本信息字典
- numeric_types:支持的数值类型元组
这种初始化模式确保了:
- 所有后端类都有统一的基础接口
- 每个具体后端可以自定义特定行为
- 代码复用和扩展性得到平衡
允许用户调用的设置整个类的属性的精度的函数set_dtype()¶
def set_dtype(self, dtype):
if dtype not in ("complex128", "complex64", "float64", "float32"):
raise_error(
ValueError,
f"Unknown ``dtype`` ``{dtype}``."
+ "``dtype`` must be one of the following options: 'complex128', 'complex64',"
+ "'float64', 'float32'",
)
if dtype != self.dtype:
self.dtype = dtype
if self.matrices:
self.matrices = self.matrices.__class__(self.dtype)
数据类型转换函数cast()¶
def cast(self, x, dtype=None, copy: bool = False):
if dtype is None:
dtype = self.dtype
if isinstance(x, self.tensor_types):
return x.astype(dtype, copy=copy)
if self.is_sparse(x):
return x.astype(dtype, copy=copy)
return np.asarray(x, dtype=dtype, copy=copy if copy else None)
首先,这个 cast 函数的主要作用是将输入数据 x 转换为指定的数据类型 dtype。函数会根据输入数据的类型采用不同的转换方法。
让我解释一下涉及的几个关键函数:
astype()函数:- 用于 NumPy 数组、张量或稀疏矩阵
- 创建一个具有指定数据类型的新数组/矩阵
- 当
copy=True时,总是创建副本;当copy=False时,只有在必要时才创建副本
asarray()函数:- 将输入转换为 NumPy 数组
- 如果输入已经是 NumPy 数组且 dtype 匹配,则不创建副本(除非明确要求)
- 对于非数组输入,会创建一个新数组
现在,让我通过几个例子来说明这个 cast 函数的行为:
示例 1:处理张量(如 PyTorch 或 TensorFlow 张量)¶
import torch
import numpy as np
# 假设 self.tensor_types 包含 torch.Tensor
# self.dtype 默认为 float32
# 创建一个 PyTorch 张量
tensor = torch.tensor([1, 2, 3], dtype=torch.int32)
# 调用 cast 函数
result = cast(tensor) # dtype=None, copy=False
# 这会执行 x.astype(dtype, copy=copy)
# 结果是一个 float32 类型的 PyTorch 张量
print(result) # tensor([1., 2., 3.])
print(result.dtype) # torch.float32
示例 2:处理稀疏矩阵¶
from scipy import sparse
# 创建一个稀疏矩阵
sparse_matrix = sparse.csr_matrix([[1, 0], [0, 2]], dtype=np.int32)
# 调用 cast 函数
result = cast(sparse_matrix, dtype=np.float64)
# 这会执行 x.astype(dtype, copy=copy)
# 结果是一个 float64 类型的稀疏矩阵
print(result)
# <Compressed Sparse Row sparse matrix of dtype 'float64'
# with 2 stored elements and shape (2, 2)>
print(result.dtype) # float64
示例 3:处理普通 Python 列表¶
# 创建一个 Python 列表
python_list = [1, 2, 3]
# 调用 cast 函数
result = cast(python_list, dtype=np.float32)
# 这会执行 np.asarray(x, dtype=dtype, copy=copy if copy else None)
# 结果是一个 NumPy 数组
print(result) # [1. 2. 3.]
print(result.dtype) # float32
print(type(result)) # <class 'numpy.ndarray'>
示例 4:copy 参数的影响¶
import numpy as np
# 创建一个 NumPy 数组
arr = np.array([1, 2, 3], dtype=np.int32)
# 不创建副本
result_no_copy = cast(arr, dtype=np.int32, copy=False)
# 因为 dtype 相同且 copy=False,不会创建副本
print(np.may_share_memory(arr, result_no_copy)) # True
# 创建副本
result_with_copy = cast(arr, dtype=np.int32, copy=True)
# 即使 dtype 相同,因为 copy=True,也会创建副本
print(np.may_share_memory(arr, result_with_copy)) # False
总结一下,cast 函数的作用是根据输入数据的类型,选择合适的方法将其转换为指定的数据类型:
- 对于张量或稀疏矩阵,使用它们的
astype方法 - 对于其他类型的数据,使用 NumPy 的
asarray函数
这种设计使得函数可以灵活处理不同类型的输入,同时保持了高效的类型转换。
判断稀疏矩阵的函数is_sparse()¶
这段代码是一个Python方法,名为is_sparse,用于检查输入对象x是否是稀疏矩阵(sparse matrix)。让我详细解释一下:
代码解释¶
方法定义:
def is_sparse(self, x):- 定义了一个名为is_sparse的方法,它接受两个参数:self(表示类的实例)和x(要检查的对象)。
方法功能:
return sparse.issparse(x)- 调用sparse模块中的issparse函数,检查x是否为稀疏矩阵,并返回检查结果(布尔值:True或False)。
实现原理¶
稀疏矩阵是一种特殊类型的矩阵,其中大部分元素为零。为了节省存储空间和计算资源,稀疏矩阵通常只存储非零元素及其位置。在Python中,scipy.sparse模块提供了处理稀疏矩阵的功能。
issparse函数通过检查输入对象是否是scipy.sparse模块中定义的稀疏矩阵类型(如csr_matrix、csc_matrix等)的实例来判断其是否为稀疏矩阵。
用途¶
这个方法的主要用途是:
- 在处理矩阵运算前,判断输入矩阵是否为稀疏矩阵,以便选择适当的处理方法
- 在需要优化存储和计算的场景中,帮助决定是否应该将普通矩阵转换为稀疏矩阵
- 在编写支持稀疏和密集矩阵的通用算法时,用于分支处理
注意事项¶
使用此方法前,需要确保已导入
sparse模块,通常是from scipy import sparse或import scipy.sparse as sparse。此方法只能识别
scipy.sparse中定义的稀疏矩阵类型,不能识别其他库(如numpy)中的稀疏矩阵实现。如果输入
x不是矩阵类型,方法将返回False。在性能敏感的代码中,频繁调用此方法可能会带来一定的开销。
工作流程图¶
flowchart TD
Start(("开始")) --> Input["输入对象x"]
Input --> Check{"调用sparse.issparse(x)检查x是否为稀疏矩阵"}
Check --> |"是稀疏矩阵"| ReturnTrue["返回True"]
Check --> |"不是稀疏矩阵"| ReturnFalse["返回False"]
ReturnTrue --> End(("END"))
ReturnFalse --> End(("END"))
to_numpy() 将数据转换为numpy¶
这个方法的主要目的是将输入x转换为NumPy数组格式。下面是对代码的详细解释:
def to_numpy(self, x):
if self.is_sparse(x):
return x.toarray()
return x
实现原理¶
- 方法定义:
def to_numpy(self, x)定义了一个方法,它接受两个参数:self(表示类的实例)和x(要转换的数据)。 - 稀疏性检查:
self.is_sparse(x)调用类中的另一个方法is_sparse,用于检查输入x是否是稀疏矩阵(sparse matrix)。 - 转换逻辑:
- 如果
x是稀疏矩阵,则调用x.toarray()方法将其转换为密集的NumPy数组。 - 如果
x不是稀疏矩阵,则直接返回x(假设它已经是NumPy数组或类似格式)。
- 如果
用途¶
- 数据格式统一:在机器学习或数据处理流程中,可能需要处理不同格式的数据(稀疏矩阵或密集矩阵)。此方法确保所有数据都转换为NumPy数组格式,便于后续处理。
- 兼容性:某些库或函数可能只接受NumPy数组作为输入,此方法可以确保输入数据的兼容性。
注意事项¶
- 依赖性:假设
self.is_sparse(x)方法已正确定义,能够正确判断输入是否为稀疏矩阵。 - 输入类型:如果输入
x既不是稀疏矩阵也不是NumPy数组,直接返回x可能导致后续操作失败。因此,调用此方法时需确保输入类型正确。 - 性能:稀疏矩阵转换为密集矩阵(
toarray())可能会消耗大量内存,尤其是当稀疏矩阵非常大时。需谨慎使用,避免内存不足。
工作流程图¶
以下是代码的工作流程图,使用Mermaid语法绘制:
flowchart TD
Start(("开始")) --> Input["输入x"]
Input --> CheckSparse{"x是稀疏矩阵吗?"}
CheckSparse --> |"是"| Convert["调用x.toarray()"]
CheckSparse --> |"否"| ReturnX["直接返回x"]
Convert --> ReturnX
ReturnX --> END(("结束"))
matrix(self, gate) 将量子门转换为矩阵¶
def matrix(self, gate):
"""Convert a gate to its matrix representation in the computational basis."""
name = gate.__class__.__name__
_matrix = getattr(self.matrices, name)
if callable(_matrix):
_matrix = _matrix(2 ** len(gate.target_qubits))
return self.cast(_matrix, dtype=_matrix.dtype)
这段代码是一个Python方法,用于将量子门(gate)转换为其在计算基(computational basis)中的矩阵表示。让我详细解释一下:
代码功能¶
这个方法的主要目的是将量子门对象转换为对应的矩阵表示形式。在量子计算中,量子门可以表示为作用于量子比特上的酉矩阵,这个方法就是实现这种转换的核心部分。
参数¶
gate: 量子门对象,这是一个输入参数,代表需要转换的量子门。
返回值¶
返回量子门对应的矩阵表示。
实现原理¶
获取量子门类型:
name = gate.__class__.__name__
通过获取量子门对象的类名来确定是哪种类型的量子门。
获取矩阵表示:
_matrix = getattr(self.matrices, name)
使用
getattr从self.matrices对象中获取对应量子门类型的矩阵。这里假设self.matrices是一个包含各种量子门矩阵表示的对象或模块。处理可调用矩阵:
if callable(_matrix): _matrix = _matrix(2 ** len(gate.target_qubits))
检查获取到的矩阵是否是可调用的(即一个函数)。如果是,则调用该函数,传入参数
2 ** len(gate.target_qubits),这表示量子门作用的目标量子比特数所对应的矩阵维度(n个量子比特对应2^n维矩阵)。类型转换:
return self.cast(_matrix, dtype=_matrix.dtype)
使用
self.cast方法将矩阵转换为适当的数据类型,保持原有的数据类型不变。
用途¶
这个方法在量子计算框架中非常重要,它允许将抽象的量子门操作转换为具体的矩阵表示,从而可以用于量子态的演化计算、量子电路的模拟等。
注意事项¶
- 此方法假设
self.matrices对象包含了所有可能需要的量子门矩阵表示。 - 对于可调用的矩阵表示,方法假设它们接受一个参数,即矩阵的维度。
self.cast方法的具体实现可能会影响矩阵的最终表示形式。- 此方法依赖于量子门对象具有
target_qubits属性,用于确定矩阵的维度。
在NumpyMatrices类中,参数化门通过特殊的方式实现,使得我们之前讨论的matrix方法可以工作。让我详细解释这个机制:
参数化门的实现方式¶
在NumpyMatrices类中,量子门的矩阵表示有两种不同的实现方式:
固定矩阵(使用
@cached_property装饰器):- 例如:
H,X,Y,Z,CNOT,SWAP等 - 这些门的矩阵是固定的,不需要参数
- 例如:
参数化矩阵(作为方法):
- 例如:
RX,RY,RZ,U1,U2,U3等 - 这些门需要参数来生成矩阵
- 例如:
关键机制¶
参数化门作为方法:
def RX(self, theta): cos = self.np.cos(theta / 2.0) + 0j isin = -1j * self.np.sin(theta / 2.0) return self._cast([[cos, isin], [isin, cos]], dtype=self.dtype)
RX是一个方法,接受参数theta- 根据参数计算并返回对应的矩阵
维度参数的特殊情况:
def I(self, n=2): return self.np.eye(n, dtype=self.dtype)
- 单位矩阵
I是一个特殊情况,它接受维度参数n - 默认值为2(单量子比特情况)
- 单位矩阵
特殊参数化门:
def GeneralizedRBS(self, qubits_in, qubits_out, theta, phi): # 构建矩阵的代码...
- 这是一个更复杂的参数化门,需要多个参数
与matrix方法的配合¶
现在我们来看matrix方法如何与这些参数化门配合:
def matrix(self, gate):
"""Convert a gate to its matrix representation in the computational basis."""
name = gate.__class__.__name__
_matrix = getattr(self.matrices, name)
if callable(_matrix):
_matrix = _matrix(2 ** len(gate.target_qubits))
return self.cast(_matrix, dtype=_matrix.dtype)
获取门类型:
name = gate.__class__.__name__
- 获取门的类名,例如"RX"、"RY"、"I"等
获取矩阵生成器:
_matrix = getattr(self.matrices, name)
- 从
self.matrices(NumpyMatrices实例)中获取对应的属性 - 对于固定矩阵,这是一个属性值
- 对于参数化矩阵,这是一个方法
- 从
处理可调用对象:
if callable(_matrix): _matrix = _matrix(2 ** len(gate.target_qubits))
- 检查获取到的矩阵生成器是否可调用
- 如果是方法(参数化门),则调用它
- 传入的参数是
2 ** len(gate.target_qubits),表示矩阵的维度
为什么这种方式有效¶
对于固定矩阵:
getattr(self.matrices, name)返回的是一个矩阵(属性值)callable(_matrix)返回False- 直接返回矩阵,不需要调用
对于参数化门:
getattr(self.matrices, name)返回的是一个方法callable(_matrix)返回True- 调用方法并传入参数
特殊情况:
- 对于
I(单位矩阵),它接受维度参数n 2 ** len(gate.target_qubits)正好提供了这个维度- 例如,对于2个目标量子比特,
2 ** 2 = 4,生成4x4的单位矩阵
- 对于
参数化门的参数来源¶
你可能会问:参数化门(如RX)需要的参数(如旋转角度theta)从哪里来?
实际上,我们看到的matrix方法是一个简化的版本。在完整的代码库中,应该有另一个方法(如matrix_parametrized)专门处理参数化门:
def matrix_parametrized(self, gate):
"""Convert a parametrized gate to its matrix representation in the computational basis."""
name = gate.__class__.__name__
_matrix = getattr(self.matrices, name)
if name == "GeneralizedRBS":
_matrix = _matrix(
qubits_in=gate.init_args[0],
qubits_out=gate.init_args[1],
theta=gate.init_kwargs["theta"],
phi=gate.init_kwargs["phi"],
)
else:
_matrix = _matrix(*gate.parameters)
return self.cast(_matrix, dtype=_matrix.dtype)
这个方法从gate对象中提取参数,然后调用对应的矩阵生成方法。
总结¶
NumpyMatrices类通过以下方式使得参数化门可以与matrix方法配合工作:
- 将参数化门实现为方法,接受必要的参数
- 使用
callable()检查获取到的矩阵生成器是否可调用 - 对于可调用的矩阵生成器(参数化门),传入维度参数
2 ** len(gate.target_qubits) - 对于特殊的参数化门(如
I),这个维度参数正好是它需要的参数 - 对于其他参数化门(如
RX),实际参数应该从gate对象中获取,这可能在另一个方法(如matrix_parametrized)中处理
这种设计使得框架可以统一处理固定矩阵和参数化矩阵,同时支持不同类型的参数化门。
matrix_parametrized(gate)方法¶
输入参数:gate 属于核心文件gates.py中定义的子类,父类为abstract.py文件中定义的ParametrizedGate类,比如:
class _Rn_(ParametrizedGate):
"""用于定义RX、RY和RZ旋转的抽象类。
参数:
q(int):量子比特的ID编号。
theta(float):旋转角度。
trainable(bool):门参数是否可以使用
:meth:`qibo.models.circuit.AbstractCircuit.set_parameters` 进行更新。
默认为 ``True``。
"""
def __init__(self, q, theta, trainable=True):
super().__init__(trainable)
self.name = None
self._controlled_gate = None
self.target_qubits = (q,)
self.unitary = True
self.initparams = theta
if isinstance(theta, Parameter):
theta = theta()
self.parameters = theta
self.init_args = [q]
self.init_kwargs = {"theta": theta, "trainable": trainable}
比如说旋转门RX
class RX(_Rn_):
def __init__(self, q, theta, trainable=True):
# ...
self.parameters = theta
# ...
其主要作用是将在gate类中定义的门类转换成npmatrices类中的矩阵形式,方便后续计算。
matrix_fused(self, fgate):矩阵融合方法¶
这段代码实现了一个量子门矩阵融合(matrix fusion)的功能,让我为你详细解释:
功能概述¶
matrix_fused 方法用于将多个量子门矩阵融合成一个单一的矩阵操作。这种技术在量子计算中很有用,可以优化量子电路的执行效率。
参数说明¶
self: 类实例,通常是一个量子计算后端fgate: 一个融合门(FusedGate)对象,包含要融合的多个量子门
实现原理详解¶
- 初始化单位矩阵:
rank = len(fgate.target_qubits)
matrix = sparse.eye(2**rank)
- 创建一个2^rank × 2^rank大小的单位矩阵作为初始矩阵
- rank是目标量子比特的数量
- 遍历处理每个量子门:
for gate in fgate.gates:
对融合门中的每个量子门进行处理
- 获取门矩阵:
gmatrix = self.to_numpy(gate.matrix(self))
将量子门的矩阵表示转换为numpy数组格式
- 处理控制量子比特:
if num_controls > 0:
gmatrix = block_diag(
np.eye(2 ** len(gate.qubits) - len(gmatrix)), gmatrix
)
如果门有控制量子比特,使用block_diag构造控制门矩阵
- 张量积扩充:
eye = np.eye(2 ** (rank - len(gate.qubits)))
gmatrix = np.kron(gmatrix, eye)
通过Kronecker积与单位矩阵进行张量积,使矩阵维度匹配整个系统
- 矩阵重排:
gmatrix = np.reshape(gmatrix, 2 * rank * (2,))
indices = qubits + [q for q in fgate.target_qubits if q not in qubits]
indices = np.argsort(indices)
transpose_indices = list(indices)
transpose_indices.extend(indices + rank)
gmatrix = np.transpose(gmatrix, transpose_indices)
gmatrix = np.reshape(gmatrix, original_shape)
这部分代码对矩阵进行重排,确保门操作作用在正确的量子比特上
- 矩阵融合:
matrix = sparse.csr_matrix(gmatrix).dot(matrix)
将当前门矩阵与总矩阵相乘,实现矩阵融合
用途¶
- 优化量子电路执行:将多个连续的量子门操作合并为一个单一矩阵操作
- 减少计算复杂度:避免多次矩阵乘法运算
- 提高模拟效率:特别是在量子电路模拟中很有用
注意事项¶
- 内存使用:对于大量量子比特的系统,矩阵维度会指数增长(2^n)
- 数值精度:多次矩阵运算可能积累数值误差
- 稀疏矩阵:代码使用了稀疏矩阵(sparse matrix)来优化性能
- 控制门处理:需要特别注意控制量子比特的处理方式
性能考虑¶
- 使用稀疏矩阵(sparse matrix)来优化内存使用和计算效率
- 对于小型张量计算,使用numpy格式更高效
- 矩阵融合操作可以显著减少量子电路模拟的计算复杂度
这个实现是量子计算模拟器中的一个重要优化技术,特别适合处理包含多个连续量子门的量子电路。
def apply_gate(self, gate, state, nqubits): 应用量子门方法¶
这段代码是一个量子计算模拟器中用于应用量子门(quantum gate)的核心函数。让我详细解释其实现原理、用途和注意事项:
实现原理¶
状态表示:
- 量子态被表示为一个形状为
(2**nqubits,)的复数向量,其中nqubits是量子比特数 - 通过
reshape操作将其转换为nqubits个维度为2的张量,便于操作特定量子比特
- 量子态被表示为一个形状为
量子门应用:
普通门(非控制门):
- 直接使用
einsum操作将门矩阵应用到目标量子比特上 opstring定义了爱因斯坦求和的具体方式
- 直接使用
控制门(controlled gate):
- 首先通过
transpose重排张量维度,将控制量子比特放在最高维 - 将状态张量重塑为
(2**ncontrol,) + nactive * (2,)的形式 - 仅当所有控制位都为1时(即
state[-1])才应用门操作 - 最后将更新后的部分与未受影响的部分重新组合
- 首先通过
用途¶
量子电路模拟:
- 这是模拟量子计算的核心操作,用于将量子门作用于量子态
- 支持普通门和控制门的应用
状态演化:
- 实现了量子态的幺正演化
- 可以模拟任意量子电路对量子态的影响
注意事项¶
性能考虑:
- 使用
einsum进行张量操作,这在处理大量量子比特时可能效率不高 - 对于控制门,只操作必要的部分(state[-1]),这优化了计算
- 使用
内存管理:
- 需要存储完整的量子态向量,内存需求随量子比特数指数增长
- 频繁的
reshape和transpose操作可能产生临时数组
数值精度:
- 使用numpy进行浮点运算,需要注意数值精度问题
- 大量的矩阵乘法可能导致累积误差
代码维护:
- 依赖
einsum_utils工具函数处理复杂的张量操作 - 需要确保维度变换的正确性,否则会导致错误结果
- 依赖
这段代码是量子计算模拟器的核心组件,它实现了量子门操作的基本功能,支持普通门和控制门,通过高效的张量操作来模拟量子计算过程。
def apply_gate_density_matrix(self, gate, state, nqubits): 应用量子门密度矩阵方法¶
这段代码是一个量子计算模拟器中的函数,用于对密度矩阵形式的量子态应用量子门。让我详细解释其工作原理:
函数功能¶
apply_gate_density_matrix 函数将一个量子门(gate)作用在密度矩阵表示的量子态(state)上。密度矩阵是描述量子态的另一种方式,特别适合处理混合态和有噪声的量子系统。
参数说明¶
gate: 要应用的量子门state: 当前量子态的密度矩阵表示nqubits: 量子系统中的量子比特数量
实现原理¶
1. 初始处理¶
state = self.cast(state)
state = self.np.reshape(state, 2 * nqubits * (2,))
首先将输入的状态转换为合适的格式,并将其重塑为一个多维数组,每个维度对应一个量子比特。
2. 获取量子门矩阵¶
matrix = gate.matrix(self)
获取量子门的矩阵表示。
3. 处理受控量子门¶
if gate.is_controlled_by:
# 处理受控量子门的逻辑
else:
# 处理普通量子门的逻辑
代码分为两个主要分支:处理受控量子门和普通量子门。
受控量子门处理¶
- 准备工作:
matrix = self.np.reshape(matrix, 2 * len(gate.target_qubits) * (2,))
matrixc = self.np.conj(matrix)
ncontrol = len(gate.control_qubits)
nactive = nqubits - ncontrol
n = 2**ncontrol
重塑矩阵并获取其共轭,计算控制量子比特数、活跃量子比特数和控制态的总数。
- 状态重塑:
order, targets = einsum_utils.control_order_density_matrix(gate, nqubits)
state = self.np.transpose(state, order)
state = self.np.reshape(state, 2 * (n,) + 2 * nactive * (2,))
使用爱因斯坦求和工具调整状态矩阵的维度顺序,以便后续操作。
- 应用量子门:
# 处理不同的子空间
state01 = state[: n - 1, n - 1]
state01 = self.np.einsum(rightc, state01, matrixc)
state10 = state[n - 1, : n - 1]
state10 = self.np.einsum(leftc, state10, matrix)
state11 = state[n - 1, n - 1]
state11 = self.np.einsum(right, state11, matrixc)
state11 = self.np.einsum(left, state11, matrix)
分别处理控制量子比特处于不同状态时的子空间,应用量子门变换。
- 重构状态:
state00 = state[range(n - 1)]
state00 = state00[:, range(n - 1)]
state01 = self.np.concatenate([state00, state01[:, None]], axis=1)
state10 = self.np.concatenate([state10, state11[None]], axis=0)
state = self.np.concatenate([state01, state10[None]], axis=0)
state = self.np.reshape(state, 2 * nqubits * (2,))
state = self.np.transpose(state, einsum_utils.reverse_order(order))
将处理后的各子空间重新组合成完整的密度矩阵状态。
普通量子门处理¶
else:
matrix = self.np.reshape(matrix, 2 * len(gate.qubits) * (2,))
matrixc = self.np.conj(matrix)
left, right = einsum_utils.apply_gate_density_matrix_string(
gate.qubits, nqubits
)
state = self.np.einsum(right, state, matrixc)
state = self.np.einsum(left, state, matrix)
对于普通量子门,代码更简单直接:
- 重塑矩阵并获取其共轭
- 获取爱因斯坦求和字符串
- 通过爱因斯坦求和应用量子门变换:先应用共轭矩阵,再应用原矩阵
4. 返回结果¶
return self.np.reshape(state, 2 * (2**nqubits,))
最后将状态重塑为合适的形状并返回。
关键点解释¶
密度矩阵操作:密度矩阵操作需要同时对状态和其共轭进行变换,这就是为什么代码中同时应用了
matrix和matrixc(共轭矩阵)。受控门处理:受控量子门需要在控制量子比特满足特定条件时才对目标量子比特进行操作,代码通过将状态空间划分为不同子空间来处理这种情况。
爱因斯坦求和:使用爱因斯坦求和约定(
np.einsum)来高效地执行高维张量运算,这是量子计算模拟中的常见技术。维度重塑:通过重塑和转置操作来改变状态的维度顺序,以便在正确的维度上应用量子门。
注意事项¶
性能考虑:密度矩阵模拟的计算复杂度比状态向量模拟更高,因为密度矩阵的大小是系统维度的平方。
数值精度:在操作过程中需要注意数值精度问题,特别是对于大型量子系统。
内存使用:密度矩阵表示需要大量内存,尤其是在处理多量子比特系统时。
幺正性保持:正确的量子门操作应该保持密度矩阵的幺正性,代码实现时需要确保这一点。
这个函数是量子计算模拟器中的核心组件,它允许对密度矩阵形式的量子态应用各种量子门操作,包括受控门,是模拟量子算法和量子噪声过程的基础。
def apply_gate_half_density_matrix(self, gate, state, nqubits): 应用量子门半密度矩阵方法¶
该函数用于对密度矩阵应用量子门操作。主要步骤包括:将输入状态重塑为多维数组,获取门矩阵并 reshape,调用 einsum 工具生成索引字符串,最后通过 numpy 的 einsum 函数执行张量收缩计算,实现门操作。不支持受控门。
噪声¶
def apply_channel(self, channel, state, nqubits):¶
这段代码实现了一个量子信道(quantum channel)的应用过程。让我详细解释其功能和原理:
- 函数参数:
channel: 量子信道对象,包含一组量子门和对应的概率系数state: 当前量子系统的状态nqubits: 量子比特的数量
- 实现原理:
- 首先从信道中获取概率系数(
channel.coefficients),并计算最后一个概率(1减去所有概率系数之和),确保总概率为1 - 使用
sample_shots函数根据这些概率进行随机采样,得到一个索引值 - 如果索引值不是最后一个(即不是"不操作"的情况),则从信道中选择对应的量子门应用到当前状态
- 最后返回更新后的量子态
- 用途: 这个函数实现了量子信道的模拟,量子信道是量子信息理论中的重要概念,用于描述量子态在有噪声环境中的演化。它可以用来模拟:
- 量子噪声(如退相干、振幅阻尼等)
- 量子操作中的随机性
- 量子测量过程
- 量子通信中的信道传输
- 注意事项:
- 概率系数的和必须小于等于1,否则会导致最后一个概率为负数
- 采样过程是随机的,多次运行可能会得到不同结果
- 信道中的量子门必须与系统的量子比特数兼容
- 函数假设量子态是以适当的数据结构表示的(如状态向量或密度矩阵)
这是一个在量子计算模拟中常用的函数,特别是在需要考虑噪声和随机过程的场景中。
def apply_channel_density_matrix(self, channel, state, nqubits): 应用量子信道密度矩阵方法¶
apply_channel_density_matrix 函数用于将量子信道(Quantum Channel)作用在密度矩阵表示的量子态上。这是量子噪声模拟中的核心操作,用于模拟量子系统与环境相互作用导致的退相干过程。函数接受一个量子信道、一个密度矩阵态和量子比特数作为输入,返回经过信道作用后的新密度矩阵。
1. 输入参数处理¶
state = self.cast(state)
- 首先使用
self.cast()将输入的密度矩阵转换为后端支持的数据类型 - 这确保了后续计算使用正确的数值精度和类型
2. 初始化新状态¶
new_state = (1 - channel.coefficient_sum) * state
- 创建新的密度矩阵
new_state (1 - channel.coefficient_sum)表示保真度(identity操作)的权重- 量子信道的所有概率系数之和应小于等于1,差值部分对应保持态不变的概率
3. 应用信道中的各个操作¶
for coeff, gate in zip(channel.coefficients, channel.gates):
new_state += coeff * self.apply_gate_density_matrix(gate, state, nqubits)
- 遍历信道中的所有量子门操作及其对应的系数
zip将系数和门操作配对- 对每个门操作:
- 使用
apply_gate_density_matrix将门作用在原始密度矩阵上 - 将结果乘以对应的系数
- 累加到
new_state中
- 使用
4. 返回结果¶
return new_state
- 返回经过量子信道作用后的新密度矩阵
数学表示¶
从数学上看,这个函数实现了以下变换: ρ' = (1 - ∑ᵢpᵢ)ρ + ∑ᵢpᵢKᵢρKᵢ†
其中:
- ρ 是输入密度矩阵
- ρ' 是输出密度矩阵
- pᵢ 是第i个Kraus算符的概率
- Kᵢ 是第i个Kraus算符对应的量子门
这个实现完整地表达了量子信道的Kraus表示形式,是量子噪声模拟的基础操作。
def reset_error_density_matrix(self, gate, state, nqubits):¶
功能¶
该方法用于模拟量子比特的重置误差对密度矩阵的影响。重置误差是指量子比特在重置操作中可能未能正确重置到|0⟩态的误差。具体来说:
- 以概率 p_0 重置到 |0⟩ 态
- 以概率 p_1 重置到 |1⟩ 态
- 以概率 1-p_0-p_1 保持不变
输入与输出¶
输入参数:¶
gate: 重置误差门,包含目标量子比特和误差概率参数state: 当前的密度矩阵nqubits: 系统中量子比特的总数
输出:¶
- 返回应用重置误差后的密度矩阵
实现原理¶
实现步骤如下:
- 状态初始化和参数提取
state = self.cast(state)
shape = state.shape
q = gate.target_qubits[0]
p_0, p_1 = gate.init_kwargs["p_0"], gate.init_kwargs["p_1"]
- 将输入状态转换为适当的数据类型
- 保存原始状态形状用于后续恢复
- 获取目标量子比特位置和误差概率
- 计算部分迹
trace = partial_trace(state, (q,), backend=self)
trace = self.np.reshape(trace, 2 * (nqubits - 1) * (2,))
- 对目标量子比特求部分迹,得到其他量子比特的约化密度矩阵
- 构造重置到|0⟩的态
zero = self.zero_density_matrix(1)
zero = self.np.tensordot(trace, zero, 0)
- 创建单量子比特的零态密度矩阵
- 通过张量积将约化密度矩阵与零态组合
- 调整量子比特顺序
order = list(range(2 * nqubits - 2))
order.insert(q, 2 * nqubits - 2)
order.insert(q + nqubits, 2 * nqubits - 1)
zero = self.np.reshape(self.np.transpose(zero, order), shape)
- 重新排列量子比特顺序,使重置的量子比特回到正确位置
- 组合所有情况
state = (1 - p_0 - p_1) * state + p_0 * zero
return state + p_1 * self.apply_gate_density_matrix(X(q), zero, nqubits)
- 以相应概率组合三种情况:
- 保持原态不变 (1-p_0-p_1)
- 重置到|0⟩态 (p_0)
- 重置到|1⟩态 (p_1),通过在|0⟩态上应用X门实现
这个实现完整地描述了重置误差对量子系统密度矩阵的影响,保持了概率的归一化,并正确处理了所有可能的误差情况。
def thermal_error_density_matrix(self, gate, state, nqubits):¶
功能¶
该方法用于在密度矩阵上应用热弛豫误差。热弛豫是量子系统中常见的噪声类型,它同时考虑了能量弛豫(T1过程)和相位弛豫(T2过程),可以更准确地模拟真实量子系统中的噪声影响。
输入与输出¶
输入参数:¶
gate: 热弛豫误差门,包含误差参数state: 当前的密度矩阵nqubits: 系统中量子比特的总数
输出:¶
- 返回应用热弛豫误差后的密度矩阵,形状与输入状态相同
实现原理¶
实现步骤如下:
- 状态预处理
state = self.cast(state)
shape = state.shape
- 将输入状态转换为适当的数据类型
- 保存原始状态的形状用于后续恢复
- 应用热弛豫误差
state = self.apply_gate(gate, state.ravel(), 2 * nqubits)
- 将密度矩阵展平为一维数组以便处理
- 使用
apply_gate方法应用热弛豫误差门,其中2 * nqubits是因为密度矩阵的维度是状态向量的两倍
- 恢复状态形状
return self.np.reshape(state, shape)
- 将处理后的状态重新整形为原始的密度矩阵形状
- 确保输出与输入具有相同的矩阵结构
该实现通过将密度矩阵展平、应用误差门、再恢复形状的方式,高效地实现了热弛豫误差对量子系统的影响。这种方法保持了密度矩阵的数学性质,同时简化了误差处理的过程。
def depolarizing_error_density_matrix(self, gate, state, nqubits):¶
功能¶
该方法用于模拟量子去极化误差对密度矩阵的影响。去极化误差是一种常见的量子噪声类型,它会以一定概率将量子态转变为完全混合态。具体来说:
- 以概率 1-λ 保持原始态不变
- 以概率 λ 将态转变为完全混合态
输入参数:¶
gate: 去极化误差门,包含目标量子比特和误差概率参数 λstate: 当前的密度矩阵nqubits: 系统中量子比特的总数
输出:¶
- 返回应用去极化误差后的密度矩阵,形状与输入状态相同
实现原理¶
实现步骤如下:
- 状态初始化和参数提取
state = self.cast(state)
shape = state.shape
q = gate.target_qubits
lam = gate.init_kwargs["lam"]
- 将输入状态转换为适当的数据类型
- 保存原始状态形状用于后续恢复
- 获取目标量子比特位置和去极化概率
- 计算部分迹
trace = partial_trace(state, q, backend=self)
trace = self.np.reshape(trace, 2 * (nqubits - len(q)) * (2,))
- 对目标量子比特求部分迹,得到其他量子比特的约化密度矩阵
- 构造完全混合态
identity = self.identity_density_matrix(len(q))
identity = self.np.reshape(identity, 2 * len(q) * (2,))
identity = self.np.tensordot(trace, identity, 0)
- 创建目标量子比特的完全混合态
- 通过张量积将约化密度矩阵与完全混合态组合
- 调整量子比特顺序
qubits = list(range(nqubits))
for j in q:
qubits.pop(qubits.index(j))
qubits.sort()
qubits += list(q)
qubit_1 = list(range(nqubits - len(q))) + list(
range(2 * (nqubits - len(q)), 2 * nqubits - len(q))
)
qubit_2 = list(range(nqubits - len(q), 2 * (nqubits - len(q)))) + list(
range(2 * nqubits - len(q), 2 * nqubits)
)
qs = [qubit_1, qubit_2]
order = []
for qj in qs:
qj = [qj[qubits.index(i)] for i in range(len(qubits))]
order += qj
identity = self.np.reshape(self.np.transpose(identity, order), shape)
- 重新排列量子比特顺序,确保目标量子比特位于正确位置
- 通过转置和重塑操作恢复正确的矩阵结构
- 组合原始态和混合态
state = (1 - lam) * state + lam * identity
return state
- 以相应概率组合原始态和完全混合态
- 返回最终的密度矩阵
该实现完整地描述了去极化误差对量子系统密度矩阵的影响,保持了概率的归一化,并正确处理了所有可能的误差情况。这种方法可以有效地模拟真实量子系统中的去极化噪声。
电路运行¶
excute_circuit¶
功能¶
execute_circuit 方法用于执行量子电路模拟,支持:
- 纯态和密度矩阵模拟
- 噪声模拟
- 测量操作
- 分布式计算
- 电路级联操作
输入与输出¶
输入参数:¶
circuit: 要执行的量子电路对象initial_state(可选): 初始量子态,可以是另一个电路或具体量子态nshots(默认1000): 重复执行次数,用于采样测量结果
输出:¶
根据电路类型返回不同结果:
- 含测量的电路: 返回
CircuitResult对象,包含测量结果 - 不含测量的电路: 返回
QuantumState对象,包含最终量子态 - 噪声模拟: 返回统计结果或密度矩阵
实现方式¶
1. 初始状态处理¶
if isinstance(initial_state, type(circuit)):
# 处理电路作为初始态的情况
return self.execute_circuit(initial_state + circuit, None, nshots)
elif initial_state is not None:
# 验证初始态形状是否正确
valid_shape = 2 * (2**circuit.nqubits,) if circuit.density_matrix else (2**circuit.nqubits,)
2. 执行模式选择¶
if circuit.repeated_execution:
# 需要重复执行的情况(噪声或含坍缩测量)
return self.execute_circuit_repeated(circuit, nshots, initial_state)
if circuit.accelerators:
# 分布式执行
return self.execute_distributed_circuit(circuit, initial_state, nshots)
3. 量子态演化¶
# 根据模拟类型选择初始态
state = (self.zero_density_matrix(nqubits) if circuit.density_matrix
else self.zero_state(nqubits))
# 依次应用每个门
for gate in circuit.queue:
if circuit.density_matrix:
state = gate.apply_density_matrix(self, state, nqubits)
else:
state = gate.apply(self, state, nqubits)
4. 结果处理¶
if circuit.measurements:
# 含测量的情况返回 CircuitResult
return CircuitResult(state, circuit.measurements, backend=self, nshots=nshots)
else:
# 不含测量的情况返回 QuantumState
return QuantumState(state, backend=self)
5. 错误处理¶
except self.oom_error:
raise_error(RuntimeError, "State does not fit in memory...")
这个方法通过灵活处理不同类型的电路和初始态,实现了完整的量子电路模拟功能,支持多种执行模式和结果类型。
execute_circuit_repeated¶
功能¶
execute_circuit_repeated 方法用于重复执行量子电路,主要用于以下场景:
- 含幺正通道(噪声模拟)且
density_matrix=False的情况 - 包含坍缩测量的情况
- 需要获取概率、频率和采样结果的情况
输入参数:¶
circuit: 要执行的量子电路对象nshots: 重复执行次数initial_state(可选): 初始量子态
输出:¶
根据电路类型返回不同结果:
- 密度矩阵情况: 返回
CircuitResult或QuantumState对象 - 非密度矩阵情况: 返回
MeasurementOutcomes对象,包含测量结果和频率信息
实现方式¶
1. 参数验证¶
if (circuit.has_collapse and not circuit.measurements
and not circuit.density_matrix):
raise_error(RuntimeError, "...")
检查电路配置是否有效,防止无效的参数组合。
2. 初始化¶
results, final_states = [], []
nqubits = circuit.nqubits
初始化存储结果和终态的列表,获取量子比特数。
3. 重复执行电路¶
for _ in range(nshots):
if circuit.density_matrix:
# 密度矩阵模拟
state = self.zero_density_matrix(nqubits) if initial_state is None
else self.cast(initial_state, copy=True)
for gate in circuit.queue:
state = gate.apply_density_matrix(self, state, nqubits)
else:
# 态矢量模拟
state = self.zero_state(nqubits) if initial_state is None
else self.cast(initial_state, copy=True)
for gate in circuit.queue:
state = gate.apply(self, state, nqubits)
4. 处理测量结果¶
if circuit.measurements:
result = CircuitResult(state, circuit.measurements, backend=self, nshots=1)
sample = result.samples()[0]
results.append(sample)
对每次执行获取测量结果并存储。
5. 结果整合¶
根据模拟类型整合结果:
- 密度矩阵情况:
final_state = self.cast(np.mean(self.to_numpy(final_states), 0))
return CircuitResult(final_state, circuit.measurements, ...)
- 非密度矩阵情况:
return MeasurementOutcomes(circuit.measurements, backend=self,
samples=self.aggregate_shots(results), ...)
该方法通过重复执行电路来获取统计结果,支持噪声模拟和测量操作,能够处理不同的模拟场景并提供相应的结果输出。
calculate_symbolic¶
calculate_symbolic 方法将量子态向量转换为狄拉克符号表示形式,用于直观展示量子态的主要组成部分。该方法会过滤掉幅度过小的项,并限制显示的项数,使表示更加清晰。
输入参数:¶
state: 量子态向量nqubits: 量子比特数decimals(默认5): 系数保留的小数位数cutoff(默认1e-10): 幅度阈值,小于此值的项将被忽略max_terms(默认20): 最大显示项数
输出:¶
返回一个字符串列表,每个字符串表示量子态的一个非零项,格式为"系数|基态>"。如果项数超过max_terms,则在最后添加"..."。
实现方式¶
1. 状态转换¶
state = self.to_numpy(state)
将输入的量子态转换为numpy数组格式。
2. 遍历非零元素¶
for i in np.nonzero(state)[0]:
使用np.nonzero找到所有非零元素的索引。
3. 生成基态表示¶
b = bin(i)[2:].zfill(nqubits)
将索引转换为二进制字符串表示,并用前导零填充到nqubits长度。
4. 处理系数¶
if np.abs(state[i]) >= cutoff:
x = np.round(state[i], decimals)
terms.append(f"{x}|{b}>")
检查幅度是否大于阈值,如果是则四舍五入到指定小数位,并添加到结果列表。
5. 限制项数¶
if len(terms) >= max_terms:
terms.append("...")
return terms
如果达到最大项数,添加"..."并返回。
这个实现通过过滤和限制,提供了一个清晰简洁的量子态符号表示,便于理解和分析量子态的主要组成部分。
_order_probabilities¶
_order_probabilities 方法根据给定的量子比特顺序重新排列概率分布。在量子计算中,当我们测量部分量子比特时,需要将概率张量的轴按照特定的量子比特顺序进行排列,以便正确表示测量结果的概率分布。
输入参数:¶
probs: 待重排的概率分布张量qubits: 目标量子比特的索引列表nqubits: 系统中总的量子比特数
输出:¶
返回一个重新排序后的概率分布张量,其轴的顺序与输入的 qubits 参数一致。
实现方式¶
1. 创建映射关系¶
unmeasured, reduced = [], {}
for i in range(nqubits):
if i in qubits:
reduced[i] = i - len(unmeasured)
else:
unmeasured.append(i)
unmeasured: 存储未被测量的量子比特索引reduced: 创建一个字典,将原始量子比特索引映射到新的索引位置
2. 执行重排¶
return self.np.transpose(probs, [reduced.get(i) for i in qubits])
使用 numpy.transpose 函数,根据 reduced 字典中的映射关系,将概率张量的轴重新排列到目标顺序。
这个实现通过创建索引映射,然后使用 transpose 操作高效地完成了概率分布的重排,确保测量结果的概率分布与指定的量子比特顺序一致。
calculate_probabilities¶
calculate_probabilities 方法用于从给定的量子态中计算指定量子比特的测量概率分布。在量子计算中,当我们测量部分量子比特时,需要计算这些量子比特处于各个可能状态的概率。
输入参数:¶
state: 量子态向量,形状为 (2^nqubits,)qubits: 需要计算概率的量子比特索引列表nqubits: 系统中总的量子比特数
输出:¶
返回一个一维数组,包含指定量子比特的所有可能测量结果的概率分布。
实现方式¶
1. 数据类型准备¶
rtype = self.np.real(state).dtype
获取实数部分的数据类型,用于后续类型转换。
2. 确定未测量的量子比特¶
unmeasured_qubits = tuple(i for i in range(nqubits) if i not in qubits)
创建一个元组,包含所有不在测量列表中的量子比特索引。
3. 计算概率密度¶
state = self.np.reshape(self.np.abs(state) ** 2, nqubits * (2,))
- 计算量子态的模平方,得到概率密度
- 将状态向量重塑为 nqubits 维的张量,每维大小为 2
4. 边缘概率计算¶
probs = self.np.sum(self.cast(state, dtype=rtype), axis=unmeasured_qubits)
通过对未测量量子比特的维度求和,计算指定量子比特的边缘概率分布。
5. 概率重排¶
return self._order_probabilities(probs, qubits, nqubits).ravel()
调用 _order_probabilities 方法对概率进行重排,使其符合指定的量子比特顺序,然后将结果展平为一维数组。
这个实现通过张量重塑和边缘概率计算,高效地得到了指定量子比特的测量概率分布,是量子计算中测量过程的核心实现。
测量¶
_append_zeros(state, qubits, results)¶
_append_zeros 函数用于在量子态坍缩后,根据测量结果在相应的量子比特位置插入零态,从而构造新的量子态。这是量子测量后状态重构的重要步骤,确保了测量后量子态的正确表示。该函数主要在 collapse_state 和 collapse_density_matrix 方法中被调用。
1. 输入参数¶
def _append_zeros(self, state, qubits, results):
state: 输入的量子态qubits: 需要操作的量子比特位置列表results: 对应的测量结果列表(0或1)
2. 逐比特处理¶
for q, r in zip(qubits, results):
- 使用
zip将量子比特位置和对应的测量结果配对 - 对每个量子比特-结果对进行独立处理
3. 维度扩展¶
state = self.np.expand_dims(state, q)
- 在指定量子比特位置
q处增加一个新的维度 - 为后续的拼接操作做准备
4. 条件拼接¶
state = (
self.np.concatenate([self.np.zeros_like(state), state], q)
if r == 1
else self.np.concatenate([state, self.np.zeros_like(state)], q)
)
- 根据测量结果
r进行不同的拼接操作:- 当
r == 1时:将零态拼接在原态前面 - 当
r == 0时:将零态拼接在原态后面
- 当
self.np.zeros_like(state)创建与输入态相同形状的零态self.np.concatenate在指定维度q上进行拼接
5. 返回结果¶
return state
- 返回处理后的新量子态
工作原理¶
该函数实现了量子测量后的状态重构过程:
- 对于每个被测量的量子比特,根据测量结果(0或1)确定其在新的量子态中的位置
- 通过维度扩展和条件拼接,确保测量结果与量子态表示一致
- 最终得到一个符合测量结果的新的量子态
这个过程是量子计算中模拟测量效应的关键步骤,保证了量子态在测量后的正确演化。
collapse_state¶
collapse_state 函数用于在量子测量后,根据测量结果将量子态坍缩到对应的子空间。这是量子计算中模拟测量效应的核心操作,确保了测量后量子态的正确演化。函数接受当前量子态、目标量子比特、测量结果和总量子比特数作为输入,返回坍缩后的新量子态。
collapse_state 函数的输入与输出如下:
输入参数¶
state: 量子态向量,表示量子系统的状态
- 类型:numpy数组或张量
- 形状:(2^nqubits,),其中nqubits是量子比特数
qubits: 需要测量的量子比特索引列表
- 类型:列表或元组
- 例如:[0, 2, 3] 表示测量第0、2、3个量子比特
shot: 测量结果
- 类型:整数
- 表示测量得到的二进制结果对应的十进制值
nqubits: 系统中总的量子比特数
- 类型:整数
- 表示量子系统的大小
normalize: 是否归一化状态(可选参数)
- 类型:布尔值
- 默认值:True
- 控制是否在坍缩后对状态进行归一化
输出¶
- 返回值: 坍缩后的量子态向量
- 类型:与输入state相同的numpy数组或张量
- 形状:与输入state相同 (2^nqubits,)
- 表示根据测量结果坍缩后的量子系统状态
功能说明¶
该函数实现了量子测量后的状态坍缩操作。当对指定量子比特进行测量并获得特定结果(shot)时,函数会更新量子系统的状态向量,使其与测量结果一致。如果normalize为True,还会对结果状态进行归一化处理,确保其物理有效性。
1. 输入参数处理¶
state = self.cast(state)
shape = state.shape
- 使用
self.cast()将输入的量子态转换为后端支持的数据类型 - 保存原始状态的形状信息,用于最后恢复
2. 测量结果转换¶
binshot = self.samples_to_binary(shot, len(qubits))[0]
- 将测量结果转换为二进制表示
samples_to_binary将十进制测量结果转换为二进制数组
3. 状态重塑¶
state = self.np.reshape(state, nqubits * (2,))
order = list(qubits) + [q for q in range(nqubits) if q not in qubits]
state = self.np.transpose(state, order)
- 将量子态重塑为张量形式
- 重新排序量子比特,将测量的量子比特放在前面
- 这样便于后续选择对应的测量结果子空间
4. 选择测量结果子空间¶
subshape = (2 ** len(qubits),) + (nqubits - len(qubits)) * (2,))
state = self.np.reshape(state, subshape)[int(shot)]
- 重塑状态以分离测量和未测量部分
- 根据测量结果选择对应的子空间
5. 归一化处理¶
if normalize:
norm = self.np.sqrt(self.np.sum(self.np.abs(state) ** 2))
state = state / norm
- 计算状态的范数
- 对状态进行归一化,保持概率守恒
6. 补充零态¶
state = self._append_zeros(state, qubits, binshot)
- 使用辅助函数
_append_zeros在测量位置补充零态 - 确保状态维度正确
7. 恢复形状¶
return self.np.reshape(state, shape)
- 将处理后的状态恢复为原始形状
- 保持与其他操作的兼容性
工作原理¶
该函数实现了量子测量的后选择效应:
- 根据测量结果选择对应的子空间
- 对选中的子空间进行归一化
- 在测量位置补充零态,确保状态维度正确
- 恢复状态的原始形状
这个过程是量子计算中模拟测量的标准方法,确保了量子态在测量后的正确演化。
collapse_density_matrix¶
collapse_density_matrix 函数实现了量子测量后的密度矩阵坍缩操作。当对量子系统的某些量子比特进行测量并获得特定结果(shot)时,该函数会根据测量结果更新系统的密度矩阵表示。
1. 初始处理¶
state = self.cast(state)
shape = state.shape
binshot = list(self.samples_to_binary(shot, len(qubits))[0])
- 将输入的密度矩阵状态转换为后端支持的格式
- 保存原始密度矩阵的形状信息,用于最终恢复
- 将测量结果shot转换为二进制表示
2. 索引重排¶
order = list(qubits) + [q + nqubits for q in qubits]
order.extend(q for q in range(nqubits) if q not in qubits)
order.extend(q + nqubits for q in range(nqubits) if q not in qubits)
- 构建新的索引顺序,将被测量的量子比特及其对应的密度矩阵部分移到前面
- 这种重排是为了方便后续提取与测量结果对应的部分
3. 状态重塑¶
state = self.np.reshape(state, 2 * nqubits * (2,))
state = self.np.transpose(state, order)
subshape = 2 * (2 ** len(qubits),) + 2 * (nqubits - len(qubits)) * (2,)
state = self.np.reshape(state, subshape)[int(shot), int(shot)]
- 将密度矩阵重塑为张量形式
- 按照新的索引顺序转置张量
- 选择与测量结果对应的部分密度矩阵
4. 归一化处理¶
n = 2 ** (len(state.shape) // 2)
if normalize:
norm = self.np.trace(self.np.reshape(state, (n, n)))
state = state / norm
- 计算子空间的维度
- 如果需要归一化,计算迹并归一化密度矩阵
5. 恢复完整状态¶
qubits = qubits + [q + nqubits for q in qubits]
state = self._append_zeros(state, qubits, 2 * binshot)
return self.np.reshape(state, shape)
- 扩展量子比特索引列表
- 使用_append_zeros方法将坍缩后的状态嵌入回完整的希尔伯特空间
- 将最终状态重塑为原始密度矩阵的形状并返回
这个函数是量子模拟中测量操作的核心实现,它确保了测量后系统状态的正确更新,保持了密度矩阵的物理性质。
增加自定义门¶
在numpy后端中,可以通过定义新的门类来扩展量子计算的功能。与量子门的接口为:matrix(self, gate)、matrix_parametrized(self, gate)函数。它们接受一个参数gate,返回一个矩阵。而gate是来自于qibo-master/src/qibo/gates/gates.py中的类。
想要增加一个量子门,需要在gates.py中定义一个类,继承Gate类,比如class MyGate(Gate):
随后由于调用了self.matrices = NumpyMatrices(self.dtype),所以需要在npmatrices.py中定义一个函数,比如
def MyGate(self):
return np.array([[1, 0], [0, 1]])
这样就可以在量子计算中使用自定义的量子门了。这是不含参数的量子门,如果需要参数,则需要定义一个带参数的函数,比如
def MyGate(self, theta):
return np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
这样就可以在量子计算中使用自定义的带参数的量子门了。