ArcTN Rust原生 张量网络 收缩序优化
代码仓库 ArcTN 是用 Rust 编写的张量网络收缩库,提供收缩序优化、切片和数值执行,并通过 Python 接口接入 Quimb、opt_einsum 等工具。ArcTN 接收张量网络,不直接将量子线路任务转换为张量网络;量子线路对应的网络由 Quimb 等前端或用户自行构建。
本页目录
许可证与使用范围
ArcTN 公司有权授权的源码适用 Arclight 非商业源码可用许可证 1.0,禁止商用和闭源集成。这不是 OSI 认可的开源许可证;商业使用需另行取得授权。
- 第三方依赖保留各自许可;此前已按 MIT / Apache 授出的版本保留已授予的权利,见第三方及历史授权说明。
- Light / Heavy 动态库单独许可。公司代码的源码许可证不授权这些动态库的分发或使用;其对外分发条款尚未确定,首次源码发布及从该源码构建的 wheel 均不附带这些动态库。
完整许可说明见 ArcTN 代码仓库的许可证章节。商业授权及许可咨询:quill@arclightquantum.com。
张量网络与二叉收缩树
张量网络描述张量之间通过 index 连接的关系。采用两两收缩时,计算过程可以表示为一棵二叉收缩树:叶节点是输入张量,内部节点是一次收缩,根节点是最终结果。
同一个网络可以对应不同的收缩树。下面以四个矩阵的乘积 为例:两种顺序得到相同的 结果,但计算量不同。
张量之间的连接
A:2×8 · B:8×2
C:2×8 · D:8×2
收缩树 1
(AB)(CD)
32 + 32 + 8 = 72 次
收缩树 2
((AB)C)D
32 + 32 + 32 = 96 次
收缩树表示张量的组合方式,收缩路径列出具体的计算步骤。例如,第一棵树可以先算 ,也可以先算 ,最后合并两者。收缩序优化要做的,就是在不同收缩树之间搜索,根据计算量、读写量等目标选择代价更低的收缩序。Light / Heavy 采用启发式搜索,不保证全局最优。详见张量网络与收缩树。
收缩序优化与执行
用 inputs、output 和 size_dict 描述张量网络,并指定优化目标(objective),即可进行收缩序优化。
当中间张量太大、占用内存过多时,可以设置 target_size,通过切片把一次大收缩拆成多次较小的收缩。target_size 限制每个切片内单个收缩结果的最大元素数:例如,100 万个 float64 元素的数据占用约 8 MB。它不限制程序的总内存,输入数组和计算时的临时空间仍需另计。
ArcTN 既可以只做规划,也可以完成数值计算:路径和切片方案可保存为 ArcTNExecutionPlan,作为规划与执行之间的中间表示(IR);提供数组后,arctn_contract 可直接完成规划与执行。已有 Quimb 网络也可以通过 ArcTNOptimizer 使用 ArcTN 的规划结果。
量子线路应用推荐使用 Quimb 前端:在 Quimb 中构建电路,计算振幅或期望值时传入 optimize=ArcTNOptimizer(...),即可让 ArcTN 优化收缩序,无需手动整理 inputs、output 和 size_dict。Quimb 负责把任务转换为张量网络,并可在搜索前化简;数值收缩由 Quimb / Cotengra 完成。
VQE、QAOA 与量子机器学习
在这类算法中,电路前端根据参数化电路构建振幅、概率或期望值对应的张量网络,ArcTN 为该网络优化收缩序,外层经典优化器根据计算结果更新电路参数。使用 Quimb 时,可通过 optimize=ArcTNOptimizer(...) 接入,数值收缩由 Quimb / Cotengra 完成;也可以把网络与数组直接交给 arctn_contract 执行。
参数更新后,如果张量顺序、index 对应关系、维度和输出顺序不变,可以复用已有收缩序。ArcTN 不是完整的量子机器学习训练框架,损失函数、参数梯度和训练循环由应用或所用框架处理。具体调用见 VQE 与 QAOA 示例,重复执行见参数变化时复用收缩序。
电路定义:Qiskit 或 Quimb
其他张量网络方法:MPS 状态更新与可选截断;PEPS 更新与收缩算法。
其他方法:稠密状态向量/密度矩阵、稳定子方法、Pauli 传播。
inputs · output · size_dict
arrays (用于执行)
Qiskit 电路需要转换;兼容的 OpenQASM 2 电路可由 Quimb 导入。
收缩路径 + 切片索引
arctn_contract(…)
或保存收缩序与切片信息: ArcTNExecutionPlan (IR)
Native CPU 执行器(Rust)
或 opt_einsum + NumPy / CuPy / Torch / JAX
ArcTNOptimizer.search()
↓ cotengra.ContractionTree
Quimb / Cotengra 执行 → autoray
CPU 或 GPU 数组后端
收缩结果:标量或张量
ArcTN 处理张量收缩问题,也可处理 MPS/PEPS 算法中的收缩子问题。状态更新、截断、采样与噪声模型由调用方管理。
从量子线路到收缩结果
两个量子比特从 出发,依次施加 H、、CNOT 和 。我们计算最后测到 11 的概率:先求振幅 ,再计算 。这里的基顺序为 。
逐步查看收缩
先把初态、量子门和末端的 写成张量,再交给 ArcTN 搜索收缩路径。下图逐一对应电路中的门与张量;点击“下一步”,可查看已生成的收缩序和各步中间结果。
“运行 NumPy”可沿这条路径计算振幅与概率,并与 ArcTN 的结果、直接收缩和独立状态向量计算比较。
量子线路
时间从左向右。CNOT 的控制位是 q0,目标位是 q1;末端 ⟨1| 指定要计算的输出。
对应的张量网络
每条连线是一个共享 index,取值为 0 或 1。所有 index 都参与求和,结果是一个振幅。
量子门怎样变成张量?
| 电路中的对象 | 张量 | index 与形状 |
|---|---|---|
| 两个初态 |0⟩ | T0、T1,向量 [1, 0] | [a]、[b],各 2 个元素 |
| H、Ry(π/3) | T2、T3,单比特门矩阵 | [c,a]、[d,b],各 2 × 2 |
| CNOT | T4,两个输出轴和两个输入轴 | [e,f,c,d],2 × 2 × 2 × 2 |
| Ry(π/4) | T5,单比特门矩阵 | [g,e],2 × 2 |
| 指定输出 11 的两个 ⟨1| | T6、T7,对偶向量 [0, 1] | [g]、[f],各 2 个元素 |
门张量按“输出轴、输入轴”排列。CNOT 的 4 × 4 矩阵通过 reshape(2, 2, 2, 2) 写成 [e,f,c,d] 四个轴,不改变元素顺序。把末端向量也接入后,网络没有开放的 index,因此传给 ArcTN 的 output=[]。
本例用 NumPy 构造这些张量。ArcTN 从 inputs、output 和 size_dict 开始规划,不解析电路图或量子门。
SSA path [(4, 7), (0, 2), (8, 9), (1, 3), (5, 6), (10, 11), (12, 13)]
(4, 7) → 8待展示(0, 2) → 9待展示(8, 9) → 10待展示(1, 3) → 11待展示(5, 6) → 12待展示(10, 11) → 13待展示(12, 13) → 14待展示
T0…T7 是电路对应的输入张量;T8 起为每步新产生的结果。树的左右位置只用于排版,编号与实际路径一致。
二叉收缩树
叶节点是初态、量子门或末端 bra;内部节点表示一次两两收缩。
当前保留:T0 [a]T1 [b]T2 [c,a]T3 [d,b]T4 [e,f,c,d]T5 [g,e]T6 [g]T7 [f]
T0[a]
2 · float64| 1 |
| 0 |
T1[b]
2 · float64| 1 |
| 0 |
T2[c,a]
2 × 2 · float64| 0.707107 | 0.707107 |
| 0.707107 | -0.707107 |
T3[d,b]
2 × 2 · float64| 0.866025 | -0.5 |
| 0.5 | 0.866025 |
T4[e,f,c,d]
2 × 2 × 2 × 2 · float64| 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 0 | 0 | 1 |
| 0 | 0 | 1 | 0 |
T5[g,e]
2 × 2 · float64| 0.92388 | -0.382683 |
| 0.382683 | 0.92388 |
T6[g]
2 · float64| 0 |
| 1 |
T7[f]
2 · float64| 0 |
| 1 |
这里按输入轴展示元素,CNOT 的 4 × 4 表格将 [e,f] 合为行、[c,d] 合为列。点击“下一步”后,矩阵按该步的求和 index 重新排列和分组。
ArcTN 最终振幅 A₁₁
| 0.701057 |
测到 11 的概率 P(11) = |A₁₁|²
| 0.491481 |
完整路径: 42 FLOPs · 最大收缩结果: 8 个元素
路径与指标
{
"ssa_path": [[4, 7], [0, 2], [8, 9], [1, 3], [5, 6], [10, 11], [12, 13]],
"linear_path": [[4, 7], [0, 2], [4, 5], [0, 1], [0, 1], [0, 1], [0, 1]],
"metrics": {
"log10_flops": 1.6232492903979006,
"log2_max_size": 3,
"log2_max_contraction_size": 4.700439718141093,
"log2_total_size": 4.392317422778761,
"log2_read_write": 6.266786540694901,
"log2_peak_size": 5.459431618637297,
"log2_n_slices": null,
"sliced_log10_flops_total": null,
"sliced_log2_max_size": null,
"sliced_log2_max_contraction_size": null,
"sliced_log2_peak_size": null,
"max_intermediate_log2_elements_per_slice": null
}
}表格显示最多 6 位小数。逐步演示按原生执行器的轴顺序展开矩阵:左矩阵的列与右矩阵的行对应求和 index,其余 index 在乘法后还原为结果张量的轴。
沿 ArcTN 已返回的路径执行,不重新寻路。首次运行会从 jsDelivr 加载 Pyodide 和 NumPy;计算在浏览器中完成。
尚未运行。点击“运行 NumPy”在浏览器中计算。
执行步骤(伪代码)
tensors = 按 SSA 编号保存输入数组(arrays)
for left, right, out, axis_orders, matrix_shapes, output_shape in contractions:
A = 重排轴并合并为矩阵(tensors[left], axis_orders.left, matrix_shapes.left)
B = 重排轴并合并为矩阵(tensors[right], axis_orders.right, matrix_shapes.right)
tensors[out] = reshape(A @ B, output_shape)
del tensors[left], tensors[right]
amplitude = 取最终张量(tensors)
probability = abs(amplitude) ** 2
核对振幅(amplitude, ArcTN结果, 直接收缩结果, 状态向量结果)
return amplitude, probability本例使用默认目标 FLOPs + 64 × read/write。步骤按钮展示已保存的结果,不重新寻路;“运行 NumPy”执行这条收缩路径。FLOPs 在本例中按标量乘法次数计数。
- 快速开始 — 从一个更小的 Python 例子开始。
数值执行与第三方接入
直接执行收缩
提供数值数组后,arctn_contract 可在一次调用中完成规划、可选切片和执行。默认使用 ArcTN 的原生 CPU 执行器,也可以指定外部数组后端。return_info=True 同时返回规划和执行报告。
在 Quimb 中使用
向 Quimb 的 optimize= 传入 ArcTNOptimizer,即可使用 ArcTN 搜索路径。ArcTNOptimizer.search() 返回包含路径和切片 index 的 ContractionTree,后续数值收缩由 Quimb / Cotengra 执行。
保存与复用收缩序
同一网络结构和维度下,数组值变化时无需重新寻路。用 arctn_plan 得到收缩序和切片信息,保存后可用于后续收缩。
核心能力
| 能力 | 实现方式 | 相关说明 |
|---|---|---|
| 路径生成 | 贪心、随机贪心、动态规划与递归超图二分 | 寻路算法 |
| 路径改进 | 子树重构、模拟退火、副本交换与固定叶序动态规划 | 退火与副本交换、子树重构 |
| 自动收缩序优化 | Light / Heavy 预设,安排路径生成与改进 | 方法组合调度 |
| 切片 | Fixed 固定路径,Dynamic 允许局部调整路径 | 切片 |
| 数值执行 | 原生 CPU 执行器,或指定 opt_einsum 数组后端 | 执行后端 |
| 并行与分布式 | Rayon 单机并行,以及 tnmpi 分布式切片执行 |
并行设置 |