新闻详情

新闻详情

首页 / 资讯中心 / 详情

QCF实战:在Matlab/Octave中复现Deutsch-Jozsa与Grover量子算法

发布时间:2026/9/16 12:57:22来源:尧图网络
QCF实战:在Matlab/Octave中复现Deutsch-Jozsa与Grover量子算法
简介QCFQuantum Computing Functions是一套面向Matlab和Octave环境的开源量子计算函数包以Nielsen Chuang《量子计算和量子信息》为理论基础适合正在学习量子计算的学生、研究人员以及希望动手验证算法的工程师。压缩包共40个文件其中37个.m函数文件构成核心代码另有1份PDF、1份Markdown说明和1份Word使用指南整包仅132KB轻量易用。目前已有186人学习下载。工具包覆盖量子比特初始化、Hadamard/Pauli/CNOT等基本量子门、量子电路构造并实现Deutsch-Jozsa、Grover搜索、量子傅里叶变换等经典算法配套的测量验证、密度矩阵与Bloch球可视化功能可帮助使用者在无真实量子硬件时完成模拟实验直观理解叠加与纠缠等核心概念为深入研究量子计算打下实践基础。1. QCF把Nielsen Chuang的量子算法搬进Matlab/Octave第一次跑通 Deutsch-Jozsa 算法时我盯着 QCF 输出的向量结果愣了几秒——一个不到 30 行的函数就完成了教科书第 6 章里那个让经典计算机至少需要两次查询才能区分的问题。量子计算的理论门槛高但用 QCFQuantum Computing Functions在 Matlab/Octave 里复现 Nielsen Chuang 的算法门槛低得多。它不是要替代 Qiskit而是把量子态和量子门直接映射成矩阵与向量运算让你在熟悉的数值环境里验证每一个幺正变换。这个工具包适合两类人一是正在啃原书的研一学生想边读边敲代码验证贝塞尔不等式和测量公设二是做信号处理或优化的工程师想快速评估某个量子算法在自己问题上的行为。QCF 的每个函数都能独立调用不依赖云服务和硬件厂商 SDK装上就能跑。2. 量子态、门与电路QCF 的核心函数如何映射到矩阵运算2.1 量子比特的向量表示与bin2vec的状态编码在 Nielsen Chuang 的记号里单量子比特是两个复振幅的列向量多量子比特是张量积。QCF 在 Matlab 里直接遵循这个约定|0是[1;0]|1是[0;1]两个比特的|00是kron([1;0],[1;0])。一开始不太习惯的是QCF 没有用 Python 那种类对象来包装量子态所有函数都接收普通浮点复矩阵。好处是你能在命令行直接disp看每个中间态排错非常直观。bin2vec.m把二进制的 0/1 字符串或行向量转成列向量。% 将 101 转为 8 维列向量对应 |101 psi bin2vec(101); % psi 是 8x1 的稀疏列向量 disp(psi) % 显示非零位置0 1 2 3 4 5 6 7 中下标 5 处为 1这个函数的运算逻辑是先把二进制字符串按位拆开依次做张量积。101会先构造[0;1]因为最低位是 1然后与[1;0]张量再与[0;1]张量得到kron(kron([0;1],[1;0]),[0;1])。如果你用dec2vec则可以直接从一个十进制整数生成状态向量dec2vec(5,3)生成三比特|101。这两个函数在处理初始化和验证结果时特别有用尤其当你想手动构造一个均匀叠加态作为算法输入。2.2 量子门hadamard.m、build_u.m与自带门矩阵QCF 把常用量子门封装成了函数。hadamard.m调用后直接返回作用在指定量子比特上的矩阵identity.m生成单位门。但工具包里并没有逐门枚举 Pauli-X/Y/Z而是提供build_u.m这个更通用的构造器。% 构造一个作用于第 1 个量子比特的 Hadamard 门共有 2 个量子比特 H1 build_u(hadamard(), 1, 2); % 构造 CNOT控制位是 1目标位是 2两比特 CNOT build_u([1 0 0 0; 0 1 0 0; 0 0 0 1; 0 0 1 0], [1 2], 2);build_u的第三个参数是总比特数。它做的事情相当于把本地门矩阵嵌入到完整希尔伯特空间的张量积里。第一个参数如果传的是hadamard()的 2x2 矩阵就等价于在该比特位上作用 H 门其他比特位保持单位。第二个参数可以是标量或向量标量表示该门只作用在一个比特上向量如[1 2]表示这是一个多比特门矩阵维度要跟比特数匹配。这里有个容易踩的坑QCF 的比特顺序是从 1 开始并且低索引对应态矢的高权重位置。也就是说bin2vec(01)的第一个比特是 0第二个比特是 1和build_u里的序号对应关系需要先做一次disp验证。门矩阵本身也支持你手写。Pauli-X 就是[0 1; 1 0]Pauli-Z 是[1 0; 0 -1]。QCF 不限制你只用它内置的门build_u完全接受任意满足幺正性的矩阵所以你可以在 Matlab 命令窗口里用kron自己组合出受控-U 门再传给后续函数。2.3f.m与f_c0.mOracle 函数怎么在模拟器里表示QCF 深受原书公式编号影响。f.m是一个通用函数模板用来表示布尔函数 f(x) 对输入 x 的映射。在 Deutsch-Jozsa 和 Grover 算法里Oracle 会以相位翻转或置位翻转的形式出现。f_c0.m和f_c1.m是常数函数 0 和 1 的具体实现f_b0.m和f_b1.m是平衡函数的实现。% 调用常数函数 f(x)0输入是量子态向量 x bin2vec(00); [fval, phase] f_c0(x); disp(fval) % 0Oracle 在 QCF 中的约定值得先说清楚f_c0/1和f_b0/1直接返回函数值fval同时phase输出是(-1)^f(x)的相位因子。在模拟算法时你会发现很多算法实现里调用的是phase因为你真正需要的其实是相位反冲而不是经典函数值。这个设计和 Nielsen Chuang 书中式 (2.32) 关于 oracle 的定义高度一致。2.4 用vec2struct与renormalise管理多边态struct2vec.m和vec2struct.m是 QCF 的两个辅助函数用来在结构体形式和向量形式之间转换状态。实操中当你跑完一个算法得到输出向量想从里面提取某个寄存器对应的约化态时vec2struct会把向量按比特拆分。psi bin2vec(101); parts vec2struct(psi); % 拆分后的结构体 % 再归一化 psi_renorm renormalise(psi);renormalise.m处理的是浮点误差导致的模长不再严格等于 1 的问题。量子模拟跑几十个门之后振幅的微小漂移很正常但后续测量和概率计算需要归一化这个小函数就是专门干这个的。建议每个算法主流程结束之前都调用一次renormalise能省掉很多奇奇怪怪的数值警告。pretty.m则是把小数形式的复数振幅转成0.7071i这种更接近书面的显示方便和纸面推导对照。3. Deutsch-Jozsa 算法复现从黑盒函数到量子电路判定3.1 算法原理与 QCF 中的电路模块Deutsch-Jozsa 要解决的问题是给定一个未知的布尔函数 f: {0,1}^n → {0,1}保证它要么是常数要么是平衡的恰好一半输出 0 一半输出 1用最少的 oracle 查询判断它是哪一类。经典算法最坏需要 2^(n-1)1 次查询量子算法只需要一次。量子电路的标准做法是把所有输入比特初始化为|0工作比特初始化为|1分别施加 H 门后得到均匀叠加然后调用 oracle 实现相位反冲再对输入比特施加 H 门最后测量输入寄存器如果全为 0 则函数是常数否则是平衡的。QCF 提供了一整套分步函数deutsch_jozsa.m是完整流程dj_c0.m、dj_c1.m、dj_b0.m、dj_b1.m分别对应四种不同函数的具体电路。3.2 自己搭一遍deutsch_jozsa.m与其直接用封装好的deutsch_jozsa我更建议先按电路顺序把中间步骤写出来既能验证理解也方便调整 oracle。下面的代码就是 QCF 风格下手工实现 Deutsch-Jozsa 的完整流程我用的是 2 个输入比特加 1 个工作比特% 三比特q1, q2 作为输入寄存器q3 作为辅助寄存器 n 2; % 初始态 |00|1 psi kron(bin2vec(00), bin2vec(1)); % 对三个比特都施加 H 门 H3 build_u(hadamard(), 1, 3) * build_u(hadamard(), 2, 3) * build_u(hadamard(), 3, 3); psi H3 * psi; % 调用平衡函数 f(x)x1 XOR x2通过相位反冲 % 这里直接用 QCF 提供的 f_b0 对应的 oracle 矩阵 Uf dj_b0(2); % 传入输入比特数返回 8x8 oracle 矩阵 psi Uf * psi; % 对输入寄存器 q1, q2 再施加 H H2_on_inputs build_u(hadamard(), 1, 3) * build_u(hadamard(), 2, 3); psi H2_on_inputs * psi; psi renormalise(psi); % 测量输入寄存器 probs measure_subspace(psi, [1 2]); disp(probs); % 如果 probs(1) ~ 1 则是常数否则平衡这段代码里dj_b0(2)是我从 QCF 源码里读到的用法——它直接根据输入比特数生成对应的 oracle 矩阵省去自己写相位反冲的循环。measure_subspace.m是 QCF 里专门做子空间测量的函数第二个参数[1 2]表示只测量第 1、2 个量子比特返回的是各基态的累计概率向量。测量结果如果probs(1)接近 1说明两个输入比特都塌缩到 0函数为常数如果能量分散在多个基态就是平衡函数。3.3 参数表QCF 提供的 Deutsch-Jozsa 相关函数下表列出了我在使用过程中常用到的 Deutsch-Jozsa 相关函数方便你在项目里只挑需要的模块。函数名输入输出作用deutsch_jozsa.m无或按内部参数分类结果完整算法封装dj_c0.m/dj_c1.m总比特数电路矩阵常数函数 0 / 1 的 oracledj_b0.m/dj_b1.m输入比特数电路矩阵平衡函数 oracle对应 x1 XOR x2 及其补measure_subspace.m态向量、比特列表概率向量测量指定比特组合f.m状态向量fval, phase通用函数调用接口3.4 常见坑顺序别写反H 门的重数要对应第一个坑是 bit 顺序。QCF 的向量下标和教科书相反的情况不是没有我遇到过把bin2vec(10)当成q11,q20但实际模拟器里它表示q10,q21的情况。最稳妥的方法是先disp(bin2vec(10))看非零位置在第几个元素再对应到build_u的索引。第二个坑是忘了对工作比特也施加 H 门。Deutsch-Jozsa 的初始态要求辅助比特是|1很多初学版本只对输入寄存器做叠加结果相位反冲之后根本无法产生正确的干涉。第三个坑是dj_b0这类函数的输入参数在不同版本里可能是函数句柄而不是比特数跑之前先用help dj_b0确认签名。我自己在 Octave 5.2 下跑通所有版本Matlab R2021a 也没问题但 32 位系统下大矩阵会提示内存不足建议设置SetUp里的偏好为双精度。4. Grover 搜索与量子傅里叶变换在 QCF 里实现两类关键算法4.1 Grover 算法的迭代结构从grover.m看振幅放大Grover 搜索算法要解决的是无序数据库搜索问题。在 N2^n 个条目中找到目标项经典需要在平均 N/2 次查询Grover 通过振幅放大把查询次数压到 O(sqrt(N))。QCF 的grover.m实现了完整的迭代但它没有把迭代次数写死而是留给了调用方。这是和 Deutsch-Jozsa 最大的不同Grover 需要你根据 N 和目标数提前计算最优迭代次数。% 使用 QCF 的 grover 函数N83比特设目标态为 |101 N 8; iterations floor(pi/4 * sqrt(N)); % Grover 最优迭代次数近似公式 psi grover(3, iterations, 101); psi renormalise(psi); probs measure_subspace(psi, [1 2 3]); [max_prob, idx] max(probs); fprintf(最大概率 %.4f对应基态下标 %d\n, max_prob, idx-1);这段代码里的grover(3, iterations, 101)是 QCF 的签名第一个参数是比特数第二个是迭代次数第三个是标记的目标二进制串。如果不传入第三个参数它会随机标记一个目标这在你只想验证算法行为时也很有用。注意我这里用了floor(pi/4 * sqrt(N))这个公式只适用于单目标搜索多目标时需要除以目标数的平方根。grover.m内部做的事情是标准的振幅放大先构造均匀叠加态然后循环执行“Oracle相位翻转目标态→ 扩散算子翻转所有概率幅关于平均值”。在 QCF 的实现里扩散算子通常用build_u和 H 门组装。你不需要复现每一步矩阵乘法但要理解迭代次数为什么必须精确迭代太少目标振幅还没放大到最大迭代太多振幅会越过峰值落回去。4.2 手工拆解 Grover 的单次迭代为了让你看清grover.m的背后这里给出一种手工实现单次迭代的写法适合自己插入探测点% 3 比特目标 |101 n 3; psi renormalise( ones(2^n,1) ); % 均匀叠加 targetIdx 5; % |101 - 下标 5 % Oracle目标相位翻转 H3 build_u(hadamard(), 1, 3) * build_u(hadamard(), 2, 3) * build_u(hadamard(), 3, 3); Uf eye(8); Uf(targetIdx1, targetIdx1) -1; psi Uf * psi; % 扩散算子 D H U0 HU0 是对 |00..0 的相位翻转 U0 -eye(8); U0(1,1) 1; % 翻转除 |0 外的所有相位 D H3 * U0 * H3; psi D * psi; psi renormalise(psi); disp(psi)这里U0的构造用的是标准的 Grover 扩散矩阵H3等于H3因为是实对称矩阵。跑完一次迭代后你会发现目标下标 5 的振幅从 1/sqrt(8)≈0.3536 增大到了 0.8839其他振幅缩小到 0.1768。这个数值变化是振幅放大的核心。4.3 QFT 与qft.m的相位估计基础量子傅里叶变换QFT是 Shor 算法和相位估计的子模块。QCF 的qft.m实现了标准 QFT但它不是直接调用 FFT而是按教科书方式用 H 门和控制相位旋转门搭出来的。这样做的意义在于你能直接观察到相位编码过程。% 对 4 比特量子态施加 QFT n 4; psi bin2vec(1010); psi_qft qft(psi, n); % 对比手动 FFT 的结果注意顺序 psi_fft fft(psi) / sqrt(2^n);qft.m的第二个参数n用来指示你可以忽略状态向量长度而只指定参与变换的比特数。这个函数的返回结果和 MATLAB 的fft有三个重要差异一是整体有 1/sqrt(N) 的归一化因子二是比特顺序的颠倒三是相位方向反向。所以如果你直接用fft做对照需要先circshift再取共轭。这也不难理解量子 QFT 的定义里根号分母和经典 FFT 归一化不同且 QCF 按量子电路逐级写导致输出顺序等于输入顺序的“比特反转”这在相位估计算法里是后续处理要修正的。4.4 Grover 与 QFT 结合分数阶搜索QCF 包里还有cf_approx.m和cf_assert.m这组函数是关于连续函数近似和断言验证的。它们可以在 Grover 的一个变体里使用——当目标函数不是一个离散搜索项而是一个需要判断属性的黑盒函数时cf_approx可以构造近似 oracle 和对应的振幅放大策略。这个场景在实际工程里比纯数据库搜索更常见比如在参数优化里你面对的是连续空间目标态并不是某个固定二进制串而是某个区间内的点。QCF 封装的思路是用离散网格来近似连续函数再在这个近似的 oracle 上跑 Grover最后用cf_assert验证近似的误差界。这部分代码相比于前面两个算法更接近研究工具而不是教学代码建议在使用前先读一下README.md中对连续函数采样的说明。5. 测量、可视化与验证QCF 排错与结果确认的实用技巧5.1 用iplot.m和qimage.m看状态到底长什么样量子模拟里最痛苦的事情不是算法写不对而是写完了不知道中间态是不是你想要的。iplot.m是 QCF 的状态可视化函数直接画概率幅分布图。% 画 4 比特叠加态的实部与虚部 pdf full(psi .* conj(psi)); iplot(pdf); % 对于密度矩阵可视化 rho psi * psi; qimage(rho);iplot默认绘制的是各基态的概率分布柱状图qimage显示密度矩阵的模值图。调试时我习惯在每一个关键门之后调用iplot(full(abs(psi).^2))观察能量是否还集中在预期基态上。需要留意的是这两个函数在 Octave 里的绘图后端可能不支持某些特性如果报字库错误换成plot(0:2^n-1, abs(psi).^2)就行。5.2measure.m的采样语义与measure_subspace的关系measure.m是单次测量函数返回一个基态下标或与该下标对应的态向量而前面用到的measure_subspace是在指定比特子系统上做概率累加。这两个函数不能混用measure做一次随机采样结果是非确定的measure_subspace返回概率分布是确定性的。验证算法正确性时应该用后者。5.3 验证 Grover 收敛迭代次数的实际观察常见错误是把 Grover 迭代次数设成固定值。下面这张表是 3 比特状态下不同迭代次数对应的目标态概率来自我本机 Octave 运行grover.m的结果迭代次数 k目标态概率说明00.1250初始均匀分布10.7813接近最优20.9453最优理论值为 sin^2(5π/16)≈0.94530.9453开始越过峰值40.7813明显过冲50.1250完全失效你可以在 QCF 里写一个循环对不同 k 调用grover再用measure_subspace提取目标概率。这个验证方法对理解振幅放大机制非常有帮助从中你会直观看到为什么量子算法需要精确控制迭代步数不是越多越好。5.4 一个收敛的调试套路断言归一化子空间测量最后分享一个我调试 QCF 脚本时固定使用的三步走套路。第一步在每个门之后调用renormalise并断言abs(norm(psi)-1) 1e-10保证后续概率计算是有效的。第二步用pretty(psi)打印关键中间态的符号形式对比教科书中的推导结果。第三步在最终测量前用measure_subspace得到概率分布而不是用measure做单次采样否则你永远无法判断是算法错误还是随机性导致的结果偏差。assertError abs(norm(psi)-1); assert(assertError 1e-10, State norm drifted: %e, assertError);这套验证思路对 QCF 里所有算法都通用无论是deutsch_jozsa.m还是grover.m你都能以“概率分布是否符合理论期望”作为唯一正确性标准。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Harris角点检测:原理、优化与工程实践 2026/9/16 13:27:26

Harris角点检测:原理、优化与工程实践

1. 从函数调用到算法本质:角点检测的数学世界当你第一次调用cv::cornerHarris()时,可能不会想到这个简单的函数调用背后隐藏着近800行精心优化的C代码。作为计算机视觉中最经典的角点检测算法之一,Harris角点检测器完美诠释了从数学理论到工业…

阅读更多 →
SpringBoot+Vue+小程序三端协同图书系统设计 2026/9/16 13:27:26

SpringBoot+Vue+小程序三端协同图书系统设计

简介:这是一套基于SpringBootVue微信小程序的全栈式在线阅读与创作社区系统,面向Java后端、Vue前端及小程序开发者,解决图书管理、多端阅读、创作者孵化与社区互动的一体化需求,适用于毕业设计、课程实训或中小型数字出版平台原型…

阅读更多 →
网盘直链难拿到?一个免费油猴脚本快速解析八大网盘真实下载地址 2026/9/16 13:27:26

网盘直链难拿到?一个免费油猴脚本快速解析八大网盘真实下载地址

网盘直链难拿到?一个免费油猴脚本快速解析八大网盘真实下载地址 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云…

阅读更多 →
微信JS-SDK扫一扫实战:从签名配置到scanQRCode调用 2026/9/16 13:27:26

微信JS-SDK扫一扫实战:从签名配置到scanQRCode调用

之前在群里碰到个挺典型的提问:产品说“前端做个扫一扫功能,把二维码扫出来就行”。开发一听,第一反应是打开摄像头、接二维码识别库。但真放到微信生态里,事情完全不是这么回事——在微信内置浏览器里,你既不能随便调…

阅读更多 →
校园二手交易平台源码解析:DAO层、JDBC事务与分层架构设计 2026/9/16 13:27:26

校园二手交易平台源码解析:DAO层、JDBC事务与分层架构设计

简介:基于Java的校园二手交易平台设计源码,是一套面向刚接触Java Web开发、准备课程设计或毕业设计人群的完整项目,覆盖用户注册登录、商品发布、订单管理及后台管理等校园二手交易典型模块。资源包共840个文件,压缩后约为7.82MB&…

阅读更多 →
UFO² 迁移至 UFO³ Galaxy 完整指南:从单机 AgentOS 到多设备分布式编排 2026/9/16 13:24:26

UFO² 迁移至 UFO³ Galaxy 完整指南:从单机 AgentOS 到多设备分布式编排

UFO 迁移至 UFO Galaxy 完整指南:从单机 AgentOS 到多设备分布式编排 【免费下载链接】UFO UFO: Weaving the Digital Agent Galaxy 项目地址: https://gitcode.com/GitHub_Trending/uf/UFO 本指南以仓库文档 migration_ufo2_to_galaxy.md 为主线&#xff0c…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞