---
title: "切片计算与求和"
description: "枚举切片取值、并行执行并汇总结果，以及切片对总计算量和内存的影响。"
eyebrow: "切片"
---

## 计算每个切片，再把结果相加 {#one-slice}

确定路径和切片 index 后，才开始实际的数组计算。每组 index 取值对应一个子任务：从输入张量中取出相应的数据，再按方案中的收缩路径得到该片结果。所有切片计算完后，将结果逐元素相加，得到原网络的收缩结果。

例如，一个维度为 2 的内部 index 被切片后，计算两个结果 $R_0$、$R_1$，最终结果为 $R=R_0+R_1$。这就是“按切片方案执行收缩”，不是再次搜索路径。

```diagram
slicing-execution
两个切片 index 的取值组合。连续编号分为一组；组内顺序累加，组间并行执行，最后按组编号合并结果。
```

```rust
use arctn::contract_network_sliced;

let output = contract_network_sliced(
    &net, &tensors, &ssa_path, &sliced_legs
)?;
```

## 并行计算与结果求和 {#native-chunks}

原生执行器把连续编号的切片分成若干组（chunk）。每组按切片编号顺序累加，Rayon 并行处理不同组；完成后再按组编号依次合并部分和。分组只依赖切片数和输出元素数，不依赖线程数。

| 项目 | 具体行为 |
| --- | --- |
| 分组数上限 | 最多 256，并受部分输出的元素数预算限制 |
| 线程变化 | 改变各组的完成时机，不改变分组和最终合并顺序 |
| 无切片 index | 直接调用 `contract_network` |
| 并发内存 | 同时执行的每个切片都有自己的输入副本和中间结果 |

线程数独立的归并顺序用于稳定单机浮点结果；它不意味着 MPI Allreduce 在不同 rank 数下也逐位相同。

## 总工作量与内存 {#cost-and-memory}

若切片数为 $N$，全部切片的二元收缩工作量为

$$
\begin{aligned}
F_{\mathrm{total}}&=NF_{\mathrm{slice}},\\
\log_{10}F_{\mathrm{total}}&=\log_{10}F_{\mathrm{slice}}+\log_{10}N.
\end{aligned}
$$

切片可能降低单片最大结果，同时因重复计算使总 FLOPs 上升；模型计数不含最终跨片求和的额外加法。

| 随切片增加通常下降 | 随切片增加通常上升 |
| --- | --- |
| 单片最大中间结果 | 完整执行的切片数 |
| 单个子任务的路径模型内存 | 总 FLOPs 和输入读取 |

`target_size` 只限制单片的二元收缩结果，单张量网络则检查最终输出。原始输入、一元预处理、转置临时量、后端工作区、部分和以及同时执行的其他切片都会增加实际 RSS。控制总内存时，还需考虑执行并行度。

## 三条执行路线 {#execution-routes}

| 路线 | 切片任务调度 | 单片收缩 | 结果累加 |
| --- | --- | --- | --- |
| Rust / Python native | Rust 按固定分组，用 Rayon 并行 | ArcTN Rust CPU 执行器 | 组内、组间均按编号顺序累加 |
| Python 外部后端 | Python 按固定顺序串行枚举 | 复用一个 `opt_einsum.contract_expression` | 在所选数组后端上相加 |
| tnmpi | 各进程执行不同的连续切片区间 | ArcTN Rust CPU 执行器；`--dtype` 支持四种实数 / 复数类型，见 [MPI 执行](/docs/mpi#run) | MPI Allreduce |

三条路线使用相同的数学分解，但任务调度、同步和浮点归并顺序不同。性能测试应注明执行路线。
