MATLAB量子仿真工具箱:从态矢量到量子门操作的工程化实现
发布时间:2026/10/23 8:51:01 锦皓数字建站

简介面向量子信息方向的MATLAB实用工具箱整合了量子比特操作、量子门实现、量子线路模拟、量子测量以及熵与纠缠度量等功能适合科研人员、工程师与相关专业学生开展量子算法仿真和量子系统性质分析。压缩包共279个文件以276个.m脚本为主辅以3个txt说明文档整体仅163KB轻量易用。核心脚本与初始化配置分别提供库函数调用与环境预设启动加载模块确保每次使用自动生效dm、measurements、entropy_and_entanglement等目录则按密度矩阵计算、量子测量和纠缠度量分模块组织查阅路径清晰。配套README.txt、release_notes.txt和LICENSE.txt可帮助快速上手、获知更新与许可条款。资源已有545人学习想深入量子信息计算模拟的读者可由此获得一套结构完整、可直接调用的MATLAB基础工具。1. 量子信息计算库把态矢量演化和测量封装成可用的 MATLAB 工具箱做量子计算仿真的人大多经历过这种尴尬算法流程画在纸上很清晰一落到 MATLAB 里就开始和复数矩阵搏斗。态矢量乘法、张量积顺序、测量坍缩概率每一步都是出错重灾区调试一个小规模量子线路常常要花掉一整个下午。这个量子信息计算库就是为解决这类问题而生的它把量子态表示、量子门操作、测量与线路模拟封装成一组 MATLAB 函数和类让开发者从底层矩阵运算中解脱出来。无论是刚接触量子计算的初学者还是需要快速验证算法的研究者都能靠这份源码把思路直接变成可运行的仿真结果改参数、换门、加测量几乎不用动框架代码。2. 总体架构围绕 QuantumState、QuantumGate、QuantumCircuit 的三层拆解先说结论这个库的架构可以概括为“两个核心类、一个调度类、三个辅助模块”。QuantumState负责量子态的存储与基础运算QuantumGate负责门的定义与组合QuantumCircuit负责把门按时间序排成线路并执行仿真。上层再挂测量模块和可视化工具整套分层方式和主流量子计算框架的思路基本一致后面想迁移到别的语言也容易对照。2.1 三层职责划分为什么把态和门拆成两个类而不是塞进一个对象在 MATLAB 里做量子仿真的常见做法是直接拿复数矩阵塞进脚本然后靠一堆过程式函数操作这些矩阵。这样做在 2 到 3 个量子比特时还好一旦超过 4 个比特就会陷入“哪个矩阵乘哪个矩阵”的黑匣子状态。这个库选择了面向对象的分层QuantumState只关心“我是谁”也就是当前系统的态矢量或密度矩阵QuantumGate只关心“我要做什么变换”也就是一个酉矩阵QuantumCircuit把两者组合起来按时间序调度门的执行。这样拆的好处体现在两个地方。第一门本身是可复用的同一个 H 门可以在不同线路里反复使用不用每次重新构造矩阵。第二态的存储方式可以独立演进比如从态矢量改成密度矩阵表示时门和线路的代码不用大改。我自己写仿真代码时也倾向于这种职责划分否则后期加噪声模型时会发现所有函数都要跟着改那种牵一发动全身的感觉经历过一次就不想再来第二次。2.2 目录结构拿到源码后第一眼看哪里解压源码包后第一件事应该是看目录结构。这个库的布局大致如下quantum-lib/ ├── QuantumState % 量子态类态矢量、密度矩阵、部分求迹 ├── QuantumGate % 量子门类单比特门、受控门、自定义门 ├── QuantumCircuit % 线路类门的追加、执行、深度统计 ├── Measurement % 测量类投影测量、概率采样 ├── utils/ % 辅助函数张量积、矩阵归一化、随机数封装 ├── examples/ % 示例脚本贝尔态、GHZ 态、量子隐形传态 └── docs/ % 文档和 API 说明开头是 MATLAB 的类文件夹语法表示该文件夹下的所有文件都属于这个类的方法。使用类文件夹的好处是不用手动addpath到每个子目录MATLAB 会自动把类定义加载进搜索路径。初次使用时只需要在仓库根目录执行一次addpath(genpath(quantum-lib))后续所有类都能被直接调用不用每次启动都重新配置一遍。2.3 数据流一次仿真从输入参数到输出结果经历了什么把一次典型仿真的数据流理顺能帮你在改代码时快速定位到具体模块。以制备并测量一个两比特纠缠态为例整个流程是先创建两个初始化为零态的QuantumState对象接着用QuantumGate构造 H 门和 CNOT 门然后通过QuantumCircuit按顺序把 H 门作用到比特 1、把 CNOT 门作用到比特 1 和比特 2执行线路得到最终态最后调用测量模块对最终态做投影测量得到坍缩后的态和对应概率。这个流程对应到代码里就是三层对象各司其职出问题时可以按层排查概率算得不对先看测量模块演化结果不符合预期先看QuantumGate的矩阵构造如果连初始态都错了那就是QuantumState的问题。分层的价值在调试时体现得最明显不用每次都在上千行脚本里翻来翻去。3. 核心实现拆解态矢量、酉变换与测量坍缩的代码链路这一章挑三个最关键的模块把核心代码拉出来逐段讲。代码做了适度简化保留了原库的核心逻辑方便阅读也方便直接抄走。3.1 QuantumState态矢量与密度矩阵的统一封装量子态在仿真里有两个表示层级纯态用态矢量混态用密度矩阵。这个库在设计QuantumState时做了一个实用的决定内部data属性统一存复数矩阵纯态存列向量混态存方阵通过is_pure标志区分。classdef QuantumState handle properties data; % 复数矩阵纯态为列向量混态为方阵 nq; % 量子比特数 is_pure true; end methods function obj QuantumState(init_state) % 支持传入态矢量或密度矩阵 if isvector(init_state) obj.data init_state(:); obj.nq log2(length(init_state)); obj.is_pure true; % 归一化态矢量 n norm(obj.data); if abs(n - 1) 1e-12 obj.data obj.data / n; end else obj.data init_state; obj.nq log2(size(init_state, 1)); obj.is_pure false; % 密度矩阵归一化迹等于 1 tr trace(obj.data); if abs(tr - 1) 1e-12 obj.data obj.data / tr; end end end function rho density_matrix(obj) % 纯态转密度矩阵混态直接返回 if obj.is_pure rho obj.data * obj.data; else rho obj.data; end end end end构造函数接收一个复数向量或方阵通过取对数自动推断比特数nq并在创建时就完成归一化。这里的关键细节是归一化阈值1e-12量子线路跑完一轮之后由于浮点误差振幅模方和往往不是精确的 1直接做后续运算会积累偏差所以在入口统一处理掉。density_matrix方法是纯态和混态之间的桥梁在计算期望值或绘制布洛赫球时非常有用。注意这里继承的是handle类而不是值类这是源码里一个值得留意的设计选择。handle是引用语义两个变量可以指向同一个数据对象在构造线路时可以避免反复复制大矩阵。但这也带来一个副作用你改了其中一个变量另一个也会跟着变。后面避坑章节会专门讲这个问题。3.2 QuantumGate从单比特门到受控门的矩阵组装量子门的本质是酉矩阵。这个库的QuantumGate类把常用门Pauli 门、H 门、S 门、T 门、CNOT、CZ、SWAP预置为静态方法也允许传入任意酉矩阵构造自定义门。classdef QuantumGate properties matrix; % 酉矩阵 nq; % 门作用的比特数 name; % 门名称 end methods function obj QuantumGate(matrix, name) % 校验酉性M*M 应接近单位阵 assert(norm(matrix * matrix - eye(size(matrix))) 1e-10, ... 输入矩阵必须是酉矩阵); obj.matrix matrix; obj.nq log2(size(matrix, 1)); obj.name name; end end methods (Static) function g H() g QuantumGate(1/sqrt(2) * [1 1; 1 -1], H); end function g CNOT(nq, ctrl, tgt) % nq : 系统总比特数 % ctrl: 控制比特编号1 到 nq % tgt : 目标比特编号1 到 nq且不等于 ctrl dim 2^nq; m eye(dim); for idx 0:dim-1 bits dec2bin(idx, nq) - 0; % 转成二进制位向量 if bits(ctrl) 1 bits(tgt) 1 - bits(tgt); % 翻转目标比特 new_idx bin2dec(num2str(bits)) 1; m(idx 1, :) 0; m(idx 1, new_idx) 1; end end g QuantumGate(m, sprintf(CNOT(%d,%d), ctrl, tgt)); end end end构造方法里的酉性校验用的是M * M也就是共轭转置不是普通转置transpose。这个细节对复矩阵极其关键很多人自定义门时会把写成.结果矩阵平方和算出来是复数断言直接不通过。CNOT 构造的逻辑是对每个计算基编号逐位判断把编号转成二进制位串后检查控制位是否为 1是的话就把目标位翻转再把新的编号映射到单位阵对应行上。这个方法的时间复杂度是O(4^n)能覆盖到 10 比特以内的大部分教学和验证场景。3.3 测量模块概率计算、随机采样与坍缩实现测量是量子线路里最容易写错的部分关键在两点概率要按振幅模平方计算坍缩要按测量结果筛选分量。这个库的测量函数把整条逻辑封装在一个函数里。function [outcome, probs, collapsed] measure_state(state, qubits_to_measure) % state : QuantumState 对象 % qubits_to_measure : 要测量的比特编号向量例如 [1 2] % outcome : 测量结果位串如 [0 1] % probs : 每种结果出现的概率 % collapsed : 坍缩后的量子态未归一化需要再归一化 if state.is_pure nq state.nq; psi state.data; n_meas numel(qubits_to_measure); dim_meas 2^n_meas; probs zeros(dim_meas, 1); % 第一遍对所有计算基分量按测量比特分组累加概率 for i 1:numel(psi) bits dec2bin(i - 1, nq) - 0; meas_bits bits(qubits_to_measure); group_idx bin2dec(num2str(meas_bits)) 1; probs(group_idx) probs(group_idx) abs(psi(i))^2; end % 归一化概率 probs probs / sum(probs); % 第二遍按概率随机采样确定测量结果 r rand(); cumprobs cumsum(probs); chosen find(cumprobs r, 1, first); chosen_bits dec2bin(chosen - 1, n_meas) - 0; % 第三遍坍缩只保留与测量结果一致的分量 collapsed zeros(size(psi)); for i 1:numel(psi) bits dec2bin(i - 1, nq) - 0; if isequal(bits(qubits_to_measure), chosen_bits) collapsed(i) psi(i); end end outcome chosen_bits; collapsed collapsed / norm(collapsed); % 重新归一化 else error(measure_state 暂不支持混态的测量请先转为纯态); end end这个函数做了三件事先遍历所有计算基振幅按测量比特的不同取值分组累加概率相当于做了一次“部分求迹”然后用rand()做加权随机采样模拟测量坍缩的随机性最后把所有不满足测量结果的分量清零再归一化得到坍缩后的态。三步对应着量子力学测量公理的三个要求少一步结果都是错的。rand()每次返回 0 到 1 之间的均匀随机数find(cumprobs r, 1, first)实现的是概率加权抽样哪个区间被命中就得到哪个测量结果。4. 从零跑通路径配置、贝尔态制备和概率验证三步走这一章把环境配置和运行流程完整过一遍照着做就能跑出结果。我建议在 MATLAB R2020b 及以上版本运行低版本对 classdef 的支持虽然也能跑但性能会差一些。4.1 环境准备与路径加载打开 MATLAB 后先 cd 到仓库根目录然后执行一次路径加载% 当前目录指向 quantum-lib 所在文件夹 addpath(genpath(pwd)); savepath; % 保存路径下次启动不用重新配置genpath(pwd)会递归地把当前目录下所有子文件夹加入搜索路径包括那些开头的类文件夹。savepath把路径配置写入 MATLAB 的 pathdef 文件这样下次重启 MATLAB 不用重复操作。如果你用的是 MATLAB Online 或者校园机房的共享环境可能没有写 pathdef 的权限那每次会话开始手动执行一次addpath(genpath(pwd))即可。4.2 跑通一个贝尔态制备线路贝尔态是量子信息里最基础的纠缠态制备线路只有两步H 门作用到第一个比特再 CNOT 把第一个比特作为控制位、第二个比特作为目标位。% 创建两比特系统的初始态 |00 q1 QuantumState([1; 0]); q2 QuantumState([1; 0]); psi0 kron(q1.data, q2.data); system QuantumState(psi0); % 构建线路 circ QuantumCircuit(system); circ.add_gate(QuantumGate.H(), 1); % H 门作用到比特 1 circ.add_gate(QuantumGate.CNOT(2, 1, 2), [1, 2]); % CNOT: 控制 1 目标 2 % 执行线路 final_state circ.run(); % 测量两个比特 [outcome, probs, collapsed] measure_state(final_state, [1, 2]); disp(probs); % 期待看到 [0.5; 0.5; 0; 0] 之类的结果这里kron函数按从左到右的顺序做张量积对应比特 1 在前、比特 2 在后索引顺序一旦搞混后续所有结果都会乱掉。circ.add_gate的第一个参数是门对象第二个参数是门作用的比特位置位置编号从 1 开始。执行完线路后measure_state返回的probs理论上应该只有[0 0]和[1 1]两种结果的概率并且各占一半。4.3 验证结果正确性不只看概率还要看态矢量只跑出概率还不够建议把最终态矢量也打印出来用数学期望验证一下。贝尔态的标准形式是(|00⟩ |11⟩) / sqrt(2)对应到态矢量就是四个分量为[1/sqrt(2); 0; 0; 1/sqrt(2)]。你可以在线路执行后检查% 查看最终态矢量的非零分量 nonzero_idx find(abs(final_state.data) 1e-8); disp(nonzero_idx); disp(final_state.data(nonzero_idx));如果打印出来是第 1 个和第 4 个分量为0.7071说明线路逻辑正确。如果你发现翻转了过来比如是[0; 0.7071; 0.7071; 0]不用怀疑别的就是你kron的顺序或者 CNOT 的控制目标写反了。这是我最常遇到的翻车现场所以每一步都建议验一下。提示概率结果有随机性单次测量看到[0 0]或[1 1]都很正常。想验证概率分布用一个循环跑 1000 次测量取频率或者用rng(42)固定随机种子再重跑。5. 避坑记录张量积顺序、测量概率与内存爆炸的五个坑这个章节每条都是实际跑仿真时容易踩进去的坑按“现象 → 原因 → 解决”的格式记录方便你快速对照排查。5.1 张量积顺序搞反所有概率对不上号现象跑贝尔态制备测量结果的概率分布完全对不上理论值[0 1]和[1 0]出现了不该有的概率。原因MATLAB 的kron是严格按输入顺序做张量积的而量子线路的比特编号习惯从左到右排列很多人把kron(q1.data, q2.data)写成了kron(q2.data, q1.data)整个矢量空间里的坐标顺序全部镜像翻转。解决在创建初始态时固定写成从左到右的编号顺序并且加一行注释标明“比特 1 在前”。如果你觉得记号太绕可以封装一个工具函数combine_states(varargin)内部用kron逐个相乘并做一次维度校验函数返回的nq必须等于输入参数个数否则直接抛错。5.2 测量概率与随机数的玄学重复采样结果总是偏向一边现象同样的线路跑很多次测量结果里[0 0]出现的次数明显多于[1 1]反复重试都一样。原因大概率是概率计算时取了psi(i)的平方而不是模平方。复数振幅a bi的平方是(abi)^2模平方才是a^2b^2。MATLAB 里abs(psi(i))^2和real(psi(i))^2是两回事。解决检查所有概率累加的地方统一用abs(...)^2另外如果你的脚本在循环里调用了rand而没设随机种子重复试验之间会有偏差感建议用rng(2024)这类固定种子复现排除玄学因素。5.3 超过 20 个比特后内存开始吃紧现象从 20 个比特开始每次run()执行时间越来越长到 24 个比特时直接卡出内存不足的错误。原因态矢量存储空间随比特数指数增长2^24个复数的双精度矩阵需要约 256MB 内存而这只是一份数据如果代码里用了值传递或者不小心复制了对象内存占用直接翻倍。解决一是尽量用handle类避免对象复制二是对于只需要部分子系统的线路考虑用密度矩阵做部分求迹不要保留完整态空间三是可以尝试用gpuArray把矩阵乘法挪到 GPU 上遇到 20 个比特以上的大矩阵运算GPU 带来的速度提升不是一点半点。5.4 自定义门报“输入矩阵必须是酉矩阵”现象自己构造了一个相位门[1 0; 0 exp(1i*theta)]传入QuantumGate构造函数时直接断言失败。原因浮点误差累计导致M*M和单位阵的差超过了 1e-10 的容差另一类可能是把共轭转置写成了普通转置复矩阵的虚部没被正确处理矩阵乘出来不是单位阵。解决构造自定义门前先手动验证norm(M*M - eye(size(M)))如果是因为浮点误差把构造函数里的容差放宽到1e-8如果是因为转置写错把.改成。从这之后我每次写新门都会先跑一遍酉性检查成了固定流程。5.5 handle 引用语义导致变量互相污染现象创建了两个QuantumState对象只是想改其中一个结果发现另一个的数据也变了。原因QuantumState handle是引用语义多个变量持有同一个底层数据地址任何一处修改都会同步。这在构造线路时省了复制开销但对不熟悉 MATLAB 面向对象的人来说非常反直觉。解决如果你确实需要独立副本自己实现一个copy方法把data和标志位复制到新对象里返回MATLAB内置的copy函数对 handle 类默认是浅拷贝使用时要注意区分。知道这个坑之后我再写多比特仿真时都会刻意避免把一个对象反复赋值给多个变量。6. 二次开发思路自定义门、噪声信道与性能优化的改造点这个库的扩展方式比想象中要直接核心思路是“不修改现有类只新增子类或新增静态方法”。比如要加一个自定义单比特门只需要构造QuantumGate实例不必改动类定义本身theta pi/3; phase_gate QuantumGate([1 0; 0 exp(1i*theta)], P(pi/3)); circ.add_gate(phase_gate, 1);加噪声模型稍微绕一点但也可以独立于框架实现。常见做法是在线路run()之后对最终密度矩阵做一次信道变换比如退极化信道function noisy_rho depolarizing_channel(rho, p) % rho: 输入密度矩阵 % p : 退极化概率0 到 1 之间 d size(rho, 1); noisy_rho (1 - p) * rho p * eye(d) / d; end调用时先用density_matrix()把纯态转成密度矩阵再过一次信道。性能优化方面我一般从三个方向入手一是把QuantumCircuit.run()里循环调用的矩阵乘法改成预先合并所有门矩阵的形式减少中间矩阵数量二是对只涉及少数比特的门用稀疏矩阵存储避免单位阵撑满内存三是在 MATLAB 支持 GPU 的环境中把QuantumState.data转成gpuArray大矩阵乘法直接交给 GPU 处理。每次改完记得跑一遍贝尔态和 GHZ 态的验证脚本确认新模块没有破坏原有的酉性约束和概率归一化。从那以后我每次加完功能都强制走一遍三个验证点矩阵酉性、概率归一化、两比特纠缠态保真度成了肌肉记忆。这个习惯帮我拦住了不少看似没问题、实际改了索引顺序的隐形 bug希望也能帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。