---
title: "网络化简"
description: "先对满足规则且腿数较少的局部张量执行确定性收缩，再把缩减网络路径接回原网络。"
eyebrow: "寻路算法"
---

## 化简到固定点 {#rules}

`simplify` 反复扫描当前活张量；每次收缩都会减少一个活张量，结构发生变化后从头扫描，直到没有规则可以继续应用。规则只依赖当前腿结构和秩。

```diagram
simplification-pass
三条规则都是精确的结构收缩；图中 rank 1 与 rank 2 是满足输出腿和 holder 条件的具体例子。任一规则改变网络后，扫描从头开始；无规则可用时得到 fixed point。
```

| 当前张量 | 确定性处理规则 |
| --- | --- |
| rank 0 标量 | 吸收到当前秩最小的另一个活张量 |
| rank 1 向量 | 吸收到共享其唯一腿的张量 |
| rank 2 矩阵 | 与共享腿的邻居收缩；仅当结果秩不高于该邻居原秩时应用 |
| rank ≥ 3 | 没有以此张量为起点的规则；仍可与满足规则的邻居收缩 |

> **精确的结构变换**
>
> 这里的 rank 是张量当前保留腿的数量。化简规则不是低秩近似，也没有奇异值截断。

网络化简规则循环的伪代码；省略函数外围

```rust
loop {
    let ids: Vec<usize> = (0..st.legs.len())
        .filter(|&i| st.alive(i))
        .collect();
    if ids.len() <= 1 { break; }
    let mut fired = false;
    for &i in &ids {
        if !st.alive(i) { continue; }
        match st.rank(i) {
            0 => {
                if let Some(j) = ids.iter().copied()
                    .filter(|&j| j != i && st.alive(j))
                    .min_by_key(|&j| st.rank(j))
                {
                    st.contract(i, j);
                    fired = true;
                }
            }
            1 => {
                let leg = st.legs[i].as_ref().unwrap()[0];
                if let Some(j) = st.other_holder(leg, i) {
                    st.contract(i, j);
                    fired = true;
                }
            }
            2 => {
                let legs = st.legs[i].as_ref().unwrap().clone();
                for &leg in &legs {
                    if let Some(j) = st.other_holder(leg, i) {
                        let result = st.result_legs(i.min(j), i.max(j));
                        if result.len() <= st.rank(j) {
                            st.contract(i, j);
                            fired = true;
                            break;
                        }
                    }
                }
            }
            _ => {}
        }
        if fired { break; }
    }
    if !fired { break; }
}
```

## Simplified 的保存内容 {#result}

| 字段 | 含义 |
| --- | --- |
| prefix | 已经确定的原网络 SSA 收缩步骤 |
| reduced | 保留原腿 ID 与输出顺序的缩减 TensorNetwork |
| map | 每个缩减输入张量所代表的原网络 SSA 节点 |

`stitch` 把缩减路径中的叶节点和新 SSA 节点映射回原网络编号，再接在 `prefix` 后面。最终交付的仍是原网络上的完整路径。

stitch 的 SSA 编号映射伪代码；省略函数签名

```rust
let base = n_orig + prefix.len();
let trans = |x: usize| -> usize {
    if x < map.len() { map[x] } else { base + (x - map.len()) }
};
let mut full = prefix.clone();
for &(a, b) in reduced_path {
    let (x, y) = (trans(a), trans(b));
    full.push((x.min(y), x.max(y)));
}
```

## 在缩减网络上寻路 {#rust-usage}

```rust
use arctn::{random_greedy, simplify, simulate_path, stitch};

let reduced = simplify(&net);
let (reduced_path, _) = random_greedy(&reduced.reduced, 64, 7)?;
let path = stitch(
    net.n_tensors(),
    &reduced.prefix,
    &reduced.map,
    &reduced_path,
);
let stats = simulate_path(&net, &path)?;
```

若只需要这一常用组合，`random_greedy_simplified` 会完成网络验证、化简、缩减网络 random-greedy、stitch 和原网络重放。得到的路径属于原始完整网络，因此可以与其他完整路径使用同一 evaluator 比较。

## 公开入口与边界 {#interfaces}

| 入口 | 返回内容 | 是否运行完整寻路 |
| --- | --- | --- |
| simplify | Simplified { prefix, reduced, map } | 否 |
| stitch | 原网络完整 SSA path | 否 |
| random\_greedy\_simplified | 完整路径与 PathStats | 只运行缩减网络 random-greedy，不运行 Auto |
| arctn\_simplify | Python 化简统计、前缀和缩减结构信息 | 否 |

> **能力边界**
>
> 网络化简不是数值执行后端，也不会修改张量网络所表示的数学收缩。只查看 arctn\_simplify 的张量数统计，不能代替生成并验证一条完整路径。

> [!WARNING]
> **fixed point 不等于最优化简**
>
> `simplify` 按当前确定性扫描规则反复应用可用收缩，直到这一规则集的 fixed point。它不保证得到所有可能化简结果中张量数最少的网络，也不保证 prefix 对规划目标最优。调用低层 Rust API 时，应先验证网络，并在 `stitch` 后用 `simulate_path` 复核原网络上的完整路径。

> **API 层级**
>
> 低层化简 API 可独立调用；Light 与 Heavy 的内部组合和调度不属于该 API 的接口定义。
