检查输入与处理错误

说明网络、收缩路径、数值数组和收缩序文件分别检查什么,并用小例子解释如何修改常见错误。

本页目录

输入和路径检查

一次收缩需要先说明张量之间怎样连接,再指定收缩顺序,最后传入数值数组。ArcTN 会在相应步骤检查这些信息是否相符。例如,维度写错会让数组形状与网络不符,路径中重复使用已参与收缩的张量则会使后续步骤无法执行。

网络:索引和维度是否定义完整

inputs 列出每个输入张量各个轴的索引,output 列出结果保留的索引,size_dict 给出每个索引的维度。即使只调用 arctn_path 搜索收缩序、不传入数组,网络也会接受检查:

以快速开始的矩阵乘法为例,inputs 使用了 "a"、"b"、"c"、"d" 四个索引。如果漏写 "b": 3,就无法确定两块相连矩阵的公共维度,需要把这一条补回 size_dict。若把 output 写成 ("a", "a"),则重复保留了同一个索引;这个例子应改回 ("a", "d")。

路径:每一步是否能接着执行

收缩路径说明每一步合并哪两个张量。检查路径时,ArcTN 会确认两个编号不同、引用的张量已经存在且尚未被前面的步骤使用,并确认全部步骤执行后只剩一个结果。

以三个输入张量为例,SSA 路径中的输入编号为 0、1、2,第一步生成的结果编号为 3。路径 [(0, 1), (3, 2)] 表示先收缩输入 0 和 1,再把结果 3 与输入 2 收缩。若写成 [(0, 1), (0, 2)],第二步就错误地再次引用了输入 0;这里应将第二步改为 (3, 2)。若只保留第一步,仍有两个张量未合并,路径也不完整。

SSA 路径中的编号不会重复分配;opt_einsum 使用的 linear path 则按当前剩余张量列表的位置编号。ArcTNExecutionPlan 保存的是 SSA 路径,可用 plan.to_linear_path() 将它转换为 linear path。

数组:数量、形状和数据类型是否匹配

执行时,arrays[i] 必须对应 inputs[i],各个轴的大小也必须符合 size_dict。快速开始中的三个数组应依次具有形状 (2, 3)、(3, 4)、(4, 2)。把第一个数组转置为 (3, 2) 后传入,就会与 inputs[0] = ("a", "b") 的要求不符;应按所需轴顺序传入数组,或在确实改变了网络时同步修改网络定义并重新生成收缩序。

通过 arctn_contract、plan.execute() 或 ArcTNCompiledContraction.execute() 执行时,各数组必须使用同一种受支持的数据类型:float32、float64、complex64 或 complex128。例如,用 NumPy 创建示例数组时明确设置 dtype=np.float64,可以避免默认整数数组不被支持的问题。处理复数数据时应选择复数类型,以保留虚部。若只把 ArcTN 的路径或树交给 Quimb/Cotengra 执行,数组类型由实际执行库检查。

捕获参数错误

沿用快速开始中的 inputs、output 和 size_dict,下面故意省略 Dynamic 切片必需的 target_size:

python
from arctn import arctn_schedule

try:
    report = arctn_schedule(
        inputs, output, size_dict,
        slicing_mode="dynamic",
    )
except ValueError as exc:
    print(f"规划参数或网络无效:{exc}")

异常信息会指出,slicing_mode="dynamic" 必须同时提供 target_size。可以在调用中补上 target_size=4,表示每个切片内,每一步生成的张量(包括最终输出)最多有 4 个元素。这里的 4 是小型示例的设置;实际使用时应根据网络和可用内存选择上限。

如果参数有效,但仍未找到满足 target_size 的切片方案,调用也会抛出 ValueError。这时应根据错误信息考虑增大上限,或在原来设置了时间限制的情况下增加 max_time;搜索不会自行放宽 target_size。

检查保存的收缩序文件

先按保存与复用收缩序保存 plan.json,再用快速开始中的网络定义和 arrays 检查:

python
from arctn import ArcTNExecutionPlan, PlanValidationError

try:
    plan = ArcTNExecutionPlan.load("plan.json")
    plan.validate(inputs, output, size_dict, arrays=arrays)
except PlanValidationError as exc:
    print(f"文件、网络或数组检查失败:{exc}")
else:
    result = plan.execute(arrays, backend="native")

ArcTNExecutionPlan.load() 会读取文件,并检查保存的网络、SSA 路径、切片索引和大小限制是否相符;文件中已有的浮点运算量、中间张量大小等核心指标,也会根据网络和路径重新计算后核对。加载过程不会重新搜索收缩序。

随后,plan.validate() 将当前网络的连接关系、维度、输入及输出顺序与文件中的网络比较,并检查数组的数量、形状和数据类型。单独调用 plan.validate(arrays=arrays) 也可以检查数组;如果还要传入网络定义,则 inputs、output 和 size_dict 必须一起提供。检查通过时返回 None,失败时抛出异常。

例如,文件保存的是第一个数组形状为 (2, 3) 的网络,后来传入了 (2, 4) 的数组,错误信息会列出实际形状和所需形状。若只是拿错数组,应传入原网络对应的数组;若维度确实改变了,应使用新网络重新生成并保存收缩序。文件缺失、无法读取或 JSON 格式损坏,也会由 load() 包装为 PlanValidationError;可根据异常信息检查路径,或从原来的网络重新保存文件。

这些检查核对的是网络、路径和数组信息。需要验证计算出的数值时,可沿用快速开始中的 np.testing.assert_allclose(result, a @ b @ c),将结果与已知的参考计算比较。

时间限制

max_time 以秒为单位,必须是有限的正数。搜索会在运行过程中检查已用时间,因此设置 max_time=1.0 后,函数也可能超过 1 秒才返回。成功返回的仍是完整路径,可以继续执行收缩。若任务要求到时立即结束整个进程,需要在调用程序外设置超时控制,例如使用作业调度器的时间限制。

常见异常

异常 常见情况与处理方式
TypeError 参数类型不符,例如 target_size=4.0;这里应传入整数 4。
ValueError 网络、路径或权重无效,或未找到满足限制的方案;按错误信息检查对应参数。
PlanValidationError 收缩序文件无法加载,或文件、网络、数组检查失败;它继承 ValueError,可单独捕获以区分这类问题。
NotImplementedError 通过仅返回路径的 ArcTNOptimizer.__call__ 传入 memory_limit 或请求切片;需要保留切片信息时,改用支持 target_size 的 arctn_tree 或 arctn_contract。
ImportError 缺少 Cotengra、opt_einsum 等可选依赖;按安装说明补装所用功能的依赖。
OverflowError 整数参数超出当前平台可表示的范围;检查输入值和单位,并将其改为接口支持的范围。

Rust 高层接口通常用 Result 返回成功值或错误信息,可用 ? 继续向调用方传递错误。各函数的返回类型见 Rust API。