Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

前言与阅读路线

本教程讨论 Presburger 算术如何成为 polyhedral analysis 的表示语言,并把表示、依赖、调度和代码生成放进一条连续推理链。读者应熟悉线性代数、离散数学和一阶逻辑的基本记号,并已见过简单循环优化或 Polyhedral Model 的最小例子;无需预先掌握整数规划或完整的编译器实现。

这里的 Presburger Algebra 是一个教学用简称:它指 Presburger 可定义集合/关系及其并、交、补、投影、逆、复合、像和逆像等闭包运算。它不是一个独立于 Presburger arithmetic 的标准理论名称。全文还会明确区分自然数版与整数版 Presburger 算术、实数多面体与其整数格点、单个凸多面体与一般 Presburger 集合。

十二章路径

  1. Polyhedral Model 的最小回顾:从静态控制部分、语句实例和参数出发,说明为什么循环优化关心整数格点。
  2. Presburger 算术的语法与语义:区分自然数与整数版本,建立加法、序、量词、整除和同余的边界。
  3. 可判定性、量词消去与表达能力:解释可判定性、Cooper 消元、投影及变量乘法和间接访问的表达边界。
  4. Presburger 集合与关系代数:学习集合、映射、关系、逆、复合、像、逆像、投影和词典序。
  5. 半线性集合、格点与多面体:区分半线性等价、凸多面体、整数点、析取和周期结构。
  6. 循环程序的关系建模:把迭代域、读写访问、语句身份和原始顺序写成关系。
  7. 数据依赖分析:从同址候选到精确 RAW、WAR、WAW 和最后写入者,包含归约的边界。
  8. 仿射调度:用整数时间戳和词典序表示顺序,区分合法性、并行性与局部性。
  9. Farkas 引理与调度约束有限化:把“对所有依赖实例”成立的条件转成有限系数约束,并定位整数规划的角色。
  10. 调度变换:比较 interchange、fusion、distribution、skewing、strip-mining、tiling 和 wavefront 的合法性与性能目标。
  11. 扫描与代码生成:从调度像空间扫描整数点,恢复含 floor、ceil、min、max、步长和参数分支的循环 AST。
  12. 端到端案例与工具表示:以二维时间—空间 stencil 串联 SCoP 识别、建模、依赖、调度、变换、AST 与 isl/Omega 风格表示。

三种阅读方式

数学主线:按第 2 → 3 → 4 → 5 → 9 → 11 章阅读,再以第 12 章检查这些定义怎样落到程序。它适合希望先建立可表达性、消元、关系运算和整数点语义的人。

编译器主线:按第 1 → 6 → 7 → 8 → 10 → 11 → 12 章阅读;遇到符号或定理时回看第 2、4、5、9 章。它适合已有循环优化直觉、希望追踪编译器调用链的人。

完整主线:从第 1 章顺序读到第 12 章。每章都依照“直觉 → 形式定义 → 手算示例 → 编译器用途 → 常见误区 → 练习”的模板推进;二维时间—空间 stencil 是贯穿案例,矩形域、三角域、同余/步长、析取、多语句、归约与非仿射反例用于检验边界。

开始第 1 章前,尤其要记住:依赖关系恒写作 source → sink,且实数多面体 $P$ 与整数点集 P ∩ ℤ^d 不可混用。全书统一记号可随时查阅附录中的术语与符号速查,原始论文与官方工具资料按学习目标整理在延伸阅读路径中;附录还给出全部 78 道练习的参考答案。

第 1 章:Polyhedral Model 的最小回顾

直觉

Polyhedral Model 把循环程序的一部分执行结构改写成几何对象。一个循环迭代对应整数格上的一个点;循环边界给出点必须满足的不等式;数组下标给出从迭代点到内存位置的映射。这样,交换循环、融合循环或改变执行次序,就可以转化为对整数点及其关系的变换。

这里首先要分清两层对象。设 $d$ 为循环嵌套的维数,$P \subseteq \mathbb{R}^d$ 表示实数空间中的有理多面体;真正会执行的实例却属于整数点集 $P \cap \mathbb{Z}^d$。图上画出的连续三角形或矩形只是“实数形状”,编译器必须处理的是其中离散的整数格点。二者有联系,但不是同一个集合。

Polyhedral Model 通常从 静态控制部分(static control part,SCoP)出发:循环边界、分支条件和数组下标都能由外围参数与循环变量的仿射式描述,并且控制结构不依赖运行时数组值。SCoP 是工程上的可分析程序区域,不是“任何使用数组的循环”的同义词。这种以仿射域、访问和变换组织循环程序的工程路线可参照 Pluto 项目/作者资料页;从 polyhedra 扫描整数点并恢复循环的经典表述参见 Bastoul 2004。两处引用用于定位经典模型与工程语境,不替代本章对具体公式的推导。

形式定义

令 $m$ 表示参数个数,$p=(p_1,\ldots,p_m)$ 表示参数向量。参数是在所分析区域内保持不变、但编译时未必知道具体数值的整数,例如矩阵尺寸 $N$ 和 $M$。只约束参数的公式记为 $C(p)$,称为参数上下文。例如

$$ p=(N,M),\qquad C(p): N\ge 0\land M\ge 0. $$

令 $S$ 表示一条语句,$x=(i_1,\ldots,i_d)$ 表示它的一次语句实例迭代向量。语句 $S$ 的参数化迭代域记为

$$ D_S(p)\subseteq \mathbb{Z}^d. $$

因此 $x \in D_S(p)$ 表示实例 $x$ 会执行;完整条件写作 $C(p) \land x\in D_S(p)$,避免把参数误当成迭代坐标。

本章所说的仿射式

$$ a_0+a_1i_1+\cdots+a_di_d+b_1p_1+\cdots+b_mp_m, $$

其中所有系数 $a_r$、$b_s$ 都是固定整数。仿射边界和数组下标允许常数乘变量,例如 2i+N-1;不允许两个一般变量相乘,例如 ij

共同符号契约把抽象内存位置集合记为 $M$。由于本章的矩形例已用 $M$ 表示尺寸,在两者同现时临时写作 M_{mem};它只是该内存集合的消歧别名。读访问关系 $R_S \subseteq D_S\times M_{mem}$、写访问关系 $W_S \subseteq D_S\times M_{mem}$ 都按“语句实例 $\to$ 内存位置”读取。例如

$$ ((i,j),A[i,j])\in R_S $$

表示实例 (i,j) 读取数组元素 A[i,j]

手算示例

矩形域

令 $N,M\in\mathbb{Z}$ 且参数上下文为 $N\ge0\land M\ge0$。矩形域定义为

$$ D_{\mathrm{rect}}(N,M)= \{(i,j)\in\mathbb{Z}^2\mid 0\le i<N\land 0\le j<M\}. $$

N=3M=2,逐行固定 $i$ 可得

$$ D_{\mathrm{rect}}(3,2) =\{(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)\}. $$

它的实数松弛是

$$ P_{\mathrm{rect}}(3,2)= \{(u,v)\in\mathbb{R}^2\mid 0\le u<3\land0\le v<2\}. $$

例如 (1/2,1) 属于这个实数形状,却不是循环实例;循环只执行 $P_{\mathrm{rect}}(3,2)\cap\mathbb{Z}^2$ 中的点。严格上界使该实数集合不是闭多面体;在整数语义下可等价改写为 $i\le N-1$、$j\le M-1$,得到通常使用的闭不等式描述。

三角域

令 $N\in\mathbb{Z}$,并把循环尺寸的参数上下文规定为 $C(N):N\ge0$。在此上下文下,三角域定义为

$$ D_{\mathrm{tri}}(N)= \{(i,j)\in\mathbb{Z}^2\mid0\le i<N\land0\le j\le i\}. $$

取 $N=4$:当 $i=0,1,2,3$ 时,$j$ 分别取 $0$、$\{0,1\}$、$\{0,1,2\}$、$\{0,1,2,3\}$,所以

$$ D_{\mathrm{tri}}(4) = \left\{ \begin{aligned} &(0,0),\\ &(1,0),(1,1),\\ &(2,0),(2,1),(2,2),\\ &(3,0),(3,1),(3,2),(3,3) \end{aligned} \right\}. $$

点数为 $1+2+3+4=10$。边界 $j\le i$ 把两个循环变量线性联系起来,因此它仍是仿射约束。

数据运算不等于下标运算

考虑矩阵乘法内部语句

C[i][j] += A[i][k] * B[k][j];

若 $i$、$j$、$k$ 的循环边界仿射,访问 C[i][j]A[i][k]B[k][j] 的下标也都是仿射的。右侧 A[i][k] * B[k][j] 确实做了乘法,但相乘的是从内存读出的数据值,不是用来决定控制流或地址的循环变量。因此该乘法不违反经典 SCoP 对控制和下标的仿射限制。

编译器用途

把每次执行显式表示成整数点后,编译器可以分别记录:

  • 域 $D_S(p)$:哪些实例存在;
  • 访问关系 $R_S$、$W_S$:每个实例读写哪里;
  • 调度:每个实例在什么逻辑时间执行。

这些对象共同支持后续的依赖分析和循环变换。特别要注意,本章只建立表示条件:某段程序可被建模,并不自动说明任意变换都合法;合法性还要由 source 实例到 sink 实例的依赖顺序证明。

矩形域常对应彼此独立的规则循环,三角域常对应带迭代变量相关仿射边界(如 $j\le i$)的嵌套循环。二者都能用仿射不等式描述,所以可以交给整数集合/关系工具做求交、投影和扫描。

常见误区

  1. 把实数图形等同于执行集合。 $P\subseteq\mathbb{R}^d$ 包含连续点,程序实例是 $P\cap\mathbb{Z}^d$。在实数上消去严格不等式、取凸包或做松弛时,必须检查是否保持所需的整数语义。
  2. 认为程序中不能出现任何乘法。 限制针对控制条件和地址函数。A[i][k] * B[k][j] 的数据值乘法不改变迭代域或访问下标,因此可以留在语句体内。
  3. 把参数和循环坐标混在一起。 $N$、$M$ 属于参数向量 $p$,$i$、$j$ 属于实例 $x$;应写 $C(p)\land x\in D_S(p)$。
  4. 把所有数组表达式都当成仿射访问。 A[i*i] 的下标含变量乘变量;A[B[i]] 的地址依赖运行时数组值;while (A[i] > 0) 的迭代次数依赖运行时数据。三者都越过经典 SCoP/Presburger 建模边界。运行时检查、保守近似或扩展模型可以处理部分情况,但那是另外的技术路线,不能把原表达式悄然当成精确仿射模型。
  5. 从“能表示”直接跳到“优化有效”。 表示、变换合法性和性能收益是三个不同问题。

练习

练习 EX01-B01|矩形域枚举与计数(基础)

枚举 $D_{\mathrm{rect}}(2,3)$ 的全部整数点,并写出点数关于 $N,M$ 的公式。

答案索引: ANS-EX01-B01

练习 EX01-D01|三角域计数与语言边界(推导)

枚举 $D_{\mathrm{tri}}(5)$,验证点数为 $N(N+1)/2$。这里的乘法出现在分析者给出的计数公式中;说明它为何不等于在 Presburger 域公式里加入变量乘法。

答案索引: ANS-EX01-D01

练习 EX01-B02|仿射下标判定(基础)

判断下列下标是否仿射,并说明理由:A[2*i+N]A[i+j]A[i*j]A[index[i]]

答案索引: ANS-EX01-B02

练习 EX01-C01|参数化斜三角域(综合)

for (i=0;i<N;i++) for (j=i;j<M;j++) S(i,j); 写出参数上下文和迭代域。若 $N>M$,域会发生什么?

答案索引: ANS-EX01-C01

本章小结

Polyhedral Model 的基本对象不是连续图形本身,而是参数化仿射约束所选出的整数语句实例。参数上下文、迭代域和访问关系分别回答“尺寸是否合法”“哪些实例执行”“实例访问哪里”。经典 SCoP 允许语句体中的一般数据计算,但要求控制和地址保持仿射且不依赖运行时数组值。下一章将用 Presburger 算术精确说明这些整数集合能够使用哪些公式表达。

第 2 章:Presburger 算术的语法与语义

直觉

第 1 章把循环实例看成整数点,本章回答一个更基础的问题:可以用什么样的逻辑公式挑选这些点?Presburger 算术允许整数常量、加法、比较、布尔组合和量词。它足以表达仿射边界、析取、投影以及固定周期的步长,却刻意排除一般的变量乘变量。

“允许固定常数乘变量”与“不允许变量乘变量”是核心分界。例如 3y 只是 y+y+y 的缩写;yz 中乘数 $z$ 随赋值变化,不能展开成固定次数的加法。

Presburger 1929 年的原始工作建立了这一加法算术体系的完备性与可判定性;这里采用整数编译器建模所需的语法,并在涉及历史定理时回溯其稳定英文译注

形式定义

语言和项

令 $\mathcal{L}_{PA}$ 表示本章使用的一阶语言,论域先取整数集合 $\mathbb{Z}$。变量记为 x,y,z,k;整数常量记为 $c\in\mathbb{Z}$。线性项 $t$ 可写为

$$ t ::= c\mid x\mid t+t\mid -t. $$

等价地,每个线性项都可整理为

$$ t=c+a_1x_1+\cdots+a_nx_n, $$

其中 $a_1,\ldots,a_n\in\mathbb{Z}$ 是固定系数。a_ix_i 表示常数乘法;它不是两个变量的乘积。

原子公式和公式

由线性项构造原子公式 t_1=t_2 和 $t_1\le t_2$。严格序 t_1<t_2 是 $t_1\le t_2\land t_1\ne t_2$ 的缩写;在整数上也可写成 $t_1+1\le t_2$。再用布尔联结词和量词构造公式:

$$ \varphi ::= t_1=t_2\mid t_1\le t_2 \mid\neg\varphi\mid(\varphi\land\varphi)\mid(\varphi\lor\varphi) \mid\exists x\,\varphi\mid\forall x\,\varphi. $$

蕴含 $\varphi\Rightarrow\psi$ 是 $\neg\varphi\lor\psi$ 的缩写。给定固定正整数 $m$,整除原子 $m\mid t$ 和同余原子

$$ t_1\equiv t_2\pmod m $$

常作为便于量词消去的扩展语法;其语义分别是“存在整数 $q$ 使 t=mq”和 $m\mid(t_1-t_2)$。因此它们不增加可定义集合,只让公式更紧凑。

赋值、自由变量与真值

变量赋值 $\sigma$ 把每个自由变量映到一个整数。记 $\llbracket t\rrbracket_\sigma$ 为线性项 $t$ 在赋值 $\sigma$ 下的整数值。满足关系 $\mathbb{Z},\sigma\models\varphi$ 递归定义如下:等式和序比较相应整数值;布尔联结词采用通常真值规则;并且

$$ \mathbb{Z},\sigma\models\exists x\,\varphi \quad\Longleftrightarrow\quad \text{存在 }a\in\mathbb{Z},\quad \mathbb{Z},\sigma[x\mapsto a]\models\varphi. $$

全称量词类似。$FV(\varphi)$ 表示公式 $\varphi$ 的自由变量集合,即未被量词绑定的变量。例如

$$ FV(\exists k:\ x=3k+1)=\{x\}. $$

没有自由变量的公式称为句子,它在整数结构中只有真或假,不再依赖外部赋值。

自然数版和整数版

若量词与赋值范围取非负整数集合 $\mathbb{N}=\{0,1,2,\ldots\}$,得到自然数版;本教程的循环坐标、差值和调度统一使用整数版 $\mathbb{Z}$。两者不能在推导中无提示地混用。例如整数版的 $\exists x:x+1=0$ 为真,自然数版为假。

需要搬运集合结论时,可把一个整数坐标 $z$ 编码成两个非负坐标之差 z=z^+-z^-,其中 $z^+,z^-\in\mathbb{N}$,并同步改写公式。Ginsburg–Spanier 对 modified Presburger formulas 与半线性集等价的直接论域是 $\mathbb{N}^n$;整数版必须先做这类显式编码,不能省略域的变化。参见其原始论文

手算示例

逐式判断表达能力

谓词是否可表达理由或等价写法
x = 3y + 232 是固定常数,右侧是线性项。
x ≡ 1 (mod 3)可作扩展同余原子,或写成 $\exists k\in\mathbb{Z}:x=3k+1$。
x = yz一般否$y$、$z$ 都是变量,这是一般变量乘变量,不是固定次数的加法。若乘法图可定义,令 z=y 便会得到平方图。
x = y²一般否$y^2=y\cdot y$ 仍是变量乘变量。若平方图可定义,投影 $y$ 就能定义所有平方数;但一元 Presburger 集合最终呈固定周期,平方数间距却无界增长。
∃k: x = 3k + 1$k$ 被存在量词绑定,矩阵仍是线性等式;它恰好定义余数为 1 的整数。
(0 ≤ x ≤ N) ∨ (2N ≤ x ≤ 3N)两个仿射区间的析取;$N$ 是自由参数,所有乘数都是固定常数。

表中的“一般否”强调统一的无限整数关系。若把所有变量限制在某个固定有限集合,当然可以穷举成有限析取,但这不等于得到对任意参数规模都有效的 Presburger 乘法定义。

析取例子的自由变量集合是 {x,N}。若外层另给参数上下文 $C(N):N\ge0$,它定义两个可能分离的整数区间,说明一般 Presburger 集合不必是单个凸多面体。

非单位步长循环

考虑

for (int i = 1; i < N; i += 3) S(i);

引入整数迭代计数 $k\in\mathbb{Z}$。初始化对应 k=0、第 $k$ 次执行时 i=1+3k,且循环只沿正方向执行,因此域可写成

$$ D_S(N)=\{i\in\mathbb{Z}\mid \exists k\in\mathbb{Z}: i=1+3k\land0\le k\land i<N\}. $$

i=1+3k 和 $k\ge0$ 可得 $i\ge1$ 以及 $i\equiv1\pmod3$。反过来,若 $i\ge1$ 且 $i\equiv1\pmod3$,则存在整数 $k=(i-1)/3\ge0$。所以等价的同余写法是

$$ D_S(N)=\{i\in\mathbb{Z}\mid1\le i<N\land i\equiv1\pmod3\}. $$

N=11,从 k=0 开始手算:

$$ k=0,1,2,3\quad\Longrightarrow\quad i=1,4,7,10. $$

k=4i=13,已不满足 i<11。因此全部实例恰为

$$ D_S(11)=\{1,4,7,10\}. $$

若只保留区间 $1\le i<N$,就会得到 {1,2,3,4,5,6,7,8,9,10},其中 2,3,5,6,8,9 是原循环从不到达的虚假实例。区间描述丢掉了模 3 的周期信息。

编译器用途

Presburger 公式给编译器一种统一方式来表示:

  • 仿射循环边界与参数上下文;
  • if 条件形成的交、并、补;
  • 非单位步长形成的同余类;
  • 引入辅助变量后的投影,即存在量词;
  • 对所有候选实例成立的合法性条件,即全称量词。

自由变量决定一个公式描述什么坐标空间。对 $\varphi(i,j,N)$,若把 $N$ 视为参数,则固定 $N$ 后自由迭代坐标是 (i,j);若消去 $j$,所得公式只描述 (i,N)。后续的集合与关系代数会把这种变量角色显式组织成输入、输出和参数空间。

同余不是装饰信息。若分析器把 i += 3 松弛为普通区间,后续依赖测试可能报告并不存在的实例和冲突;精确整数模型必须保留步长带来的周期结构。

常见误区

  1. 把固定常数乘法与一般乘法混为一谈。 7x 合法,因为 7 固定;xy 不合法,因为重复加法次数由变量决定。
  2. 认为存在量词让任意运算都可表达。 $\exists k:x=3k+1$ 仍只含线性项;增加量词不会把 x=yz 变成线性公式。
  3. 混用 $\mathbb{N}$ 与 $\mathbb{Z}$。 负数见证可能改变句子真值。若从自然数结果搬到整数,必须给出编码。
  4. 认为同余是额外的非线性能力。 固定模数同余可展开为带存在量词的线性等式,它仍处于 Presburger 范围内。
  5. 认为析取仍一定是一个凸域。 两个分离区间的并可以由公式表达,却不能当成单个凸多面体。
  6. 把数据依赖控制或地址的表达式强行线性化。 A[i*i]A[B[i]]while (A[i] > 0) 分别引入非线性下标、间接下标和数据相关控制;删掉这些信息得到的只是近似,不是原程序的精确 Presburger 语义。

练习

练习 EX02-B01|同余的量词形式与自由变量(基础)

写出谓词 $x\equiv2\pmod5$ 的存在量词形式,并求其自由变量集合。

答案索引: ANS-EX02-B01

练习 EX02-D01|Presburger 可定义性判定(推导)

判断 $x=4y-N$、$x=Ny$、$x=y+z$、$x=|y|$ 是否可定义。对最后一式尝试用析取展开绝对值。

答案索引: ANS-EX02-D01

练习 EX02-D02|固定步长循环建模(推导)

for (i=2; i<=20; i+=4) 写成存在量词形式与同余形式,并枚举全部实例。

答案索引: ANS-EX02-D02

练习 EX02-B02|整数版与自然数版真值(基础)

在整数版和自然数版中分别判断 $\exists x:2x+1=0$ 的真值,并说明这道命题对区分两个论域的诊断力为何有限。

答案索引: ANS-EX02-B02

练习 EX02-C01|析取域的参数边界(综合)

对 $\varphi(i,N):(0\le i<N)\lor(2N\le i<3N)$,分别讨论 $N=0$、$N=2$ 时定义的集合。

答案索引: ANS-EX02-C01

本章小结

整数版 Presburger 算术以线性项、比较、布尔联结词和量词描述整数点集。固定常数乘变量、固定模数同余、析取和投影都可表达;一般变量乘变量、非线性或数据相关地址则不在经典边界内。非单位步长例子显示,整数集合不仅需要区间,也需要同余所携带的周期信息。

第 3 章:可判定性、量词消去与表达能力

直觉

一个逻辑理论可判定,是说存在一个总会停机的算法,能够对该理论中任意句子回答“真”或“假”。这是一项关于算法存在性与终止性的保证,不是关于日常运行成本的保证。公式变长、量词交替增加、系数或模数变大时,中间公式可能急剧膨胀;所以“Presburger 算术可判定”绝不等于“每个编译器查询都廉价”。可判定性的历史依据可追溯到 Presburger 的原始工作英文译注

量词消去试图把含量词的公式改写为不含相应量词、但对剩余自由变量等价的公式。对集合而言,消去一个存在量词就是投影掉一个坐标:保留下来的点,正是至少存在一个被删除坐标使原约束成立的点。

整数与实数的消元有一个关键差异:整数点带有整除和余数条件。Cooper 的方法通过规范化被消去变量的系数,并显式处理界与固定模数,给出整数线性算术的量词消去路线;本章依据其1972 年原文解释思想。

形式定义

令 $Th(\mathbb{Z},+,\le)$ 表示整数加法与序的一阶理论,即所有在结构 $(\mathbb{Z},0,1,+,\le)$ 中为真的句子集合。称它可判定,若存在算法 Decide,对任意该语言中的句子 $\psi$ 都在有限时间内终止,并满足

$$ Decide(\psi)=\texttt{true} \quad\Longleftrightarrow\quad \mathbb{Z}\models\psi. $$

m,n 为非负整数。若公式 $\varphi(x,y)$ 的自由变量包含坐标向量 $x\in\mathbb{Z}^m$ 和 $y\in\mathbb{Z}^n$,则消去 $y$ 是寻找只含 $x$ 的公式 $\widehat\varphi(x)$,使

$$ \mathbb{Z}\models \widehat\varphi(x)\leftrightarrow\exists y\,\varphi(x,y). $$

对由 $\varphi$ 定义的集合

$$ X=\{(x,y)\in\mathbb{Z}^{m+n}\mid\varphi(x,y)\}, $$

令 $I_x$ 表示 $X$ 中属于向量 $x$ 的坐标索引集合。按照全文契约,保留坐标集合 $I$ 的投影统一记为 proj_I(X);因此这里保留 $x$ 坐标的投影写作 $\operatorname{proj}_{I_x}(X)$,并满足

$$ \operatorname{proj}_{I_x}(X) =\{x\in\mathbb{Z}^m\mid\exists y\in\mathbb{Z}^n:\varphi(x,y)\}. $$

在只含 $0,1,+,\le$ 的基础语言里,消元结果未必能方便地写成单个合取。Cooper 风格消元通常在加入固定模数整除原子的扩展语言中得到量词自由的布尔组合;这些整除原子本身又可用存在量词线性定义。这里的“量词消去”应按这种常用扩展语法理解,而不是声称每个结果都是单个凸多面体。

手算示例

一个 Cooper 风格的教学性小推导

考虑自由参数 $a,b\in\mathbb{Z}$ 和公式

$$ \Phi(a,b):\quad \exists x\in\mathbb{Z}: a\le2x\le b\land x\equiv1\pmod3. $$

第一步是把被消去变量前的非单位系数规范化。令新变量 z=2x。条件 $x\equiv1\pmod3$ 等价于存在 $q\in\mathbb{Z}$ 使 x=3q+1,从而

$$ z=2x=6q+2 \quad\Longleftrightarrow\quad z\equiv2\pmod6. $$

反向也成立:若 z=6q+2,则 z=2(3q+1),可取 x=3q+1。因此

$$ \Phi(a,b)\quad\Longleftrightarrow\quad \exists z\in\mathbb{Z}:a\le z\le b\land z\equiv2\pmod6. $$

现在只需判断闭区间 [a,b] 是否含有一个模 62 的整数。按 $a$ 的余数分六种情况。令 $\delta_r$ 表示当 $a\equiv r\pmod6$ 时,从 $a$ 向上到最近目标余数 2 的距离,则

$$ (\delta_0,\delta_1,\delta_2,\delta_3,\delta_4,\delta_5) =(2,1,0,5,4,3). $$

最小候选是 $z=a+\delta_r$;区间中存在目标点当且仅当该候选不超过 $b$。于是量词自由结果为

$$ \bigvee_{r=0}^{5} \left(a\equiv r\pmod6\land a+\delta_r\le b\right). $$

例如 a=7,b=9 时,$a\equiv1\pmod6$,最近候选是 8,故公式为真,对应 x=4a=9,b=12 时,$a\equiv3\pmod6$,最近候选是 14>b,故为假。

这个推导展示了三件事:通过公倍数/换元整理系数、从下界产生有限候选、用模条件枚举有限余数类。它是教学性小例子,不冒充完整 Cooper 算法。完整算法还必须系统处理否定范式、多个上下界、无界情形、多个整除条件、系数的最小公倍数以及消元后的公式化简;其正确性不能由本例替代。

三角域的投影

令 $N\in\mathbb{Z}$,并定义整数点集

$$ X_{\mathrm{tri}}(N)= \{(i,j)\in\mathbb{Z}^2\mid0\le j\le i\land0\le i<N\}. $$

当它表示第 1 章的循环域时,采用尺寸参数上下文 $C(N):N\ge0$。在有序坐标 (i,j) 中,令索引集合 $I=\{1\}$ 表示只保留第一维 $i$;依照契约,所求投影记为 $\operatorname{proj}_{I}(X_{\mathrm{tri}}(N))$。对应的存在量词公式是

$$ \exists j\in\mathbb{Z}: 0\le j\le i\land0\le i<N. $$

它表示从三角域中投影掉 $j$,只保留 $i$。分两向证明:

  • 若存在 $j$ 满足 $0\le j\le i$,则由传递性得到 $0\le i$;原式又直接给出 i<N
  • 若 $0\le i<N$,取见证 j=0,便有 $0\le j\le i$。

所以精确的消元结果是

$$ \exists j: 0\le j\le i\land0\le i<N \quad\Longleftrightarrow\quad 0\le i<N. $$

等价地,

$$ \operatorname{proj}_{I}(X_{\mathrm{tri}}(N)) =\{i\in\mathbb{Z}\mid0\le i<N\}. $$

这个等价式对每个整数 $N\in\mathbb{Z}$ 都成立:若 N<0,左右两侧同为空集;$C(N):N\ge0$ 只是把 $N$ 解释为合法循环尺寸时采用的参数语义,并不是上述逻辑等价成立的前提。几何上,投影把三角域的所有整数点沿 $j$ 轴压到 $i$ 轴;逻辑上的存在量词与集合上的投影是同一件事的两种表述。

编译器用途

投影和可满足性查询贯穿 polyhedral 编译:

  • 从含辅助计数器 $k$ 的步长域中消去 $k$,得到关于循环变量的区间与同余条件;
  • 从实例—内存位置关系中消去内存坐标或实例坐标,计算像、逆像和候选冲突;
  • 从多维约束中逐层消去内层坐标,推导外层循环边界或运行时 guard;
  • 判断某个依赖关系是否为空,或变换后的非法次序是否存在。

这里必须区分两种结论。判定过程回答的是“某个整数公式是否有解/是否恒真”;优化器还要考虑公式表示规模、消元顺序和最坏情况爆炸。工程工具通常会选择受限片段、启发式顺序、缓存和近似,以控制成本。Pugh 的 Omega Test 是整数仿射约束在编译器依赖分析中的经典判定路线,但不能因此泛称为任意 Presburger 输入都同样廉价。

常见误区

  1. 把可判定理解成高效。 “总会停机并给出正确真值”没有给出小的时间或空间上界;量词消去可能产生大量析取与同余条件。
  2. 把整数投影当成实数区间投影。 实数消元可能漏掉整数整除条件。例如 $\exists x:z=2x$ 在实数上对每个 $z$ 都有解,在整数上只定义偶数 $z$。
  3. 认为消元结果必是一个凸多面体。 模条件和析取会产生周期或非凸集合;一般 Presburger 集合比单个凸多面体更广。
  4. 把教学推导当成 Cooper 全算法。 本章只演示系数规范化、界和余数类的核心思想,没有覆盖算法的全部分支与复杂度控制。
  5. 用量词消去越过语言边界。 A[i*i] 含非线性地址,A[B[i]] 含运行时决定的间接地址,while (A[i] > 0) 含数据相关控制。Cooper 消元只处理整数线性公式,不会把这些表达式自动变成精确 Presburger 约束。运行时检查、保守近似或扩展模型必须被明确标成另外的路线。
  6. 把存在性与实际执行顺序混为一谈。 投影能回答“是否存在匹配坐标”,但精确依赖还需要原始顺序、访问方向以及最后写等语义,不能仅凭同址存在性完成。

练习

练习 EX03-D01|偶数区间的量词消去(推导)

消去 $\exists x:c\le x\le d\land x\equiv0\pmod2$ 中的 $x$。按 $c$ 的奇偶性写出量词自由公式。

答案索引: ANS-EX03-D01

练习 EX03-D02|带正下界的三角投影(推导)

对 $\exists j:1\le j\le i\land0\le i<N$ 求关于 $i$ 的投影,并指出它与本章三角域投影的边界差异。

答案索引: ANS-EX03-D02

练习 EX03-B01|仿射像与同余类(基础)

判断 $\exists x:z=4x+1$ 定义哪一个同余类;解释为什么只写 $z\ge1$ 不等价。

答案索引: ANS-EX03-B01

练习 EX03-C01|析取投影构造(综合)

给出一个含析取的二维整数集合,使其投影仍是两个分离区间;写出集合、逐分支存在见证,并手算投影。

答案索引: ANS-EX03-C01

练习 EX03-B02|查询种类辨析(基础)

分别说明下列三项查询的种类:(1)固定 $N=N_0$,判断 $\exists i:\varphi(i,N_0)$ 是否成立;(2)判断带参数上下文的全称蕴含 $\forall i(\varphi\Rightarrow\psi)$ 是否有效;(3)求 $\exists j:\varphi(i,j)$ 的等价无 $j$ 公式。再说明若第(1)项不固定 $N$,它与投影的关系。

答案索引: ANS-EX03-B02

本章小结

Presburger 算术的可判定性保证句子真值可由终止算法决定,却不保证查询廉价。量词消去把存在量词转成对剩余变量的等价约束;在整数域中,界之外还必须保留整除和同余信息。三角域说明投影就是存在量词消去,Cooper 风格小例子则说明整数消元为何需要有限余数分类。该能力为后续集合、关系、依赖与代码生成提供逻辑基础,但不覆盖非线性下标、间接访问或数据相关控制。

第 4 章:Presburger 集合与关系代数

直觉

前两章把 Presburger 公式看作真假命题。本章换一个同等重要的视角:固定参数后,让自由变量遍历整数格点,满足公式的点就组成一个集合;把自由变量分成输入、输出两组,满足公式的点对就组成一个关系。于是,逻辑中的合取、析取、否定和存在量词,分别成为集合/关系的交、并、补和投影。

这种视角正是 polyhedral 编译器的接口语言。循环实例是集合,数组访问是从实例到内存位置的关系,调度是从实例到时间戳的关系或函数。分析过程不是在若干无类型的公式之间“拼字符串”,而是在带有明确源空间和目标空间的对象之间做代数运算。

本章始终采用如下方向约定:

$$ R\subseteq X\times Y \quad\text{读作}\quad R:X\to Y. $$

若 $(x,y)\in R$,则沿着关系从 $x$ 走到 $y$。这只是关系的类型和方向;关系不必是单值函数,也不必覆盖整个 $X$。

形式定义

从自由变量到集合与关系

令 $p\in\mathbb Z^m$ 是参数向量,$C(p)$ 是只约束参数的上下文。若 $\varphi(x,p)$ 是 Presburger 公式,且 $x\in\mathbb Z^d$ 是它的一组自由变量,则它定义参数化集合

$$ S(p)=\{x\in\mathbb Z^d\mid C(p)\land\varphi(x,p)\}. $$

若自由变量被分成 $x\in X\subseteq\mathbb Z^d$ 与 $y\in Y\subseteq\mathbb Z^e$ 两组,公式 $\psi(x,y,p)$ 定义参数化关系

$$ R(p)=\{x\to y\mid C(p)\land\psi(x,y,p)\}\subseteq X\times Y. $$

箭头左、右两侧的 tuple 空间是类型的一部分。例如,语句实例空间 $D_S$、内存空间 $M$ 和时间空间 $\mathbb Z^k$ 即使维数碰巧相同,也不能因此互换。访问关系 $W_S:D_S\to M$ 与调度 $\theta_S:D_S\to\mathbb Z^k$ 是不同类型的对象。

基本运算及其逻辑含义

设 $A,B\subseteq X$,$R\subseteq X\times Y$,$Q\subseteq Y\times Z$。以下定义同时给出代数运算和相应公式。

运算形式定义逻辑操作
$A\cup B=\{x\mid x\in A\lor x\in B\}$析取
$A\cap B=\{x\mid x\in A\land x\in B\}$合取
$A\setminus B=\{x\mid x\in A\land x\notin B\}$合取与否定
相对补$X\setminus A=\{x\in X\mid x\notin A\}$在指定全集内否定
投影$\operatorname{proj}_I(S)=\{x_I\mid\exists x_{\bar I}:x\in S\}$消去其余坐标
定义域$\operatorname{domain}(R)=\{x\mid\exists y:(x,y)\in R\}$投影到输入
值域$\operatorname{range}(R)=\{y\mid\exists x:(x,y)\in R\}$投影到输出
逆关系$R^{-1}=\{y\to x\mid(x,y)\in R\}$交换两组自由变量
$R[A]=\{y\mid\exists x:x\in A\land(x,y)\in R\}$限制输入后投影
逆像$R^{-1}[B]=\{x\mid\exists y:y\in B\land(x,y)\in R\}$限制输出后投影
复合$Q\circ R=\{x\to z\mid\exists y:R(x,y)\land Q(y,z)\}$在中间空间连接并消去

补集必须说明全集。$\mathbb Z\setminus A$、区间 $U\setminus A$ 和参数上下文内的补集通常不同。关系的并、交、差也要求两侧具有同一类型 $X\to Y$;复合则要求前一关系的输出类型与后一关系的输入类型相同。

投影就是存在量化的集合语义。Cooper 的整数线性算术消元给出了消去这类量词的一条经典算法路线;但“存在等价的无量词描述”不意味着描述总是短或计算总是便宜。参见 Cooper (1972) 原文扫描

复合方向:数学记号与 isl apply_range

全文固定采用函数复合式的记法:

$$ (Q\circ R)(x,z) \Longleftrightarrow \exists y:\ R(x,y)\land Q(y,z). $$

因此路径是

$$ X\xrightarrow{R}Y\xrightarrow{Q}Z, $$

书写结果却是 $Q\circ R$,即“先 $R$,后 $Q$”。在 isl 的对象方法记法中,对应关系是

R.apply_range(Q)  ==  Q ∘ R

也就是对 $R$ 的输出再应用 $Q$。如果 R : X -> YQ : Y -> Z,结果类型为 X -> ZQ.apply_range(R) 要求 $Q$ 的输出空间能接到 $R$ 的输入空间;在带命名 tuple 的模型里,它通常直接类型不匹配,即使维数碰巧相等也不能据此把方向倒过来。这里的 API 含义以 isl 官方手册 为工具语义来源;数学复合的定义仍以上式为准。

访问关系给出一个之后反复使用的方向检查。若

$$ W_S:D_S\to M, \qquad R_T:D_T\to M, $$

则“源实例 $x$ 写的位置被汇实例 $y$ 读”形成的同址候选关系是

$$ R_T^{-1}\circ W_S:D_S\to D_T. $$

在 isl 方向中对应 W_S.apply_range(R_T.reverse())。它仍是 source -> sink。相反,$W_S^{-1}\circ R_T:D_T\to D_S$ 得到的是其反向匹配,不能仍称为同一个 source-to-sink 依赖;而且同址候选还不是考虑执行顺序和中间覆盖后的精确 flow 依赖。

词典序关系

对 $a,b\in\mathbb Z^k$,若在第一个满足 $a_r\ne b_r$ 的分量上有 $a_r<b_r$,则写作 $a\mathrel{\mathrm{lex}<}b$。例如

$$ (2,7)\mathrel{\mathrm{lex}<}(3,-100), \qquad (2,7)\not\mathrel{\mathrm{lex}<}(2,7). $$

它本身也是 Presburger 可定义关系:对固定维数 $k$,把“前 $r-1$ 个分量相等且第 $r$ 个严格小于”在 $r=1,\ldots,k$ 上作有限析取即可。后文的调度合法性正是比较 source 时间戳与 sink 时间戳的这一关系。

手算示例

一个关系的 domain、range、inverse 与 image

设参数上下文为 $C(N):N\ge 0$,并给三个 tuple 空间命名为 $I,J,K$。考虑

$$ R_N=\{[i]_I\to[j]_J\mid 0\le i<N\land j=2i+1\}:I\to J. $$

它是部分函数关系。逐项消去变量可得:

$$ \begin{aligned} \operatorname{domain}(R_N) &=\{[i]_I\mid 0\le i<N\},\\ \operatorname{range}(R_N) &=\{[j]_J\mid 1\le j<2N\land j\equiv1\pmod 2\},\\ R_N^{-1} &=\{[j]_J\to[i]_I\mid 0\le i<N\land j=2i+1\}. \end{aligned} $$

inverse 交换输入和输出,不是把等式机械写成允许实数除法的 $i=(j-1)/2$;在整数语义下必须保留“$j$ 为奇数”这一可整除条件。

若取输入子集

$$ A_N=\{[i]_I\mid0\le i<N\land i\equiv0\pmod2\}, $$

则其像为

$$ R_N[A_N] =\{[j]_J\mid 1\le j<2N\land j\equiv1\pmod4\}. $$

例如 $N=6$ 时,$A_N=\{0,2,4\}$,像是 $\{1,5,9\}$。若以整个定义域为输入,$R_N[\operatorname{domain}(R_N)]=\operatorname{range}(R_N)$。

再取输出集合

$$ B_N=\{[j]_J\mid 0\le j<2N\land j\ge5\}. $$

逆像是

$$ R_N^{-1}[B_N] =\{[i]_I\mid0\le i<N\land i\ge2\}, $$

因为约束 $2i+1\ge5$ 在整数上等价于 $i\ge2$。注意 $R_N^{-1}[B_N]$ 表示逆像;它与“先构造逆关系,再求像”是同一个集合语义。

并、交、差与补:区间和奇偶析取

固定全集

$$ U=\{i\in\mathbb Z\mid0\le i\le9\}, $$

并定义

$$ A=\{i\in U\mid i\le5\}, \qquad E=\{i\in U\mid i\equiv0\pmod2\}. $$

于是:

运算逻辑公式集合解释
$A\cup E$$0\le i\le9\land(i\le5\lor i\equiv0\pmod2)$$\{0,1,2,3,4,5,6,8\}$
$A\cap E$$0\le i\le5\land i\equiv0\pmod2$$\{0,2,4\}$
$A\setminus E$$0\le i\le5\land i\not\equiv0\pmod2$$\{1,3,5\}$
$U\setminus A$$0\le i\le9\land i>5$$\{6,7,8,9\}$

这也展示了析取和同余造成的非凸性。若不写全集,符号“$\neg A$”可能被误解为 $\mathbb Z\setminus A$,其结果会额外包含所有负数和大于 9 的整数。

三角域投影

令 $C(N):N\ge0$,三角域为

$$ T_N=\{(i,j)\in\mathbb Z^2\mid0\le i\le j<N\}. $$

投影到 $i$ 坐标:

$$ \begin{aligned} \operatorname{proj}_{i}(T_N) &=\{i\in\mathbb Z\mid\exists j:\ 0\le i\le j<N\}\\ &=\{i\in\mathbb Z\mid0\le i<N\}. \end{aligned} $$

第二步不是简单“删掉含 $j$ 的不等式”。它利用了存在这样的整数 $j$ 当且仅当 $i<N$,且可以取见证 $j=i$。投影到 $j$ 也得到 $\{j\mid0\le j<N\}$,此时见证可取 $i=0$。当 $N=0$ 时两者都为空,与参数上下文一致。

两个关系的复合

继续使用 $R_N:I\to J$,定义

$$ Q_N=\{[j]_J\to[k]_K\mid 1\le j<2N\land k=j-1\}:J\to K. $$

正确复合为

$$ \begin{aligned} Q_N\circ R_N &=\{[i]_I\to[k]_K\mid \exists j:\ 0\le i<N\land j=2i+1\\ &\hspace{42mm}\land 1\le j<2N\land k=j-1\}\\ &=\{[i]_I\to[k]_K\mid0\le i<N\land k=2i\}. \end{aligned} $$

集合解释是:从输入 $i$ 先走到奇数 $j=2i+1$,再走到前一个偶数 $k=j-1$。类型链为 $I\to J\to K$,所以结果是 $I\to K$。在 isl 中应写 R_N.apply_range(Q_N)

为了看见“关系”而非仅仅“函数”,再定义

$$ F=\{[i]_I\to[j]_J\mid j=i\lor j=i+1\}, \qquad G=\{[j]_J\to[k]_K\mid k=j\lor k=-j\}. $$

$$ G\circ F =\{[i]_I\to[k]_K\mid k=i\lor k=-i\lor k=i+1\lor k=-i-1\}. $$

中间点有多个选择,输出也可有多个;复合定义中的存在量词恰好保留所有可达的 $(i,k)$ 对。

准仿射表达式如何落回 Presburger 关系

工程文献常把由仿射式、固定整数除法、floor、ceil 和 modulo 构成的表达式称为准仿射(quasi-affine)表达式。关键不是把 floormod 当作新的神秘原语,而是把它们展开成线性约束、同余或存在变量。

固定正分母的 floor

$$ q=\left\lfloor\frac{i+2}{3}\right\rfloor. $$

因为分母 3 是固定正整数,这等价于

$$ 3q\le i+2<3(q+1). $$

右侧只有加法、序和常数乘法,因此关系

$$ F=\{i\to q\mid3q\le i+2<3q+3\} $$

是 Presburger 可定义的。负数也按数学 floor 处理:例如 $i=-3$ 时 $(i+2)/3=-1/3$,唯一满足不等式的整数是 $q=-1$。这避免了把语言实现中的“向零截断”误当 floor。

固定分块大小的 ceil

令 $B\in\mathbb Z_{>0}$ 是预先固定的正整数常量,例如编译时选定的块大小。则

$$ c=\left\lceil\frac{N-i}{B}\right\rceil $$

等价于

$$ B(c-1)<N-i\le Bc, $$

也等价于 $c=\left\lfloor(N-i+B-1)/B\right\rfloor$。固定 $B$ 后,$Bc$ 是常数乘变量,仍在 Presburger 语言内。

若把 $B$ 与 $c$ 都当作可变量化的自由变量,乘积 $Bc$ 就是变量乘变量,不再是一般 Presburger 项。因此不能仅凭写成 ceil((N-i)/B) 就声称它属于核心 Presburger 算术。某个工具若接受参数化除数,必须逐项核对该工具对除数、参数上下文和局部变量的具体规则;这种工具扩展不能反过来扩大本章的数学语言。isl 对 quasi-affine 表达式和 div 的具体对象规则应以 isl 官方手册 为准。

modulo、商余数与分段

标准余数

$$ r=i\bmod3 $$

可展开为

$$ \exists q\in\mathbb Z:\ i=3q+r\land0\le r<3. $$

固定正模数 3 保证每个 $i$ 恰有一个这样的 $r$。例如谓词 $i\equiv1\pmod3$ 可写为 $\exists q:i=3q+1$。

floor 也可以借商余数看成有限分段。写 $i=3q+r$、$0\le r<3$,则

$$ \left\lfloor\frac{i+2}{3}\right\rfloor = \begin{cases} q,&r=0,\\ q+1,&r=1\lor r=2. \end{cases} $$

每个分支都是仿射等式,分支条件是有限析取与同余;所以整张图仍是 Presburger 可定义关系。更一般地,只要分支数有限、每个 guard 是 Presburger 公式、每个分支值由允许的线性关系给出,就可以把分段表达式写成这些分支关系的并。

限制必须再次强调:固定常数除法、固定常数 modulo 可以用上述方式编码;i mod jfloor(i/j)ceil(i/j) 在 $j$ 也是任意变量时涉及变量之间的整除或乘积,不能用上述有限线性约束直接落回一般 Presburger 公式。

编译器用途

  1. 域的组合。 合取添加循环边界,析取表示控制流分支,并、交和差可以组合或裁剪语句实例集合。
  2. 消去局部坐标。 投影把局部索引、商余数辅助变量或中间内存坐标存在量化;量词消去再尝试得到外部可见坐标上的描述。
  3. 访问匹配。 写访问与读访问经逆和复合得到 source -> sink 的同址候选;后续章节再叠加原始顺序和最后写语义。
  4. 调度与变换。 调度像把迭代域送到时间空间,逆像把时间区域拉回实例空间,词典序关系表达先后。
  5. 代码生成边界。 floor、ceil、modulo 和有限分支经显式约束进入整数集合表示,最终可能成为循环边界、步长或 guard;变量除变量和间接下标则越出本章闭包。

这些操作在数学上保持 Presburger 可定义性,但代数闭包不保证工程成本低。投影可能引入大量析取和同余,关系复合可能显著增大中间表示;工具通常需要化简、分支控制和上下文约束。

常见误区

  1. 只看维数,不看 tuple 类型。 两个一维空间未必可复合;语句实例、数组位置和时间戳应有不同身份。
  2. 把数学复合读成从左到右。 $Q\circ R$ 是先 $R$ 后 $Q$;isl 中对应 R.apply_range(Q)
  3. 把访问逆关系写错后仍声称方向不变。 $R_T^{-1}\circ W_S:D_S\to D_T$ 才沿 source 写实例走到 sink 读实例。
  4. inversepreimage 混为一谈。 前者产生关系 $Y\to X$,后者以输出集合为条件产生输入集合。
  5. 投影时直接删约束。 投影要证明存在被删坐标的整数见证;整数可行性还可能产生同余条件。
  6. 补集没有全集。 补集必须相对于 $\mathbb Z^d$、参数上下文或另一个显式集合定义。
  7. 把参数放进分母便自动称为准仿射。 在核心 Presburger 语言中,分母应是固定正整数;符号分母与商变量相乘通常越界。
  8. 把同址候选当精确依赖。 关系代数给出候选匹配,执行顺序和中间覆盖仍需后续数据流分析。

练习

练习 EX04-B01|Relation 的 domain/range/inverse/image(基础)

令 $R=\{i\to j\mid0\le i<8\land j=3i+2\}$。写出 domainrange 和 $R^{-1}$,并计算偶数输入集合在 $R$ 下的像。

答案索引: ANS-EX04-B01

练习 EX04-D01|奇偶三角域投影(推导)

令 $T_N=\{(i,j)\mid0\le i\le j<N\land i\equiv j\pmod2\}$。分别投影到 $i$ 和 $j$,说明参数 $N=0$ 与 $N=1$ 的边界情况。

答案索引: ANS-EX04-D01

练习 EX04-D02|三关系复合与 isl 调用顺序(推导)

给定 $A:X\to Y$、$B:Y\to Z$、$C:Z\to W$,写出 $C\circ B\circ A$ 的量词公式以及连续两次 isl apply_range 的调用顺序。

答案索引: ANS-EX04-D02

练习 EX04-D03|Euclidean floor 与 modulo 展开(推导)

把 $q=\lfloor(i-4)/5\rfloor$ 与 $r=i\bmod5$ 分别展开成 Presburger 约束,并用 $i=-2$ 检查 floor 和余数语义。

答案索引: ANS-EX04-D03

练习 EX04-C01|访问复合的类型与方向(综合)

设 $W_S:D_S\to M$、$R_T:D_T\to M$。判断 $R_T^{-1}\circ W_S$ 和 $W_S^{-1}\circ R_T$ 的类型与方向,并解释哪一个可作为 source 语句 $S$ 到 sink 语句 $T$ 的同址候选。

答案索引: ANS-EX04-C01

本章小结

  • Presburger 公式的自由整数变量给出集合;把自由变量分为输入、输出两组就给出带类型关系。
  • 并、交、差、补对应布尔运算,投影对应存在量化;domain、range、像、逆像都是限制与投影的组合。
  • 全文的复合约定是 $(Q\circ R)(x,z)\Leftrightarrow\exists y:R(x,y)\land Q(y,z)$,而 isl R.apply_range(Q) 对应 $Q\circ R$。
  • 访问关系必须显式取逆才能按内存位置匹配,所得依赖候选仍保持 source -> sink
  • 固定正整数分母的 floor、ceil、modulo 和有限分段可展开成线性约束、同余、析取与存在变量;变量除变量不属于一般 Presburger 表达式。
  • 闭包说明结果仍可定义,不说明表示一定简短或计算一定高效。

第 5 章:半线性集合、格点与多面体

直觉

Presburger 公式用等式、不等式、同余、布尔连接词和量词描述整数点。半线性表示则换一种方式:从有限多个基点出发,把有限多个固定周期向量分别重复非负整数次,再对有限多个这样的集合取并。

这两种语言揭示了同一个关键结构:Presburger 可定义集合可以有非凸分支和无限重复的周期图样,但这种重复由有限数据生成。它远比“单个凸多面体的全部整数点”丰富,又不像含变量乘法的任意整数集合那样失去周期控制。

本章要特别分清四类对象:

  1. 连续空间 $\mathbb R^d$ 中的单个有理凸多面体 $P$;
  2. 该多面体的整数点集 $P\cap\mathbb Z^d$;
  3. 有限并 $\bigcup_r(P_r\cap\mathbb Z^d)$;
  4. 一般 Presburger 可定义集合,也即适当定义下的半线性集合。

取整数点后的后三类之间有包含关系,但它们不是同一个概念;连续的 $P$ 不应塞进这条离散对象的包含链。尤其是,同余能在无限范围内周期性地挖洞,普通线性不等式的有限并一般做不到这一点。

形式定义

线性集与半线性集

本节先在非负整数域上工作,并约定

$$ \mathbb N=\{0,1,2,\ldots\}. $$

给定基向量 $b\in\mathbb N^d$ 与周期向量 $p_1,\ldots,p_k\in\mathbb N^d$,线性集定义为

$$ L(b;p_1,\ldots,p_k) =\left\{b+n_1p_1+\cdots+n_kp_k\mid n_1,\ldots,n_k\in\mathbb N\right\}. $$

这里“线性”是半群意义的术语,不是线性代数中的子空间:系数只能取非负整数,集合有一个基点,也不要求对加法逆元封闭。若 $k=0$,约定 $L(b;)=\{b\}$。

有限多个线性集的并称为半线性集:

$$ S=\bigcup_{r=1}^{s}L(b_r;p_{r1},\ldots,p_{rk_r}), \qquad s<\infty. $$

“有限”限制的是基点和周期生成元的描述数量,不是集合中点的数量。一个线性集通常已经是无限的。

有理凸多面体及其整数点

本教程把有理凸多面体写成

$$ P=\{x\in\mathbb R^d\mid Ax\le b\}, \qquad A\in\mathbb Q^{m\times d},\ b\in\mathbb Q^m. $$

这里沿用 polyhedral-model 文献中的宽泛用法,允许 $P$ 无界;若强调有界,则称有理凸多胞体(polytope)。凸性意味着任意 $x,y\in P$ 与 $0\le\lambda\le1$ 都满足 $\lambda x+(1-\lambda)y\in P$。

$P$ 是连续对象,循环实例对应的离散对象是

$$ P_{\mathbb Z}=P\cap\mathbb Z^d. $$

清除有理不等式的分母后,$P_{\mathbb Z}$ 可由整数系数线性不等式定义,因此是 Presburger 可定义集合。有限并

$$ \bigcup_{r=1}^{s}(P_r\cap\mathbb Z^d) $$

也因有限析取而 Presburger 可定义。本章把它简称为“有限并整数多面体点集”;这不是说并集本身仍是单个凸多面体,也不是说它已经覆盖所有 Presburger 集合。

还要区分整数点集与整数凸包:

$$ P\cap\mathbb Z^d \quad\text{是离散点集,而}\quad \operatorname{conv}(P\cap\mathbb Z^d) \quad\text{是连续凸集}. $$

即使后者恰好等于 $P$,两者仍因所在对象类别不同而不能互换。

从周期生成元读出集合

一维周期集合

非负偶数集合是

$$ E=L(0;2)=\{2n\mid n\in\mathbb N\}. $$

所有模 3 余 1 的非负整数是

$$ C=L(1;3)=\{1+3n\mid n\in\mathbb N\}. $$

两者的并

$$ S=L(0;2)\cup L(1;3) $$

是半线性的。它可以写成 Presburger 析取

$$ x\ge0\land\bigl(x\equiv0\pmod2\lor x\equiv1\pmod3\bigr). $$

前几个点是

$$ 0,1,2,4,6,7,8,10,12,13,14,\ldots $$

这不是一个连续区间的整数点:3、5、9、11 等位置形成由两个模条件叠加产生的周期孔洞。

二维格点射线与格点锥

取基点 $b=(1,2)$ 和周期向量 $p=(2,1)$,则

$$ L((1,2);(2,1)) =\{(1+2n,2+n)\mid n\in\mathbb N\} $$

是一条从 $(1,2)$ 出发、沿 $(2,1)$ 方向前进的离散格点射线。它满足线性等式

$$ x-2y=-3 $$

以及 $y\ge2$,同时只取射线上的整数点。

再加入周期 $q=(1,3)$,得到

$$ L((1,2);(2,1),(1,3)) =\{(1+2n_1+n_2,\ 2+n_1+3n_2)\mid n_1,n_2\in\mathbb N\}. $$

这是由两个离散射线方向生成的平移格点半群。它位于相应实锥内,但不应未经证明就等同于该实锥的所有整数点:生成元可能只覆盖其中某些剩余类,形成格点孔洞。

三角域:多面体整数点也是 Presburger 集合

参数上下文 $C(N):N\ge0$ 下,

$$ T_N=\{(i,j)\in\mathbb Z^2\mid0\le i\le j<N\} $$

在每个固定 $N\ge1$ 时是有理凸多面体

$$ P_N=\{(x,y)\in\mathbb R^2\mid0\le x\le y\le N-1\} $$

的整数点集 $P_N\cap\mathbb Z^2$。对固定 $N$,它是有限集,因而当然半线性:最直接的表示是把每个点作为一个零周期线性集。这个表示只证明每个纤维的存在性,并不一定是适合计算的紧凑表示。

若把参数也作为坐标,整个非空参数化族其实有一个统一线性表示:

$$ \{(N,i,j)\in\mathbb N^3\mid N\ge1\land0\le i\le j<N\} =L\bigl((1,0,0);(1,1,1),(1,0,1),(1,0,0)\bigr), $$

也就是

$$ (N,i,j)=(1,0,0)+a(1,1,1)+b(1,0,1)+c(1,0,0), \qquad a,b,c\in\mathbb N. $$

正向取 $a=i$、$b=j-i$、$c=N-1-j$:三个系数非负,代回即得该等式。反向展开则有

$$ i=a,\qquad j=a+b,\qquad N=1+a+b+c, $$

所以 $N\ge1$ 且 $0\le i\le j<N$。因此这不是只对每个固定 $N$ 逐点列举的表示。$N=0$ 时原定义要求 $0\le i\le j<0$,故该纤维为空;上式第一坐标恒至少为 $1$,也恰好不产生 $N=0$ 的点。

若再要求 $i\equiv j\pmod2$,得到的集合仍是 Presburger/半线性集合,但不再是整个 $P_N\cap\mathbb Z^2$;它在同一个三角区域中按奇偶类选择格点。参数化且无界的类似约束会持续产生周期孔洞。

Presburger 可定义集与半线性集的等价

一手结论直接位于 $\mathbb N^d$

Ginsburg–Spanier 的原始结论应按其直接论域和语法陈述。该文第 3–4 页令论域为 $\mathbb N$,把原子式限制为两边均为非负整数系数线性组合的等式

$$ t_0+\sum_r t_rx_r=t'_0+\sum_r t'_rx_r, \qquad t_0,t'_0,t_r,t'_r\in\mathbb N, $$

再闭包于 $\land$、$\lor$、$\neg$ 和存在量词。作者的脚注说明:这严格说是 modified Presburger formulas,原始 Presburger formulas 的论域是全体整数。在这个 modified 语法下,他们的 Theorem 1.3 说:$\mathbb N^d$ 上的 Presburger 集合与半线性集合恰好相同,且两种描述可有效互算。参见 Ginsburg 与 Spanier (1966), Semigroups, Presburger Formulas, and LanguagesDOI)。

本教程第 2 章的自然数版只是更方便书写的等表达扩展,而不是未经定义地换用另一个定理。对该章公式在 $\mathbb N$ 上逐项整理即可回到上述语法:

  • 任意整数系数等式把负系数和负常数移到另一边,成为两边非负系数的等式;反向包含显然成立。
  • 不等式 $s\le t$ 可写成 $\exists q\in\mathbb N:\ s+q=t$,再按上一项移项。严格序是整数上的缩写,也可先改写为 $s+1\le t$。
  • 固定模数同余 $s\equiv t\pmod m$ 可写成 $\exists q_+,q_-\in\mathbb N:\ s+m q_+=t+m q_-$,其中 $m>0$ 固定;这避免把可能为负的商误当作自然数变量。
  • 全称量词是 $\forall x\,\varphi\equiv\neg\exists x\,\neg\varphi$,其余布尔连接词已经在原语法中。

所以只有在量词和赋值均限制到 $\mathbb N$ 时,才可把本教程的等式、序、不等式、全称量词和固定同余桥接为 Ginsburg–Spanier 的 modified 语法;一般变量乘变量仍不在其中。

这条定理不是“任意整数集合都半线性”,也不是“半线性集等于单个凸多面体”。它说的是特定逻辑可定义性与有限个基点/周期生成元表示之间的等价,而且原文直接工作的坐标域是 $\mathbb N^d$,不是未经说明的 $\mathbb Z^d$。

从两个方向看,等价的直觉是:

  • 一个线性集可用存在变量 $n_r\ge0$ 和等式 $x=b+\sum_rn_rp_r$ 定义,有限并对应有限析取;
  • 反方向更深:任意允许量词和布尔组合的 modified Presburger 公式,最终仍能分解为有限个带周期生成元的线性集。

第二点是定理内容,不能用几个例子代替证明。

从 $\mathbb N^d$ 搬运到 $\mathbb Z^d$:显式差编码

要得到整数坐标版本,必须另做编码。对每个 $z_\ell\in\mathbb Z$,引入

$$ u_\ell,v_\ell\in\mathbb N, \qquad z_\ell=u_\ell-v_\ell. $$

向量形式记为线性映射

$$ \pi:\mathbb N^{2d}\to\mathbb Z^d, \qquad \pi(u,v)=u-v. $$

这个表示不唯一,例如 $1=1-0=2-1$,但存在量化只需要至少一个表示,非唯一性不影响集合像。搬运过程分两步。

从整数公式到整数半线性表示。 设 $A\subseteq\mathbb Z^d$ 由整数 Presburger 公式 $\varphi(z)$ 定义。对自由变量和量词约束的整数变量都分别引入一对非负变量,以 $z=u-v$ 替换每个整数变量,并把含负系数的线性项移到等式或不等式另一侧;再按上一节的移项、松弛变量、双非负商和 $\neg\exists\neg$ 规则,把所得自然数公式规范为 modified 语法。于是得到 $\mathbb N^{2d}$ 上的集合描述

$$ E=\{(u,v)\in\mathbb N^{2d}\mid\varphi(u-v)\}. $$

由 $\mathbb N^{2d}$ 上的 Ginsburg–Spanier 结论,$E$ 是有限个线性集之并。对每个线性分量施加 $\pi$:

$$ \pi\bigl(L(b;p_1,\ldots,p_k)\bigr) =L(\pi(b);\pi(p_1),\ldots,\pi(p_k)), $$

其中像后的基点和周期向量属于 $\mathbb Z^d$,系数仍属于 $\mathbb N$。因此

$$ A=\pi(E) $$

是 $\mathbb Z^d$ 上有限个这类线性集之并。

从整数半线性表示到整数公式。 反过来,把 $\mathbb Z^d$ 上的线性集定义为

$$ L_{\mathbb Z}(b;p_1,\ldots,p_k) =\{b+n_1p_1+\cdots+n_kp_k\mid n_r\in\mathbb N\}, $$

其中 $b,p_r\in\mathbb Z^d$。它由整数 Presburger 公式

$$ \exists n_1,\ldots,n_k:\ \bigwedge_r n_r\ge0 \land x=b+\sum_rn_rp_r $$

定义,因为 $p_r$ 都是固定整数向量,只出现常数乘变量。有限并仍由有限析取定义。

所以,整数版“Presburger 可定义集等于半线性集”是通过差编码、线性像和上述反向公式从 $\mathbb N^d$ 结论搬运得到的;它不是把 Ginsburg–Spanier 原文的论域直接改写成 $\mathbb Z^d$。Cooper 的整数消元工作提供整数公式处理的另一条经典背景,参见 Cooper (1972)

例如整个整数轴可写成

$$ \mathbb Z=L_{\mathbb Z}(0;1)\cup L_{\mathbb Z}(-1;-1). $$

第一个线性集覆盖非负方向,第二个覆盖负方向;非负系数并不要求周期向量本身在整数版中为正。

手算示例

下面用对象对照、奇数反例和两个一维集合,把连续凸性、有限非凸分段与无限周期结构的边界逐一算清。

四类对象对照

对象允许非凸并允许周期孔洞连续/离散典型表示
单个有理凸多面体 $P\subseteq\mathbb R^d$连续有限个有理线性不等式 $Ax\le b$
多面体整数点 $P\cap\mathbb Z^d$否(表示只准一个凸 $P$)由单个凸 $P$ 截取其全部格点,不会凭空选择无限模剩余类离散$P$ 与 $\mathbb Z^d$ 的交
有限并整数多面体点集 $\bigcup_r(P_r\cap\mathbb Z^d)$可表达有限分段;普通不等式的有限并一般不能表达无限周期孔洞离散union of polyhedral basic sets
一般 Presburger/半线性集合离散逻辑式或有限并半线性表示

表中前两行“不允许并”说的是表示类别只准一个 $P$,不是否认可以在集合论中另行做并。第二行也只说由单个凸 $P$ 截取全部格点,并不暗示 $P=\operatorname{conv}(P\cap\mathbb Z^d)$。取格点造成的离散性不等于模约束:比如直线 $x=2y$ 的整数点在几何上稀疏,但它们是该凸集合的全部格点;集合 $\{x\in\mathbb Z\mid x\equiv1\pmod2\}$ 则在一维凸包内部主动排除了所有偶数格点。

由定义立刻得到

$$ \{P\cap\mathbb Z^d\} \subseteq \left\{\bigcup_{r=1}^{s}(P_r\cap\mathbb Z^d)\right\} \subseteq \{\text{Presburger 可定义集合}\}. $$

这里花括号表示“这一类集合”。第二个包含在一般情形下是严格的,因为同余可以产生有限并普通多面体无法持续表达的周期孔洞。

奇数集合反例

考虑非负奇数集合

$$ O=\{x\in\mathbb Z\mid x\ge1\land x\equiv1\pmod2\} =L_{\mathbb Z}(1;2). $$

它既是 Presburger 可定义集,也是一个线性集。假设存在单个凸多面体 $P\subseteq\mathbb R$ 使

$$ P\cap\mathbb Z=O. $$

因为 $1,3\in O$,所以 $1,3\in P$。凸性要求它们的中点

$$ 2=\tfrac12\cdot1+\tfrac12\cdot3 $$

也属于 $P$。但 $2\in\mathbb Z$,于是 $2\in P\cap\mathbb Z$,与 $2\notin O$ 矛盾。因此“Presburger 可定义”不等于“某个凸多面体的全部整数点”。

这个例子甚至不能写成有限多个一维有理凸多面体的整数点之并。一维凸多面体是区间、射线、直线或点;有限并若包含任意大的奇数,就至少有一个无界分量包含某条实射线,从而也包含所有充分大的偶数。要逐个保留奇数而排除偶数,需要无限多个单点/小区间,或直接使用周期 2;有限多面体并做不到。

非凸不等于周期

以下两个集合展示两个独立维度:

$$ A=([-3,-1]\cup[1,3])\cap\mathbb Z $$

是非凸的,但仅有两个有限多面体分支,没有无限周期结构。相反,

$$ B=\{x\in\mathbb Z\mid x\ge0\land x\equiv0\pmod3\} $$

只有一个周期方向,却在整个非负射线上永久跳过两个剩余类。不能因为两者都可写成析取,就把有限几何分段与无限模周期视为同一现象。

编译器用途

  1. 迭代域的几何内核。 规则矩形域、三角域和仿射边界通常直接写成 $P\cap\mathbb Z^d$,便于使用多面体算法。
  2. 步长和对齐。 i += 2、向量对齐、银行映射等条件自然产生同余类;半线性/Presburger 视角不会把这些周期信息从凸包中抹掉。
  3. 控制流析取。 多分支语句域可能是有限并整数多面体点集;若分支还含 modulo guard,则需要 basic set 加同余或局部存在变量,而不是只保存连续凸包。
  4. 投影后的周期。 即使原约束以等式和存在变量给出,消去局部坐标也可能暴露出整除条件。例如 $\exists q:x=3q+1$ 投影后就是 $x\equiv1\pmod3$。
  5. 算法边界。 许多调度和扫描算法选择多面体子类,是为了获得有限线性不等式、凸优化或逐分支处理能力;这是一种算法设计选择,不是一般 Presburger 集合突然都变成了单个凸多面体。

工程工具里的 “basic set” 或 “union set” 是具体表示对象,其允许的局部 div、同余和规范化规则要以官方文档为准。以 isl 为例,集合、映射及其 union/basic 对象的 API 语义参见 isl 官方手册;该手册是工具语义来源,不替代 Ginsburg–Spanier 的数学定理。

常见误区

  1. 把 Ginsburg–Spanier 的论域直接写成 $\mathbb Z^d$。 原始结论直接在 $\mathbb N^d$ 上;整数版需要显式的正负部分/差编码与搬运论证。
  2. 把线性集当向量子空间。 系数属于 $\mathbb N$,有基点且通常没有加法逆元。
  3. 把“有限并”误作“无限周期”。 有限个凸分支能表达非凸,但普通不等式分支不能自动表达沿无界方向持续出现的模孔洞。
  4. 把 $P$ 与 $P\cap\mathbb Z^d$ 混用。 前者连续,后者离散;循环实例和数组下标属于后者。
  5. 把整数点集与整数凸包混用。 $P\cap\mathbb Z^d$ 是点集,$\operatorname{conv}(P\cap\mathbb Z^d)$ 是连续凸集。
  6. 看到格点稀疏就断言有周期孔洞。 低维仿射子空间与 $\mathbb Z^d$ 相交也会稀疏;周期孔洞是相对于相关格点结构主动排除剩余类。
  7. 把所有 Presburger 表示都交给凸多面体算法而不分支。 析取和同余若只取实凸包,可能加入原集合不存在的整数实例。
  8. 把定理上的可表示性等同于紧凑性。 有限集按单点并总能半线性表示,但大小可能随参数增长,未必提供统一、紧凑的参数化表示。

练习

练习 EX05-B01|同余类的线性集表示(基础)

把 $\{x\in\mathbb N\mid x\equiv2\pmod5\}$ 写成线性集,并写出对应的 Presburger 公式。

答案索引: ANS-EX05-B01

练习 EX05-D01|二维生成元枚举与成员见证(推导)

列出 $L((0,1);(2,0),(0,3))\subseteq\mathbb N^2$ 在 $0\le n_1+n_2\le3$ 下生成的点。随后回到不带该截断条件的完整线性集,判断 $(4,7)$ 与 $(3,7)$ 是否属于它,并给出系数见证或不可能性证明。

答案索引: ANS-EX05-D01

练习 EX05-D02|从整数到自然数的差编码(推导)

用差编码 $z=u-v$ 把整数公式 $z\le-2\land z\equiv1\pmod3$ 搬到非负整数变量上。注意把负系数移到关系另一侧,并处理同余见证中的整数商。

答案索引: ANS-EX05-D02

练习 EX05-C01|$\mathbb Z^2$ 的有限半线性分解(综合)

证明 $\mathbb Z^2$ 可写成有限个 $\mathbb Z^2$ 上的线性集之并;可以按四个象限及坐标轴分解,也可以寻找更紧凑的生成元表示。

答案索引: ANS-EX05-C01

练习 EX05-C02|四类对象与表示成本(综合)

判断下列离散对象分别属于本章四类对象中的哪些类:$\{0,2,4,6\}$、$\{2n\mid n\in\mathbb N\}$、固定参数 $N$ 的三角域 $T_N$,以及

$$ \bigl(([0,1]\times[0,1])\cup([3,4]\times[0,1])\bigr)\cap\mathbb Z^2. $$

说明“属于后一个大类”为什么不意味着有相同的表示成本。

答案索引: ANS-EX05-C02

练习 EX05-C03|单个同余类不是单凸多面体格点集(综合)

推广奇数反例:对 $m\ge2$ 与规范化剩余 $0\le r<m$,证明单个同余类 $\{x\in\mathbb Z\mid x\ge0\land x\equiv r\pmod m\}$ 不能是某个一维凸多面体的全部整数点。

答案索引: ANS-EX05-C03

本章小结

  • 在 $\mathbb N^d$ 上,线性集是 $b+\sum_r n_rp_r$($n_r\in\mathbb N$),半线性集是有限多个线性集的并。
  • Ginsburg–Spanier 的直接结论位于 $\mathbb N^d$:modified Presburger formulas 定义的集合恰好是半线性集。
  • $\mathbb Z^d$ 版本需把每个整数坐标编码成 $u-v$,在 $\mathbb N^{2d}$ 上应用定理,再经线性像搬运;不能悄然改写原定理的论域。
  • 单个有理凸多面体 $P$、整数点集 $P\cap\mathbb Z^d$、有限并整数多面体点集与一般 Presburger/半线性集合是不同对象。
  • 多面体整数点和它们的有限并都是 Presburger 可定义的,但一般 Presburger 集合还能表达无限周期孔洞;非负奇数集合给出严格反例。
  • 编译器使用多面体子类是为了算法结构和成本;同余、析取或投影产生的周期信息必须显式保留,不能只看连续凸包。

第 6 章:循环程序的关系建模

直觉

循环程序把三类事实写在一起:哪些动态语句会执行、每次执行访问哪个地址、这些执行原本按什么顺序发生。关系模型把它们拆成带类型对象:

  1. 迭代域 $D_S$ 枚举静态语句 $S$ 的动态实例;
  2. 访问关系 $R_S,W_S:D_S\to M$ 把实例送到读、写的内存位置;
  3. 调度 $\theta_S:D_S\to\mathbb Z^k$ 把实例送到原始执行时间。

两个语句即使都用循环变量 i,也属于不同的命名 tuple 空间;同一语句的不同迭代才是同一空间中的不同整数点。内存位置也带数组标签,$A[0]$ 与 $B[0]$ 不会因为下标相同而混为一处。

本章只建立程序事实,不提前把“同址”称作依赖。第 7 章才会显式取访问逆关系、匹配地址,并加入原始顺序和最后写/下一写条件。所有访问始终按 instance → memory 读取。

形式定义

参数、实例、内存与调度

令 $p\in\mathbb Z^q$ 为参数向量,$C(p)$ 为只含参数的上下文。每个静态语句 $S$ 有独立命名实例空间 $I_S$,其执行实例为

$$ D_S(p)=\{x\in I_S\mid\varphi_S(x,p)\}\subseteq\mathbb Z^{d_S}. $$

完整语义在 $C(p)\land x\in D_S(p)$ 下解释。参数不是迭代坐标:$N$ 控制域大小,却不是实例 tuple 的分量。

抽象内存集合写成带标签的不交并

$$ M=M_A\uplus M_B\uplus M_C\uplus\cdots. $$

数组 $A$ 的元素记作 $A[a_1,\ldots,a_r]\in M_A$。若源语言允许指针别名,必须证明两个标签不相交,或保守地把潜在别名纳入同一内存模型;不同变量名本身不是无别名证明。

语句 $S$ 的第 $r$ 条读访问和第 $w$ 条写访问分别是

$$ R_{S,r}:D_S\to M,\qquad W_{S,w}:D_S\to M. $$

$(x,m)\in R_{S,r}$ 表示实例 $x$ 读取 $m$。一个语句可有多条读写关系;只关心地址并集时,可取同类型关系的并 $R_S=\bigcup_rR_{S,r}:D_S\to M$。

原始调度是映射

$$ \theta_S:D_S\to\mathbb Z^k. $$

时间戳按严格词典序比较。多语句循环常取 $\theta_S(i)=(i,0)$、$\theta_T(i)=(i,1)$,常数分量记录同一轮的语句顺序。若不同事件仍可能同时间,必须增加语句位置或访问阶段,使原始执行顺序确定。

访问事件、access-site 与 phase

实例级访问关系不足以表达一条语句内部“先读后写”。为此给每个语法访问一个 access-site 标识 $a\in\mathcal A_S$,并把访问事件写成

$$ E_{S,a}=\{[x,a]_{S}\mid x\in D_S\}. $$

事件到实例、事件到内存的映射分别为

$$ \begin{aligned} \iota_{S,a}&=\{[x,a]_S\to[x]_S\mid x\in D_S\}:E_{S,a}\to D_S,\\ \mu_{S,a}&=\{[x,a]_S\to m\mid(x,m)\in A_{S,a}\}:E_{S,a}\to M, \end{aligned} $$

其中 $A_{S,a}:D_S\to M$ 是该 site 的读或写访问。事件本身携带 site,故两个访问即使属于同一实例并落在同一地址,也仍可区分。

把实例调度拆成循环时间 $\lambda_S(x)$ 与静态语句位置 $\operatorname{pos}(S)$,再给访问 site 一个阶段 $\operatorname{phase}(a)$,事件时间为

$$ \tau_{S,a} =\{[x,a]_S\to[\lambda_S(x),\operatorname{pos}(S),\operatorname{phase}(a)]\} :E_{S,a}\to\mathbb Z^h. $$

也可把前两部分合写成已经包含语句位置的 $\theta_S(x)$,此时 $\tau_{S,a}(x)=(\theta_S(x),\operatorname{phase}(a))$。phase 只记录语言语义保证的顺序,不能为未指定求值顺序凭空选边。对 read-modify-write(RMW),累加器 read 必须具有严格早于同实例 write 的 phase;不同且互不冲突的只读 site 可以处于同一 phase。第 7 章先在事件与地址层选择最后/下一写,最后才投影到命名实例。

经典仿射模型要求循环边界、guard 和数组下标可由参数与外围循环变量的整数仿射/准仿射约束表达。$A[2i+1]$、固定模数 guard 和三角域可进入 Presburger 模型;$A[B[i]]$、数据决定的 while 次数和 $A[ij]$ 一般不能直接精确建模。工程系统可保守近似或加入运行时检查,但不能把近似冒充精确语义。

手算示例

一维 shift:完整模型和 $N=5$ 真值表

for (int i = 1; i < N; ++i)
    S: A[i] = A[i - 1] + 1;

参数上下文为 $C(N):N\ge2$。域、读写和调度是

$$ \begin{aligned} D_S(N)&=\{[i]_S\in\mathbb Z\mid1\le i<N\},\\ R_S&=\{[i]_S\to A[a]\mid1\le i<N\land a=i-1\}:D_S\to M_A,\\ W_S&=\{[i]_S\to A[a]\mid1\le i<N\land a=i\}:D_S\to M_A,\\ \theta_S&=\{[i]_S\to[i]\mid1\le i<N\}:D_S\to\mathbb Z. \end{aligned} $$

用简化单行打印核对方向,调度的坐标部分是 [i] -> [i],完整类型仍为 $\theta_S:D_S\to\mathbb Z$;访问的左侧始终是实例,右侧始终是内存。

若把赋值拆成访问事件,读 site $r$ 与写 site $w$ 可取 $\operatorname{phase}(r)=0$、$\operatorname{phase}(w)=1$。相应事件调度为 $\tau_{S,r}=\{[i,r]_S\to[i,0]\}:E_{S,r}\to\mathbb Z^2$ 与 $\tau_{S,w}=\{[i,w]_S\to[i,1]\}:E_{S,w}\to\mathbb Z^2$。这既保留迭代顺序,也记录同实例 read 早于 write。

固定 $N=5$:

原始时间语句实例读取地址写入地址
1$[1]_S$$A[0]$$A[1]$
2$[2]_S$$A[1]$$A[2]$
3$[3]_S$$A[2]$$A[3]$
4$[4]_S$$A[3]$$A[4]$

例如 $W_S([2]_S)=A[2]$,而 $R_S([3]_S)=A[2]$。$[1]_S$ 读到的 $A[0]$ 来自循环外初始状态;$[4]_S$ 写出的 $A[4]$ 没有域内消费者。这张表是第 7 章逐点重算关系的真值表。

矩阵转置/拷贝

for (int i = 0; i < N; ++i)
  for (int j = 0; j < M; ++j)
    S: B[j][i] = A[i][j];

$$ \begin{aligned} C(N,M)&:N\ge1\land M\ge1,\\ D_S&=\{[i,j]_S\in\mathbb Z^2\mid0\le i<N\land0\le j<M\},\\ R_{S,A}&=\{[i,j]_S\to A[a,b]\mid a=i\land b=j\}:D_S\to M_A,\\ W_{S,B}&=\{[i,j]_S\to B[a,b]\mid a=j\land b=i\}:D_S\to M_B,\\ \theta_S&=\{[i,j]_S\to[i,j]\}:D_S\to\mathbb Z^2. \end{aligned} $$

假定 $M_A$ 与 $M_B$ 不别名。换位发生在访问映射中,不在域中:实例仍由原循环的 $(i,j)$ 命名,写位置才是 $B[j,i]$。

两语句生产者—消费者

for (int i = 0; i < N; ++i) {
    S: B[i] = A[i] + 1;
    T: C[i] = B[i] * 2;
}

取 $C(N):N\ge1$。两个命名域和四条访问为

$$ \begin{aligned} D_S&=\{[i]_S\mid0\le i<N\},& D_T&=\{[j]_T\mid0\le j<N\},\\ R_{S,A}&=\{[i]_S\to A[a]\mid a=i\}:D_S\to M_A,& W_{S,B}&=\{[i]_S\to B[a]\mid a=i\}:D_S\to M_B,\\ R_{T,B}&=\{[j]_T\to B[a]\mid a=j\}:D_T\to M_B,& W_{T,C}&=\{[j]_T\to C[a]\mid a=j\}:D_T\to M_C. \end{aligned} $$

$$ \theta_S=\{[i]_S\to[i,0]\}:D_S\to\mathbb Z^2,\qquad \theta_T=\{[j]_T\to[j,1]\}:D_T\to\mathbb Z^2. $$

把 $T$ 的数学坐标改名为 $j$ 不改变语义,也显示源代码变量名不能代替 statement identity。后续同址匹配得到 $[i]_S\to[i]_T$,不会把两个 tuple 合成一个实例。

矩阵乘和归约维 $k$

假定 $C$ 已清零:

for (int i = 0; i < M; ++i)
  for (int j = 0; j < N; ++j)
    for (int k = 0; k < K; ++k)
      S: C[i][j] += A[i][k] * B[k][j];

取 $C(M,N,K):M\ge1\land N\ge1\land K\ge1$,三维域、访问和调度为

$$ \begin{aligned} D_S&=\{[i,j,k]_S\in\mathbb Z^3\mid0\le i<M\land0\le j<N\land0\le k<K\},\\ R_{S,A}&=\{[i,j,k]_S\to A[a,b]\mid a=i\land b=k\}:D_S\to M_A,\\ R_{S,B}&=\{[i,j,k]_S\to B[a,b]\mid a=k\land b=j\}:D_S\to M_B,\\ R_{S,C}&=\{[i,j,k]_S\to C[a,b]\mid a=i\land b=j\}:D_S\to M_C,\\ W_{S,C}&=\{[i,j,k]_S\to C[a,b]\mid a=i\land b=j\}:D_S\to M_C,\\ \theta_S&=\{[i,j,k]_S\to[i,j,k]\}:D_S\to\mathbb Z^3. \end{aligned} $$

固定 $(i,j)$ 时,所有 $k$ 实例读写同一 $C[i,j]$,所以 $k$ 是归约维,不是 $C$ 的地址维。它却分别出现在 $A[i,k]$ 和 $B[k,j]$ 的地址中。若把清零纳入模型,应给初始化语句 $I$ 独立域 $D_I=\{[i,j]_I\}$、写关系 $W_{I,C}:D_I\to M_C$ 和早于首个乘加的调度,不能无说明地把清零塞进 $S(i,j,0)$。

对 RMW 语义,再令 $c_r,c_w$ 是 $C$ 的读、写 site,取 $\operatorname{phase}(c_r)=0<1=\operatorname{phase}(c_w)$。于是

$$ \begin{aligned} \tau_{S,c_r}&=\{[i,j,k,c_r]_S\to[i,j,k,0]\}:E_{S,c_r}\to\mathbb Z^4,\\ \tau_{S,c_w}&=\{[i,j,k,c_w]_S\to[i,j,k,1]\}:E_{S,c_w}\to\mathbb Z^4. \end{aligned} $$

同一 $k$ 的 $C$ read-to-write 顺序因此可见;$A,B$ 的只读 site 与 $C$ read 之间若语言未规定顺序,无需人为排序,因为它们访问不同抽象内存,不影响本章后续同址查询。

主案例 stencil 的模型接口

对 $p=(T,N)$,取 $C(p):T\ge1\land N\ge3$:

$$ \begin{aligned} D_S(p)&=\{[t,i]_S\in\mathbb Z^2\mid1\le t\le T\land1\le i<N-1\},\\ W_S&=\{[t,i]_S\to A[u,v]\mid u=t\land v=i\}:D_S\to M_A,\\ R_{S,-1}&=\{[t,i]_S\to A[u,v]\mid u=t-1\land v=i-1\}:D_S\to M_A,\\ R_{S,0}&=\{[t,i]_S\to A[u,v]\mid u=t-1\land v=i\}:D_S\to M_A,\\ R_{S,+1}&=\{[t,i]_S\to A[u,v]\mid u=t-1\land v=i+1\}:D_S\to M_A,\\ \theta_S&=\{[t,i]_S\to[t,i]\}:D_S\to\mathbb Z^2. \end{aligned} $$

时间坐标 $t$ 与内存首下标 $u$ 数值相关,却属于不同类型;第 7 章仍必须沿“写实例 → 内存 → 读实例”复合。

编译器用途

  1. 提取静态控制部分。 循环边界与 guard 形成域,仿射下标形成访问,源程序嵌套和语句位置形成调度。
  2. 建立跨语句连接。 命名 tuple 区分 $S[i]$ 和 $T[i]$;数组标签区分内存对象,使复合可检查类型。
  3. 保存变换基线。 原始调度描述原执行,新调度描述变换后执行;合法性与性能收益必须分别论证。
  4. 识别归约候选。 某维不出现在累加器地址中只是线索;还必须识别受支持的更新算子。
  5. 划定精度边界。 别名、间接访问和数据依赖控制流若不能排除,就要保守处理或加运行时条件。

关系对象及 API 语义以 isl 官方手册 为工具语义来源。整数仿射约束用于依赖分析的背景见 Pugh 的 Omega Test。本章展开均为教学性推导,不替代具体语言的别名、溢出和求值顺序规则。

常见误区

  1. 把访问写成 memory → instance。 本教程固定 $R,W:D\to M$;反向匹配只在依赖构造时取逆。
  2. 用循环变量名代替语句 identity。 $S[i]$ 与 $T[i]$ 是不同 tuple。
  3. 把参数塞进实例 tuple。 $N$ 属于上下文,$i$ 才是实例坐标。
  4. 遗漏语句内顺序。 多语句若都只调度到 $[i]$,时间并列,不能恢复原始全序。
  5. 把数组下标相等当地址相同。 无别名时 $A[i]\ne B[i]$;可能别名时也不能只凭变量名判为不同。
  6. 把归约维当地址维。 $k$ 不出现在 $C[i,j]$ 地址中,正因多个实例累积同一元素。
  7. 把间接访问伪装成仿射访问。 删除 $B[i]$ 这一间接层会改变语义。
  8. 建模完成便宣称有依赖。 同址、先后与覆盖尚未计算。
  9. 用实例时间代替访问事件时间。 RMW 的 read 和 write 属于同一实例,却有必须保持的内部先后;缺少 phase 会漏掉内部 WAR,并制造错误的跨迭代 next-write。

练习

练习 EX06-B01|仿射读写访问建模(基础)

设 $N\ge0$,数组 $A$ 与 $B$ 不别名。对

for (int i = 0; i < N; ++i)
  S: B[2 * i + 1] = A[i];

写参数上下文、迭代域、读写访问和原调度,并注明每个对象的类型。

答案索引: ANS-EX06-B01

练习 EX06-B02|三角写域建模与枚举(基础)

给三角域 $0\le j\le i<N$ 的写语句建模,固定 $N=3$ 列出全部实例。

答案索引: ANS-EX06-B02

练习 EX06-D01|位移消费者的域与读关系(推导)

取 $N\ge1$。生产者为 for (i=0;i<N;++i) P: B[i]=A[i]+1;;消费者改为 for (j=1;j<N;++j) T: C[j]=B[j-1];。重写 $D_T$ 和读关系,并给出访问地址范围。

答案索引: ANS-EX06-D01

练习 EX06-C01|矩阵乘初始化与同维时间戳(综合)

给矩阵乘增加清零语句 $I$,构造其域、访问和与更新语句同维的时间戳,保证每个 $(i,j)$ 的初始化早于 $k=0$ 更新。

答案索引: ANS-EX06-C01

练习 EX06-B03|间接访问的建模边界(基础)

解释为什么 $A[B[i]]$ 不能仅用 $i,N$ 的仿射访问精确表示,并给出不改变程序语义的可行处理方向。

答案索引: ANS-EX06-B03

本章小结

  • 循环程序被拆成参数上下文、命名语句域、instance → memory 访问和 instance → time 原始调度。
  • statement identity 来自命名 tuple,而不是循环变量名;数组标签和别名假设决定内存 identity。
  • 一维 shift 的 $N=5$ 真值表完整列出四个实例的读写地址,为精确依赖推导提供逐点基准。
  • 转置把换位放在访问中;生产者—消费者需要两个命名 tuple 和语句位置;矩阵乘的 $k$ 是归约维。
  • access-site 区分同实例的多个读写,事件时间 $\tau$ 在实例/语句位置之外加入 phase;RMW 的累加器 read 严格早于同实例 write。
  • 建模只提供程序事实。同址、原始顺序和最后写/下一写必须继续计算,才能得到调度使用的依赖关系。

第 7 章:精确数据依赖分析

直觉

两个动态实例访问同一地址,只说明它们可能冲突。精确依赖还要回答:source 是否先于 sink?它们之间是否有另一次写覆盖该值?

对 flow(RAW),sink 读到的是此前的最后写,不是任意更早写。对 anti(WAR),source 读必须早于此后的第一次覆盖写。对 output(WAW),直接边连接相邻写,而非所有有序写对。保留所有同址有序对可能仍保守安全,却会制造多余边,掩盖真正数据流和并行性。

访问始终按 instance → memory 读取;依赖始终按 source → sink 读取。访问逆关系只用来沿共享地址匹配,不会反转最终依赖含义。

形式定义

实例同址候选:复合方向不变

设 source 的一个访问 site 为 $A_{S,a}:D_S\to M$,sink 的一个访问 site 为 $B_{T,b}:D_T\to M$。严格按全文复合定义,

$$ \begin{aligned} \operatorname{Same}_{a,b} &=B_{T,b}^{-1}\circ A_{S,a}:D_S\to D_T,\\ (B_{T,b}^{-1}\circ A_{S,a})(x,y) &\Longleftrightarrow\exists m:\ A_{S,a}(x,m)\land B_{T,b}(y,m). \end{aligned} $$

路径是 $D_S\xrightarrow{A_{S,a}}M\xrightarrow{B_{T,b}^{-1}}D_T$,第一元仍是 source。isl 对照是

A_S_a.apply_range(B_T_b.reverse())

反写会得到 $D_T\to D_S$,不能仍称作同一个 source-to-sink 候选。该二元关系适合回答“是否同址”,但已经存在量化掉地址 $m$。若 source/sink 同时共享多个地址,不能在该投影结果上做覆盖删除;精确 last/next-write 必须先保留 access-site、事件和地址。

带地址的事件候选

沿用第 6 章事件模型。令 $E_R$ 与 $E_W$ 分别为所有读、写事件的带类型不交并,$\mathcal D=\biguplus_S D_S$ 为所有命名实例空间的不交并。定义

$$ \iota:E_R\uplus E_W\to\mathcal D,\qquad \mu:E_R\uplus E_W\to M,\qquad \tau:E_R\uplus E_W\to\mathbb Z^h, $$

分别给出事件所属实例、地址和包含循环时间、语句位置、访问 phase 的时间戳。事件已携带 access-site;若两个 site 具有语言规定的先后,$\tau$ 必须反映它,若未规定则不能任意制造顺序。

三类“同址且 source 早于 sink”的候选保留地址坐标:

$$ \begin{aligned} K_{RAW} &=\{(w,m,r)\in E_W\times M\times E_R\mid \mu(w)=m=\mu(r)\land\tau(w)\mathrel{\mathrm{lex}<}\tau(r)\},\\ K_{WAR} &=\{(r,m,w)\in E_R\times M\times E_W\mid \mu(r)=m=\mu(w)\land\tau(r)\mathrel{\mathrm{lex}<}\tau(w)\},\\ K_{WAW} &=\{(w_1,m,w_2)\in E_W\times M\times E_W\mid \mu(w_1)=m=\mu(w_2)\land\tau(w_1)\mathrel{\mathrm{lex}<}\tau(w_2)\}. \end{aligned} $$

这等价于逐 access-site 对构造 $B^{-1}\circ A$、附回共同地址与事件,再取并;关键是不能先把不同地址折叠为同一个实例对。

在同一地址上选择 last/next write

RAW 中被覆盖的三元候选为

$$ \begin{aligned} B_{RAW}=\{(w,m,r)\in K_{RAW}\mid \exists w'\in E_W:\ &\mu(w')=m\\ &\land\tau(w)\mathrel{\mathrm{lex}<}\tau(w') \land\tau(w')\mathrel{\mathrm{lex}<}\tau(r)\}. \end{aligned} $$

故精确事件级 flow 是

$$ F_{RAW}=K_{RAW}\setminus B_{RAW}\subseteq E_W\times M\times E_R. $$

它对每个 sink 读和地址 $m$ 选择此前时间最大的写。没有域内写的读来自 live-in,不会凭空产生 source。

WAR 和 WAW 都对 source 事件选择下一次同址写。令 $K$ 分别取 $K_{WAR}$ 或 $K_{WAW}$,其中三元组统一记作 $(e,m,w)$。跳过了更早覆盖写的候选为

$$ B_{\mathrm{next}}(K) =\{(e,m,w)\in K\mid \exists w'\in E_W:\ \mu(w')=m \land\tau(e)\mathrel{\mathrm{lex}<}\tau(w') \land\tau(w')\mathrel{\mathrm{lex}<}\tau(w)\}. $$

其中量词类型完整为 $w'\in E_W$,地址为该候选已有的 $m\in M$;若按语句展开,则写事件还带 $U\in\mathcal W$、$z\in D_U$ 与写 access-site。于是

$$ \begin{aligned} F_{WAR}&=K_{WAR}\setminus B_{\mathrm{next}}(K_{WAR}) \subseteq E_R\times M\times E_W,\\ F_{WAW}&=K_{WAW}\setminus B_{\mathrm{next}}(K_{WAW}) \subseteq E_W\times M\times E_W. \end{aligned} $$

中间读不覆盖值;只有同一 $m$ 上的中间写删除候选。

最后投影为实例依赖

对任一事件级关系 $F_X$,先完成地址级选择,再定义

$$ \begin{aligned} I_X&=\{(e_s,m,e_t)\in F_X\mid\iota(e_s)=\iota(e_t)\},\\ \Delta_X&=\{\iota(e_s)\to\iota(e_t)\mid (e_s,m,e_t)\in F_X\land\iota(e_s)\ne\iota(e_t)\} :\mathcal D\to\mathcal D. \end{aligned} $$

$I_X$ 是同一命名实例内部的事件边,由语句/RMW 语义保证,不产生不可能的实例调度约束 $\theta(x)<\theta(x)$。$\Delta_X$ 才交给实例调度器;不同静态语句的 tuple identity 不同,即使坐标相同也不会被误归为内部边。投影后,多个地址可合并成同一实例对,但此时每个地址的 last/next-write 决策已经完成,不会相互误删。

Feautrier 的 Dataflow Analysis of Array and Scalar References 是精确最后写语义的一手来源。这里的事件三元组、差集和投影顺序是适配本教程方向、RMW 与多访问例的教学性推导。isl API 含义以 isl 官方手册 为工具语义来源。

手算示例

一维 shift:精确 $\Delta_{RAW}$ 与 $N=5$ 对照

沿用第 6 章:

$$ \begin{aligned} C(N)&:N\ge2,& D_S&=\{[i]_S\mid1\le i<N\},\\ W_S&=\{[i]_S\to A[a]\mid a=i\}:D_S\to M_A,& R_S&=\{[j]_S\to A[a]\mid a=j-1\}:D_S\to M_A,\\ \theta_S&=\{[i]_S\to[i]\}:D_S\to\mathbb Z. \end{aligned} $$

先求同址:

$$ \begin{aligned} R_S^{-1}\circ W_S &=\{[i]_S\to[j]_S\mid \exists a:\ a=i\land a=j-1\\ &\hspace{30mm}\land1\le i<N\land1\le j<N\}\\ &=\{[i]_S\to[i+1]_S\mid1\le i<N-1\}:D_S\to D_S. \end{aligned} $$

原始顺序 $i<j$ 自动成立。整数 $k$ 不可能满足 $i<k<i+1$,故无中间覆盖写:

$$ \boxed{\Delta_{RAW}^{S\to S} =\{[i]_S\to[i+1]_S\mid1\le i<N-1\}:D_S\to D_S.} $$

省略 tuple 名后的坐标打印为 [i] -> [i + 1];完整关系类型仍为 $D_S\to D_S$,并按 source 实例到 sink 实例读取。

$N=5$ 时:

source 写共享地址sink 读中间写精确 RAW
$[1]_S$ 写 $A[1]$$A[1]$$[2]_S$ 读 $A[1]$$[1]_S\to[2]_S$
$[2]_S$ 写 $A[2]$$A[2]$$[3]_S$ 读 $A[2]$$[2]_S\to[3]_S$
$[3]_S$ 写 $A[3]$$A[3]$$[4]_S$ 读 $A[3]$$[3]_S\to[4]_S$

$[1]_S$ 对 $A[0]$ 的读没有域内 producer,$[4]_S$ 写 $A[4]$ 后没有域内 consumer。这与第 6 章四行真值表一致。距离 $j-i=1$ 只是最终关系的摘要,不能代替域、访问、同址、顺序和覆盖推导。

多地址反例:先投影会误删依赖

考虑一个 source/sink 实例对同时共享 $A[i]$ 和 $B[i]$,但中间只覆盖 $A[i]$:

for (int i = 0; i < N; ++i) {
    S: A[i] = B[i] = 1;
    U: A[i] = 2;
    T: x[i] = A[i] + B[i];
}

取 $C(N):N\ge1$,$D_S,D_U,D_T$ 为各命名 tuple 上的 $0\le i<N$。令 $s_A,s_B,u_A,t_A,t_B$ 为相应访问 site。相关实例访问均注明类型:

$$ \begin{aligned} W_{S,s_A}&=\{[i]_S\to A[i]\}:D_S\to M_A,& W_{S,s_B}&=\{[i]_S\to B[i]\}:D_S\to M_B,\\ W_{U,u_A}&=\{[i]_U\to A[i]\}:D_U\to M_A,& R_{T,t_A}&=\{[i]_T\to A[i]\}:D_T\to M_A,\\ R_{T,t_B}&=\{[i]_T\to B[i]\}:D_T\to M_B. \end{aligned} $$

原始事件顺序为 $S$ 的写事件早于 $U$ 写,$U$ 又早于 $T$ 的读。对每个 $i$,带地址 RAW 候选恰有

$$ \begin{aligned} &(s_A(i),A[i],t_A(i)),\\ &(s_B(i),B[i],t_B(i)),\\ &(u_A(i),A[i],t_A(i)). \end{aligned} $$

在 $A[i]$ 上,$u_A(i)$ 覆盖 $s_A(i)$,所以第一项进入 $B_{RAW}$;在 $B[i]$ 上没有中间写,第二项必须保留;第三项也是 $A[i]$ 的最后写。故

$$ F_{RAW} =\{(s_B(i),B[i],t_B(i)),(u_A(i),A[i],t_A(i))\mid0\le i<N\}. $$

最后投影才得到

$$ \Delta_{RAW} =\{[i]_S\to[i]_T\mid0\le i<N\} \cup\{[i]_U\to[i]_T\mid0\le i<N\}, $$

两个分支类型分别为 $D_S\to D_T$ 和 $D_U\to D_T$。若先把两个地址都投影成实例候选 $[i]_S\to[i]_T$,再因为存在 $U[i]$ 覆盖 $A[i]$ 而删除整对,就会错误丢掉 $B[i]$ 上真实的 $S\to T$ flow。这正是事件×地址×事件选择必须先于实例投影的原因。

RAW:最后写排除更早 producer

使用不同短程序:

for (int i = 0; i < N; ++i) {
    S: A[i] = 1;
    U: A[i] = 2;
    T: x[i] = A[i];
}

取 $C(N):N\ge1$,$D_S,D_U,D_T$ 分别是各命名 tuple 上的 $0\le i<N$。相关访问是

$$ \begin{aligned} W_S&=\{[i]_S\to A[a]\mid a=i\}:D_S\to M_A,\\ W_U&=\{[u]_U\to A[a]\mid a=u\}:D_U\to M_A,\\ R_T&=\{[j]_T\to A[a]\mid a=j\}:D_T\to M_A. \end{aligned} $$

原始调度为

$$ \theta_S=\{[i]_S\to[i,0]\}:D_S\to\mathbb Z^2,\quad \theta_U=\{[u]_U\to[u,1]\}:D_U\to\mathbb Z^2,\quad \theta_T=\{[j]_T\to[j,2]\}:D_T\to\mathbb Z^2. $$

同址关系为

$$ R_T^{-1}\circ W_S=\{[i]_S\to[i]_T\}:D_S\to D_T,\qquad R_T^{-1}\circ W_U=\{[i]_U\to[i]_T\}:D_U\to D_T. $$

两者均通过顺序过滤,但 $S[i]\to T[i]$ 中间有同址写 $U[i]$,故被差集移除;$U[i]\to T[i]$ 无中间写:

$$ \boxed{\Delta_{RAW}=\{[i]_U\to[i]_T\mid0\le i<N\}:D_U\to D_T.} $$

WAR:读必须早于第一次覆盖写

for (int i = 0; i < N; ++i) {
    R: x[i] = A[i];
    W: A[i] = 0;
    V: A[i] = 1;
}

取 $C(N):N\ge1$,$D_R,D_W,D_V$ 为各命名 tuple 上的 $0\le i<N$:

$$ \begin{aligned} R_R&=\{[i]_R\to A[a]\mid a=i\}:D_R\to M_A,\\ W_W&=\{[w]_W\to A[a]\mid a=w\}:D_W\to M_A,\\ W_V&=\{[v]_V\to A[a]\mid a=v\}:D_V\to M_A. \end{aligned} $$

原始调度分别为 $\theta_R=\{[i]_R\to[i,0]\}:D_R\to\mathbb Z^2$、$\theta_W=\{[w]_W\to[w,1]\}:D_W\to\mathbb Z^2$、$\theta_V=\{[v]_V\to[v,2]\}:D_V\to\mathbb Z^2$。

同址与顺序给出 $\{[i]_R\to[i]_W\}:D_R\to D_W$ 和 $\{[i]_R\to[i]_V\}:D_R\to D_V$。前者是第一次写;后者之前已有 $W[i]$,故删除:

$$ \boxed{\Delta_{WAR}=\{[i]_R\to[i]_W\mid0\le i<N\}:D_R\to D_W.} $$

它保护 $R[i]$ 读取旧值。更晚的 $V[i]$ 由 $W\to V$ 的 WAW 链间接排在后面,无需非直接边 $R\to V$。

WAW:相邻写形成直接链

for (int i = 0; i < N; ++i) {
    P: A[i] = 1;
    Q: A[i] = 2;
    Z: A[i] = 3;
}

取 $C(N):N\ge1$,$D_P,D_Q,D_Z$ 为各命名 tuple 上的 $0\le i<N$:

$$ \begin{aligned} W_P&=\{[i]_P\to A[a]\mid a=i\}:D_P\to M_A,\\ W_Q&=\{[q]_Q\to A[a]\mid a=q\}:D_Q\to M_A,\\ W_Z&=\{[z]_Z\to A[a]\mid a=z\}:D_Z\to M_A. \end{aligned} $$

调度分别为 $\theta_P=\{[i]_P\to[i,0]\}:D_P\to\mathbb Z^2$、$\theta_Q=\{[q]_Q\to[q,1]\}:D_Q\to\mathbb Z^2$、$\theta_Z=\{[z]_Z\to[z,2]\}:D_Z\to\mathbb Z^2$。

同址加顺序候选为

$$ \{[i]_P\to[i]_Q\}:D_P\to D_Q,\quad \{[i]_P\to[i]_Z\}:D_P\to D_Z,\quad \{[i]_Q\to[i]_Z\}:D_Q\to D_Z. $$

$P[i]\to Z[i]$ 中间有写 $Q[i]$,故删除;其余没有中间写:

$$ \boxed{\Delta_{WAW}= \{[i]_P\to[i]_Q\mid0\le i<N\} \cup\{[i]_Q\to[i]_Z\mid0\le i<N\}.} $$

两个分支类型分别是 $D_P\to D_Q$ 与 $D_Q\to D_Z$;放进 union map 后 tuple 名仍保留类型。直接链保证最后留下 3,而多余传递边不属于精确 WAW。

无依赖:同余排除区间伪冲突

for (int i = 0; i < N; ++i)
    S: A[2*i] = 1;
for (int j = 0; j < N; ++j)
    T: x[j] = A[2*j + 1];

取 $C(N):N\ge2$:

$$ \begin{aligned} D_S&=\{[i]_S\mid0\le i<N\},& W_S&=\{[i]_S\to A[a]\mid a=2i\}:D_S\to M_A,\\ D_T&=\{[j]_T\mid0\le j<N\},& R_{T,A}&=\{[j]_T\to A[a]\mid a=2j+1\}:D_T\to M_A,\\ &&W_{T,x}&=\{[j]_T\to x[b]\mid b=j\}:D_T\to M_x. \end{aligned} $$

假定 $M_A\cap M_x=\varnothing$,即 $A$ 与 $x$ 不别名。$\theta_S=\{[i]_S\to[0,i]\}:D_S\to\mathbb Z^2$、$\theta_T=\{[j]_T\to[1,j]\}:D_T\to\mathbb Z^2$,所以所有 $A$ 写先于所有 $A$ 读。同址却要求

$$ 2i=2j+1. $$

左侧模 2 为 0,右侧为 1,整数上无解:

$$ (R_{T,A})^{-1}\circ W_S=\varnothing:D_S\to D_T,\qquad \boxed{\Delta_{RAW}=\varnothing:D_S\to D_T.} $$

若只取各自地址的凸区间,写落在 $[0,2N-2]$,读落在 $[1,2N-1]$;当 $N\ge2$ 时二者相交,区间分析会报告伪候选。精确投影保留写地址 $a\equiv0\pmod2$ 与读地址 $a\equiv1\pmod2$,Omega 风格整数可行性检查判交为空。实数松弛中 $i=j+\tfrac12$ 可行,整数程序却无实例。

还要检查其余访问:$S[i]$ 写的偶地址随 $i$ 单射,故不同 $S$ 实例之间无 WAW;每个 $x[j]$ 也恰写一次且从不读取,故 $M_x$ 上无 RAW、WAR 或 WAW;不别名假设又排除了 $A$ 与 $x$ 的交叉冲突。因此这里确实是整个短程序无依赖,而不只是 $A$ 上 RAW 为空。这说明 Pugh 的 Omega Test 所强调的整数精确性为何重要。

归约依赖:普通冲突不等于禁止并行

for (int i = 0; i < N; ++i)
    S: sum += A[i];

取 $C(N):N\ge1$、$D_S=\{[i]_S\mid0\le i<N\}$:

$$ \begin{aligned} R_{S,A}&=\{[i]_S\to A[a]\mid a=i\}:D_S\to M_A,\\ R_{S,sum}&=W_{S,sum}=\{[i]_S\to sum\}:D_S\to M_{sum},\\ \theta_S&=\{[i]_S\to[i]\}:D_S\to\mathbb Z. \end{aligned} $$

令 $a_i$ 是读 $A[i]$ 的事件,$r_i$ 是读 sum 的事件,$w_i$ 是写 sum 的事件。事件映射例如

$$ \begin{aligned} \iota(r_i)&=\iota(w_i)=[i]_S,& \mu(r_i)&=\mu(w_i)=sum,\\ \tau(r_i)&=[i,0],& \tau(w_i)&=[i,1]. \end{aligned} $$

这里 $\iota:\{r_i,w_i\}\to D_S$、$\mu:\{r_i,w_i\}\to M_{sum}$、$\tau:\{r_i,w_i\}\to\mathbb Z^2$;关键是 $r_i$ 的 read phase 0 严格早于 $w_i$ 的 write phase 1。$a_i$ 访问不别名的 $M_A$,与 sum 事件没有同址边;它和 $r_i$ 之间若语言未规定求值顺序,不必人为排序。

固定 $N=3$,相关 read/write 事件可枚举为:

迭代数组读事件累加器读事件累加器写事件必须的实例内顺序
0$a_0:R\,A[0]$$r_0:R\,sum$$w_0:W\,sum$$r_0\prec w_0$
1$a_1:R\,A[1]$$r_1:R\,sum$$w_1:W\,sum$$r_1\prec w_1$
2$a_2:R\,A[2]$$r_2:R\,sum$$w_2:W\,sum$$r_2\prec w_2$

按带地址候选和 next-write/last-write 选择,直接普通内存依赖恰为

$$ \begin{aligned} F_{RAW}&=\{(w_0,sum,r_1),(w_1,sum,r_2)\},\\ F_{WAR}&=\{(r_0,sum,w_0),(r_1,sum,w_1),(r_2,sum,w_2)\},\\ F_{WAW}&=\{(w_0,sum,w_1),(w_1,sum,w_2)\}. \end{aligned} $$

$r_i$ 后的 next write 是同实例 $w_i$,所以不存在虚假的跨迭代 WAR $r_i\to w_{i+1}$。三个 WAR 都属于内部集合 $I_{WAR}$,由 RMW 语义保证,不投影为实例调度约束。RAW 和 WAW 投影后都给出相邻实例链 $[0]_S\to[1]_S$、$[1]_S\to[2]_S$。

识别出 $sum=sum\oplus value(i)$ 后,可把这个跨迭代 recurrence bundle 单独分类为归约依赖

$$ \Delta_{red}^{S\to S} =\{[i]_S\to[i+1]_S\mid0\le i<N-1\}:D_S\to D_S. $$

这不是否认普通 RAW/WAW 的存在,而是为合法的私有化与合并提供更高层语义。内部 $r_i\to w_i$ 仍是每次 RMW 必须保持的语句内部行为。归约私有化让 worker 各自累积,再以 $\oplus$ 合并;它改变中间内存事件,只有算子和语言语义允许时才保持结果。

矩阵乘同理。对固定 $(i,j)$,令 $r_k^C,w_k^C$ 是第 $k$ 次更新对 $C[i,j]$ 的读写事件,则

$$ \begin{aligned} F_{RAW}^C&=\{(w_k^C,C[i,j],r_{k+1}^C)\mid0\le k<K-1\},\\ F_{WAR}^C&=\{(r_k^C,C[i,j],w_k^C)\mid0\le k<K\},\\ F_{WAW}^C&=\{(w_k^C,C[i,j],w_{k+1}^C)\mid0\le k<K-1\}. \end{aligned} $$

其中 WAR 是同一 $[i,j,k]_S$ 内部的 read-to-write;RAW/WAW 是相邻 $k$ 的实例依赖。归约分类把跨 $k$ recurrence 表示为

$$ \Delta_{red}^{S\to S} =\{[i,j,k]_S\to[i,j,k+1]_S\mid 0\le i<M\land0\le j<N\land0\le k<K-1\}:D_S\to D_S. $$

不同 $(i,j)$ 地址不同。并行化 $k$ 需要私有化、树形合并或合适原子/归约原语,不能只删除边。

数学整数加法满足结合、交换律;固定宽度无符号模加法也有相应代数律,但有符号溢出须服从语言。IEEE 浮点加法一般不满足结合律,重排改变舍入顺序,NaN、无穷和有符号零也可能影响结果。因此浮点重结合只有在语言规则、显式快速数学选项或用户容差/可重现性约定允许时才合法。归约依赖必须与一般 flow 分开处理。

多语句与 stencil

第 6 章生产者—消费者中:

$$ R_{T,B}^{-1}\circ W_{S,B} =\{[i]_S\to[i]_T\mid0\le i<N\}:D_S\to D_T. $$

$(i,0)\mathrel{\mathrm{lex}<}(i,1)$,且无其他 $B[i]$ 写,所以这也是精确 $\Delta_{RAW}^{S\to T}$。坐标数值相同,tuple identity 仍分别是 producer $S$ 与 consumer $T$。

对主 stencil 的读偏移 $\delta\in\{-1,0,+1\}$,source 写 $A[t-1,i+\delta]$,sink $S[t,i]$ 读取:

$$ \Delta_{\delta}^{S\to S} =\{[t-1,i+\delta]_S\to[t,i]_S\mid 2\le t\le T\land1\le i<N-1\land1\le i+\delta<N-1\}:D_S\to D_S. $$

边界处若 producer 不在更新域,读值来自初始/边界条件。三个分支都从较早时间层 source 指向较晚时间层 sink。

Presburger/Omega 操作的职责

  1. 判空。 检查同址加顺序约束是否有整数解;奇偶例在此被判空。
  2. 投影。 覆盖查询可消去中间写事件 $w'$ 及其实例坐标,但必须暂时保留候选的共同地址 $m$ 和端点 access-site;last/next-write 完成后,才把 $m$ 与 site 投影掉得到实例关系。逻辑上这些都是存在量词消去,先后次序却影响精确性。
  3. 词典序最大/最小。 对 sink 读和固定地址从先行写事件中取最大时间得到最后写;对 source 读/写和固定地址从后继写事件中取最小时间得到第一次覆盖写。必须使用含循环时间、语句位置与 access phase 的完整 $\tau$。
  4. 差集。 在事件×地址×事件的三元候选上减去存在同址中间写的项,实现“候选且不存在覆盖见证”;不能在已折叠多个地址的实例对上做这一步。

Omega Test 为整数仿射可行性与依赖检查提供经典依据;Feautrier 给出精确数据流的最后写路线。本教程只声称给定 Presburger 模型内精确;若前端使用区间、凸包或别名近似,整体精度仍受这些近似限制。

编译器用途

  1. 调度合法性输入。 先把内部事件边 $I_X$ 与跨实例边分开,再汇总 $\Delta=\Delta_{RAW}\cup\Delta_{WAR}\cup\Delta_{WAW}$;新实例调度必须让每条 $x\to y$ 仍从 source 指向 sink。内部 RMW phase 由语句语义保持,合法实现的归约边另按归约规则处理。
  2. 揭示并行性。 删除被覆盖的传递候选,避免无意义固定早期写与远期访问;精确性不自动保证性能更好。
  3. 解释值来源。 RAW 把每次读连到实际 producer,可用于值转发和通信生成;live-in/live-out 需单独表示。
  4. 重命名与私有化。 WAR/WAW 常来自存储复用;数组扩张或 SSA 化可消除某些边,但须证明可观察结果不变。
  5. 归约并行化。 仍要选择私有化、合并顺序和数值语义;合法性与速度收益分别论证。

常见误区

  1. 把 $W_S^{-1}\circ R_T$ 当成 S → T。 它是 $D_T\to D_S$;正确候选是 $R_T^{-1}\circ W_S:D_S\to D_T$。
  2. 把 isl 复合写反。 $R_T^{-1}\circ W_S$ 对应 W_S.apply_range(R_T.reverse())。
  3. 把同址且有序称为精确 flow。 还须排除中间覆盖写,或等价地取最后写。
  4. 三类依赖都取“最后写”。 RAW 对 sink 取先行写最大者;WAR/WAW 对 source 取后继写最小者。
  5. 中间读算覆盖。 读不改变值;覆盖条件寻找中间写。
  6. 只给 distance vector。 它丢失 tuple、边界、分支和 live-in,不能替代完整关系。
  7. 把归约链当普通 flow 后直接删除。 删除边须伴随私有化/合并并满足重结合条件。
  8. 默认浮点加法可结合。 常规 IEEE 语义下重排可能改变结果,需要显式许可。
  9. 用实区间覆盖整数同余。 区间相交不证明存在整数同址实例。
  10. 过早投影共同地址。 一个实例对可共享多个位置,只覆盖其中一个不能删除另一个位置上的依赖。
  11. RMW 只使用实例调度。 read 与 write 同属一个实例;缺少 access phase 会漏掉内部 WAR,并把 next write 错推到下一迭代。
  12. 把内部事件边交给实例调度器。 $r_i\to w_i$ 约束语句内部语义,不要求同一实例满足 $\theta(i)<\theta(i)$。

练习

练习 EX07-B01|两语句 shift 的精确 RAW(基础)

取 $N\ge1$。先执行 for (i=0;i<N;++i) P: A[i]=f(i);,再执行 for (j=1;j<N;++j) Q: x[j]=A[j-1];,且 $A$ 与 $x$ 不别名。按复合定义推导同址候选、原始顺序和精确 RAW;答案中标明 source 与 sink。

答案索引: ANS-EX07-B01

练习 EX07-D01|删除覆盖写后的 RAW 重算(推导)

在 RAW 覆盖例中删除 $U$,从访问、同址候选、顺序与 Covered 差集开始重算,并解释为何不能只从旧精确依赖中删边。

答案索引: ANS-EX07-D01

练习 EX07-D02|四次连续写的精确 WAW 链(推导)

构造四次连续同址写的 WAW 候选,再按 next-write 只保留相邻链,注明每个 union 分支的 source/sink 类型。

答案索引: ANS-EX07-D02

练习 EX07-D03|模 3 排除伪冲突(推导)

取 $N\ge2$。先执行 $S(i):A[3i]=1$($0\le i<N$),再执行 $T(j):x[j]=A[3j+1]$($0\le j<N$),且 $A$ 与 $x$ 不别名。证明 $A$ 上 source $S$ 到 sink $T$ 的 RAW 为空,并比较整数判空与地址区间近似。

答案索引: ANS-EX07-D03

练习 EX07-C01|矩阵乘初始化 RAW 与归约边(综合)

给矩阵乘加入初始化,推导 source 初始化实例到 sink $k=0$ 更新的 RAW,以及 source $k$ 到 sink $k+1$ 的相邻归约边;讨论 $K=0$ 与 $K=1$ 的边界。

答案索引: ANS-EX07-C01

练习 EX07-C02|Covered 差集与 lexmax 等价(综合)

某个 sink 读事件前有三个同址写。分别用“候选差去 Covered”和“按地址取词典序最大先行写”求 producer,并证明两种方法一致。

答案索引: ANS-EX07-C02

练习 EX07-C03|多地址 last-write 后投影(综合)

重算多地址反例:分别在 $A[i]$、$B[i]$ 上做 last-write,再投影地址;说明为何先投影地址的算法会误删真实边。

答案索引: ANS-EX07-C03

练习 EX07-C04|RMW phase 与内部 WAR(综合)

枚举 $N=3$ 的 sum += A[i] RMW 读写事件,用 phase 与 next-write 证明 WAR 只含三个内部 read-to-write 边,并解释为何它们不要求实例调度满足 $\theta(i)<\theta(i)$。

答案索引: ANS-EX07-C04

本章小结

  • 同址候选严格写成 $B_T^{-1}\circ A_S:D_S\to D_T$,isl 对照为 A_S.apply_range(B_T.reverse());二者都保持 source → sink。
  • 精确选择必须保留 access-site、事件和共同地址 $m$:在事件×地址×事件候选上选择 last/next-write,最后才投影为实例依赖。
  • RAW 对 sink 事件和地址选择此前最后写;WAR 与 WAW 对 source 事件和地址选择此后第一次写。中间读不覆盖,中间写才切断直接边。
  • 一维 shift 的精确关系是 $\Delta_{RAW}^{S\to S}=\{[i]_S\to[i+1]_S\mid1\le i<N-1\}$,$N=5$ 时恰有三条可核对边。
  • RAW、WAR、WAW、无依赖和归约依赖必须分开解释;距离向量不能替代完整推导。
  • RMW 的 $\tau$ 必须含 access phase;同实例 read-to-write WAR 属于内部语义,跨实例 RAW/WAW 才约束实例调度。
  • 精确同余可排除区间/实松弛的伪依赖;投影地址必须推迟到覆盖选择之后。
  • 归约依赖抽象普通跨迭代 recurrence,而不抹掉内部 RMW;并行化还受私有化、合并、整数溢出、浮点重结合和语言选项约束。

第 8 章:仿射调度与多维时间

直觉

第 7 章把程序真正必须保持的跨实例顺序汇总为依赖关系

$$ \Delta_{S\to T}\subseteq D_S\times D_T. $$

其中第一元是 source,第二元是 sink。调度的任务不是重新猜测值从哪里来,而是给每个语句实例分配一个新时间戳,并保证每条已有依赖仍从早指向晚。

一个时间戳可以有多维。例如 $(3,5)$ 早于 $(4,-100)$,因为词典序只查看第一个不同分量;第二分量再小也不能推翻第一分量已经确定的先后。因此,多维调度的合法性不是“每一维都严格递增”,而是“第一个非零距离分量为正”。这个区别正是循环交换、融合、倾斜和并行维构造的基础。

仿射调度把时间戳限制为循环变量和全局参数的仿射函数。限制看似很强,却把寻找循环变换的问题变成寻找有限多个系数的问题。第 9 章会继续说明,如何用 affine Farkas 引理把“对所有依赖实例成立”也变成有限约束。

本章始终分开两个问题:

  1. 合法性:所有 source → sink 依赖是否严格向前;
  2. 性能:合法候选中,哪个更利于并行、局部性、向量化或 tiling。

前者是必须满足的语义边界,后者才是优化选择。

形式定义

一维与多维仿射调度

令语句 $S$ 的迭代向量为 $x\in D_S(p)\subseteq\mathbb Z^{d_S}$,参数向量为 $p\in\mathbb Z^q$,参数上下文为 $C(p)$。一维仿射调度写成

$$ \theta_S(x,p)=C_Sx+E_Sp+c_S\in\mathbb Z. $$

这里 $C_S$ 是迭代变量的系数行向量,$E_S$ 是参数的系数行向量,$c_S$ 是常数;它们是待求的调度系数。$E_S$ 使用尚未被域记号占用的字母,因而不会与迭代域 $D_S(p)$ 混淆;符号 $C_S$ 也不同于参数上下文 $C(p)$。要求整数时间戳时,这些系数取整数;也可先求有理系数,再按保持顺序的统一正尺度清除分母。

一个 $k$ 维仿射调度为

$$ \Theta_S(x,p) =\bigl(\theta_S^{(1)}(x,p),\ldots,\theta_S^{(k)}(x,p)\bigr) \in\mathbb Z^k, $$

每个分量各有一组仿射系数。不同语句的系数可以不同,因此常数分量可以表达同一循环坐标处的语句顺序。

合法性的固定方向:source 严格早于 sink

对每条依赖 $(x,y)\in\Delta_{S\to T}(p)$,合法调度必须满足

$$ \boxed{ \Theta_S(x,p)\mathrel{\mathrm{lex}<}\Theta_T(y,p) } $$

即 source 的时间戳严格小于 sink 的时间戳。不能交换两端后仍称作同一方向。

一维时定义调度差

$$ d(x,y,p)=\theta_T(y,p)-\theta_S(x,p). $$

若时间戳属于整数,则严格先后等价于

$$ d(x,y,p)\ge1. $$

“至少 1”使用了整数刻度;若尚在未归一化的有理时间上求解,只能先写 $d>0$,再统一清分母或规定尺度,不能无条件把任意正有理数说成至少 1。

词典序的逐层语义

对多维调度,令第 $r$ 维的距离为

$$ d_r(x,y,p) =\theta_T^{(r)}(y,p)-\theta_S^{(r)}(x,p). $$

从某条依赖关系或其一个非空分支开始,记尚未被先前维度严格承载的实例集合为 $U_0=\Delta_{S\to T}$。第 $r$ 层只在当前残余集合 $U_{r-1}$ 上要求

$$ \forall(x,y)\in U_{r-1}:\quad d_r(x,y,p)\ge0. $$

这叫本维对残余依赖的 weak satisfaction(弱满足)。其中

$$ K_r=U_{r-1}\cap\{(x,y)\mid d_r(x,y,p)\ge1\} $$

中的整数依赖实例在前面各维距离都为零,而在第 $r$ 维严格为正,所以由本维 strictly carried(严格承载)。距离仍为零的实例形成下一层残余关系

$$ U_r=U_{r-1}\cap\{(x,y)\mid d_r(x,y,p)=0\}. $$

若最终 $U_k=\varnothing$,每条依赖都在某个最早非零维得到正距离,因而整个向量严格词典序合法。对已经属于某个 $K_r$ 的依赖,后续距离可以为正、零或负,因为词典序先后已经由第 $r$ 维决定。于是下面三个术语必须分开:

  • weak satisfaction:当前残余关系上本维距离非负,允许为零;
  • strict carry:此前各维为零、本维距离至少为 1 的整数依赖实例;
  • residual dependence:此前各维距离都为零,尚须交给下一维处理的实例。

Feautrier 的 Part I 研究一维时间及其约束化;Part II 把算法扩展到词典序多维时间,并按需要构造足够的调度维数。本节的 $U_r$ 写法是为突出逐层语义所作的教学性整理。

固定候选的语义与逐维合成的顺序

上面的 $K_r,U_r$ 首先定义了一个已经固定的多维候选调度如何承载依赖:此时每个 $d_r$ 的系数已知,集合交可以直接计算。自动合成时,当前维的 $C_S^{(r)},E_S^{(r)},c_S^{(r)}$ 尚未知,不能把含这些未知系数的 $d_r=0$ 立即当成下一层 Farkas 的已知前提。

本教程采用以下顺序流程:

  1. 第 $r$ 轮开始时,$U_{r-1}$ 已知;$r=1$ 时它就是输入依赖 $U_0$,以后各轮则来自已经固定的前一维。
  2. 只在这个已知 $U_{r-1}$ 上,为当前 $d_r\ge0$ 建立 Farkas 约束,求出当前维,并按该轮的进展或性能准则选定一组系数。
  3. 对本轮涉及的每个语句 $S$,固定 $C_S^{(r)},E_S^{(r)},c_S^{(r)}$。代入后 $d_r$ 成为已知仿射式,再计算 $K_r=U_{r-1}\cap\{d_r\ge1\}$ 与 $U_r=U_{r-1}\cap\{d_r=0\}$。
  4. 若 $U_r\ne\varnothing$,把这个已知的新 residual dependence 化为下一轮可处理的分支或多面体描述,再为第 $r+1$ 维重新建立有限系统;若为空,严格词典序构造结束。

顺序中的“先固定、再求 $U_r$”是线性有限化的必要边界。若同时求所有维,下一层残余域的约束矩阵会含上一维未知调度系数;它再与下一层 Farkas 乘子相乘,出现“未知调度系数 × 未知乘子”的双线性项。普通 LP/ILP 不会仅因变量声明为整数就自动线性化这种乘积。联合求多维调度需要另行设计带有效界的离散或线性化编码;本教程没有给出、也不声称当前公式已经给出这种联合 ILP。

Permutable band 与 coincident 维

一个 band 是准备作为整体处理的一组连续调度维。仅有整个时间向量 lex-positive,并不足以任意交换这些维:某条依赖可能靠较早分量的正值掩盖较晚分量的负值,一旦交换,负值就可能先出现。

在常用的教学性判据下,先只看进入 band 时尚未由外层严格承载的活动依赖:若它们在 band 内每一维的距离都非负,这些维可构成 permutable band。其中在 band 内出现正分量的依赖由 band 承载;band 内距离全为零的依赖仍可留给后续维处理。分量非负保证交换 band 内的循环维不会让活动依赖以负分量开头;这种结构也是矩形 tiling 的重要入口。实际调度树还要结合依赖过滤、语句域和工具对 band 的具体定义。

若某一调度维对进入该维时仍活动、会限制并行执行的相关依赖距离都为零,则称该维 coincident;在没有归约、同步、别名等额外障碍时,它可对应并行循环维。coincident 指依赖距离为零,不是“该维调度系数全部为零”,也不能只检查一条依赖便下结论。

手算示例

一维 shift:identity、reverse 与 constant 逐条验证

沿用第 7 章的精确 RAW 关系:

$$ \Delta_{S\to S} =\{[i]_S\to[i+1]_S\mid1\le i<N-1\}. $$

对任意 source $i$ 和 sink $i+1$,逐一验证三个一维候选。

Identity schedule 取 $\theta(i)=i$。调度差为

$$ \theta(i+1)-\theta(i)=(i+1)-i=1\ge1. $$

所以每条 source → sink 依赖都严格向前,identity 合法。

Reverse schedule 取 $\theta(i)=-i$。调度差为

$$ \theta(i+1)-\theta(i)=-(i+1)-(-i)=-1<1. $$

它让 sink 早于 source,reverse 非法。

Constant schedule 取 $\theta(i)=0$。调度差为

$$ \theta(i+1)-\theta(i)=0. $$

两端时间戳相同,无法区分这条已有依赖的先后,所以作为完整一维调度非法。常数分量并非总无用:它可以是多维调度中允许并列、交给后续维处理的弱满足维,也可区分不同语句,例如 $\theta_P(i)=0,\theta_C(i)=1$。这里的非法结论来自 shift 确实存在自依赖,而不是“任何两个相同时间戳都无条件非法”。

生产者—消费者:sequence 与 fusion 都可以合法

设各个 $i$ 之间独立,唯一依赖为

$$ \Delta_{P\to C} =\{[i]_P\to[i]_C\mid0\le i<N\}. $$

一种分阶段的 sequence/distribution 风格调度是

$$ \Theta_P(i)=(0,i),\qquad \Theta_C(i)=(1,i). $$

每条依赖的距离为 $(1,0)$,第一维严格承载它;所有 producer 阶段在所有 consumer 阶段之前。

另一种逐元素融合调度是

$$ \Theta_P(i)=(i,0),\qquad \Theta_C(i)=(i,1). $$

每条依赖的距离为 $(0,1)$:第一维弱满足且留下全部残余依赖,第二维再严格承载。它产生 $P(0),C(0),P(1),C(1),\ldots$ 的顺序。

两个调度都满足同一 source → sink 严格词典序约束,但性能取舍不同。融合通常缩短中间值复用距离并减小工作集;分阶段则可能更利于每个阶段独立向量化、批处理或采用不同并行策略。融合还可能增加寄存器压力或把资源需求不同的两个 kernel 绑在一起。因此,合法性没有宣布哪一个更快。

对融合调度,第一维在这组依赖上的距离恒为零;若确实不存在跨 $i$ 的其他依赖,它是 coincident 候选,可让不同 $i$ 并行。第二维仅编码同一 $i$ 内 producer 在 consumer 之前。

二维循环交换:要检查变换后的第一个非零距离

考虑二维语句实例 $S(i,j)$,并有依赖

$$ \Delta =\{[i,j]_S\to[i+1,j-1]_S \mid0\le i<I-1\land1\le j<J\}. $$

原 identity 调度 $\Theta(i,j)=(i,j)$ 的距离为

$$ (i+1,j-1)-(i,j)=(1,-1). $$

虽然第二分量为负,第一非零分量是 $+1$,所以它严格词典序合法。这也直接反驳“合法要求每维都非负或严格递增”。

交换两个循环相当于候选 $\Theta'(i,j)=(j,i)$。同一依赖的距离变为

$$ (j-1,i+1)-(j,i)=(-1,1). $$

第一个非零分量是 $-1$,故 interchange 非法。若程序只有 $[i,j]\to[i,j+1]$ 这样的内层前向依赖,则交换后距离从 $(0,1)$ 变成 $(1,0)$,仍合法。循环交换本身既非总合法也非总非法;答案由完整依赖关系决定。

主 stencil:skewing 把负的空间分量变为可置换结构

主案例的三个依赖分支为

$$ \Delta_\delta =\{[t-1,i+\delta]_S\to[t,i]_S \mid \delta\in\{-1,0,1\}\ \land\ \text{两端均在域内}\}. $$

identity 调度 $\Theta(t,i)=(t,i)$ 下,从 source $(t-1,i+\delta)$ 到 sink $(t,i)$ 的距离是

$$ (1,-\delta). $$

三个分支分别得到 $(1,1),(1,0),(1,-1)$。它们都 lex-positive,因为时间维首先增加 1;但最后一个分支的空间距离为负,所以 $(t,i)$ 两维不满足上述 permutable band 的分量非负充分条件,直接交换也会出错。

取倾斜调度

$$ \Theta'(t,i)=(t,t+i). $$

则距离变成

$$ \begin{aligned} \Theta'(t,i)-\Theta'(t-1,i+\delta) &=(t,t+i)-(t-1,t-1+i+\delta)\\ &=(1,1-\delta). \end{aligned} $$

对 $\delta=-1,0,1$,分别是 $(1,2),(1,1),(1,0)$,每个分量都非负,且第一分量严格为正。于是这两个调度维形成适合交换与矩形 tiling 的非负距离结构。skewing 没有删除依赖;它改变坐标,使 wavefront 的合法顺序更容易组织成可置换 band。是否真的更快仍取决于 tile 大小、边界代码、并行粒度和存储层次。

编译器用途

  1. 把依赖变成调度可行域。 对第 7 章产生的每个 $\Delta_{S\to T}$,编译器建立 source 早于 sink 的约束;第 9 章将说明如何有限化其中的全称量词。
  2. 组织 sequence 与 fusion。 不同语句的常数和循环系数决定它们是分阶段执行,还是在共同循环坐标下交错执行。
  3. 识别 interchange 与 skewing。 变换后重新计算依赖距离;严格词典序检查决定语义合法性,分量非负结构进一步决定 band 是否适合置换和 tiling。
  4. 逐层暴露并行性。 一维调度严格承载一部分依赖后,调度器先固定该维、计算已知残余关系,再为下一维重新建模;某维对所有相关依赖距离为零时,才可能标为 coincident。
  5. 保留参数化结构。 $E_Sp$ 让调度随合法参数上下文变化,但参数条件必须与依赖域一起参与全称合法性检查。
  6. 传给后续代码生成。 合法的调度不是最终循环文本。编译器还须扫描调度像、生成边界与 guard,并保持语句内部事件语义。

Feautrier Part IPart II 给出仿射调度的经典算法路线。Pluto 项目与作者资料 展示了面向并行性和局部性的自动仿射变换实践。它们都在合法域上进一步选择调度,而不是用性能目标代替依赖合法性。

常见误区

  1. 把方向写成 sink → source。 固定条件是 $\Theta_S(x)\mathrel{\mathrm{lex}<}\Theta_T(y)$,其中 $(x,y)\in\Delta_{S\to T}$。
  2. 要求每一维都严格递增。 严格词典序只要求第一个非零距离为正;之前各维为零,之后各维不再决定该依赖。
  3. 把 weak satisfaction 当作已经完成合法性。 $d_r=0$ 的实例仍在残余关系中,必须由后续维严格承载。
  4. 认为较晚维也必须非负。 对已经由更早维严格承载的依赖,较晚维可为负;只有构造 permutable band 时才另加更强的非负结构。
  5. 把 permutable 等同于 lex-positive。 lex-positive 允许 $(1,-1)$,但交换两维会得到非法的 $(-1,1)$。
  6. 把 coincident 解释为系数为零。 判断对象是所有相关依赖的该维距离,还要排除归约、同步和别名等其他限制。
  7. 宣布 constant schedule 总非法。 对 shift 自依赖,完整一维常数调度确实非法;作为多维前缀或跨语句常数顺序,它可以有合法用途。
  8. 对未归一化有理时间直接写差至少 1。 $>0$ 到 $\ge1$ 依赖整数时间戳或清分母后的尺度约定。
  9. 把合法调度当成高性能调度。 sequence 与 fusion 可以同时合法,却有不同的局部性、并行和资源取舍。
  10. 只检查一个代表距离。 参数边界、析取分支和不同语句依赖都必须纳入完整关系,不能用一个平均距离替代全称检查。
  11. 把未知 $U_r$ 直接送进下一层 Farkas。 合成时必须先解出并固定第 $r$ 维,才能让 $d_r=0$ 成为已知线性约束;否则下一层乘子会与上一层未知调度系数形成双线性乘积。

练习

练习 EX08-B01|Shift 候选调度合法性(基础)

对 shift 关系 $[i]\to[i+1]$,分别检验 $\theta(i)=2i+3$、$\theta(i)=-2i$、$\theta(i)=7$。统一计算 $\theta(\mathrm{sink})-\theta(\mathrm{source})$,并判定一维合法性。

答案索引: ANS-EX08-B01

练习 EX08-B02|Producer/consumer 常数次序(基础)

对 $P(i)\to C(i)$,验证 $\Theta_P=(i,1),\Theta_C=(i,0)$ 为何非法;再只改一个常数使它合法。

答案索引: ANS-EX08-B02

练习 EX08-D01|Lex-positive 与 permutable band(推导)

取二维距离 $(1,-3)$。说明它为何 lex-positive,却不能直接证明两维构成 permutable band;交换两维后重新判断。

答案索引: ANS-EX08-D01

练习 EX08-D02|Residual dependence 分层(推导)

设已知残余关系 $U_0$ 被第一维距离分成 $d_1=1$ 与 $d_1=0$ 两类,且在 $d_1=0$ 类上 $d_2=2$。只用集合条件写出 $K_1,U_1,K_2,U_2$,说明哪些依赖由哪一维严格承载;不要求枚举未给出的具体实例。

答案索引: ANS-EX08-D02

练习 EX08-C01|两支依赖下的 identity/interchange(综合)

对依赖 $[i,j]\to[i,j+1]$ 和 $[i,j]\to[i+1,j-2]$ 的并,分别检查调度 $(i,j)$ 与 $(j,i)$;不能只检查其中一个分支。

答案索引: ANS-EX08-C01

练习 EX08-D03|Stencil skew 系数下界(推导)

将 stencil 的倾斜推广为 $\Theta_k(t,i)=(t,kt+i)$。求三个 source-to-sink 距离 $(1,k-\delta)$,给出使第二分量对所有 $\delta\in\{-1,0,1\}$ 非负的最小整数 $k$。

答案索引: ANS-EX08-D03

练习 EX08-C02|Sequence 与 fusion 的性能权衡(综合)

为逐元素 $P(i)\to C(i)$ 比较分阶段与融合调度:分别列出 $N=3$ 时的执行顺序,并各写一个可能的性能优势和一个代价。不得把合法性直接当作加速结论。

答案索引: ANS-EX08-C02

练习 EX08-D04|后续负维不推翻词典序合法性(推导)

构造一个两维调度,使某条依赖第一维距离为 0、第二维为 1;再添加第三维距离 $-100$,解释为何完整调度仍合法。

答案索引: ANS-EX08-D04

本章小结

  • 仿射调度把语句实例和参数映到整数时间戳;合法性始终按 source → sink 写成 $\Theta_S(x)\mathrel{\mathrm{lex}<}\Theta_T(y)$。
  • 对整数一维时间,严格先后等价于 sink 减 source 至少为 1;identity shift 合法,reverse 与完整 constant schedule 非法。
  • 多维调度逐层处理残余依赖:本维先 weakly satisfy,正距离实例由本维 strictly carry,零距离实例继续进入 residual dependence。
  • 验证固定候选时可直接定义所有 $U_r$;合成时必须按“已知 $U_{r-1}$ → 求并固定当前维 → 计算已知 $U_r$ → 下一维重新建模”的顺序执行,本文不提供联合多维 ILP。
  • 词典序合法不要求每维严格递增;已经由前维承载的依赖,其后续距离甚至可以为负。
  • Permutable band 要求比普通 lex-positive 更强的非负距离结构;coincident 维则要求所有相关保序依赖在该维距离为零。
  • sequence、fusion、interchange 与 skewing 都必须从完整依赖关系证明合法;stencil 倾斜 $(t,t+i)$ 把三个距离变为 $(1,2),(1,1),(1,0)$。
  • 两个调度可以同样合法却有不同并行性与局部性;合法性定义可行边界,性能目标在边界内另行选择。

第 9 章:Farkas 引理与 LP/ILP 调度合成

直觉

第 8 章的合法性看起来包含无限多个条件。参数 $N$ 没有固定上界时,一条依赖关系可以含任意多实例;若逐点检查

$$ \theta_T(y,p)-\theta_S(x,p)\ge1, $$

就无法在编译期枚举完所有 $(x,y,p)$。但是调度差和依赖约束都是仿射的。Affine form of Farkas lemma 利用这一结构,把“某个仿射式在整个非空多面体上非负”改写为有限多个非负乘子和系数等式。

关键直觉是:若多面体由若干个已知非负式定义,那么这些非负式的任意非负线性组合仍在多面体上非负。Farkas 引理说明,在适当条件下,所有在该多面体上处处非负的仿射式都可这样取得,并允许再加一个非负常数 $\lambda_0$。于是全称量词消失,留下调度系数和乘子的有限线性系统。

这一步只建立合法解的可行域,并不自动选择最快的调度。编译器还要另设目标,例如缩短依赖距离、尽早暴露 coincident 维,或构造适合 tiling 的 permutable band。变量域和离散选择决定最终是 LP、ILP,还是更复杂的参数化/词典序优化问题。

还有一条不可跨越的边界:普通 Farkas 引理直接讨论实数或有理多面体,不是任意整数 Presburger 集合。整数程序可以走实松弛的保守路径,或先求 integer hull 取得精确路径;同余、析取和量词结构则不能原样塞进普通 Farkas。

形式定义

只够本章使用的 LP/ILP 背景

一组线性等式和不等式定义一个可行域。在线性规划(LP)中,未知量允许取实数或有理数;在整数线性规划(ILP)中,指定的未知量必须取整数。若另给线性目标函数,求解器在可行域中最小化或最大化它;没有目标时,问题只是可行性检查。

例如

$$ Q=\{(u,v)\in\mathbb R^2\mid u\ge0,\ v\ge0,\ 3-u-v\ge0\} $$

是顶点为 $(0,0),(3,0),(0,3)$ 的三角形:

v
3  *
   |\
   | \
   |  \
0  *---*  u
   0   3

要求 $f(u,v)=4-u-v$ “对所有 $(u,v)\in Q$ 非负”,表面上是连续无限多个点上的约束。实际上

$$ 4-u-v=1+(3-u-v), $$

即非负常数 1 与第三条面约束的非负组合,所以一张有限证书便覆盖整个三角形。这里没有在三个顶点上碰运气;证书代数地证明了所有点。

在调度问题中,LP/ILP 的未知量可包括调度系数、距离界和 Farkas 乘子;另行设计的模型还可含表示 band 或 fusion/distribution 选择的整数变量。对偶乘子可以直观理解为每条已知域约束在证书中使用多少权重;本章只需要这种证书直觉,不展开通用对偶理论。本章给出的多维有限化采用逐维求解,不把所有维的 residual 选择编码成一个联合 ILP。

Affine form of Farkas lemma

$$ P=\{z\in\mathbb R^d\mid Az+b\ge0\} $$

非空多面体,其中 $A\in\mathbb R^{m\times d}$、$b\in\mathbb R^m$。令

$$ f(z)=c^Tz+d_0 $$

为仿射函数。则

$$ \forall z\in P:\ f(z)\ge0 $$

当且仅当存在常数乘子

$$ \lambda_0\ge0, \qquad \lambda=(\lambda_1,\ldots,\lambda_m)^T\ge0, $$

使以下关于 $z$ 的恒等式成立:

$$ \boxed{ f(z)\equiv\lambda_0+\lambda^T(Az+b) } $$

逐项对齐变量系数和常数项,得到有限条件

$$ \boxed{ c=A^T\lambda, \qquad d_0=\lambda_0+b^T\lambda, \qquad \lambda_0,\lambda\ge0. } $$

$\lambda_0$ 相当于恒真约束 $1\ge0$ 的乘子,不能随意删掉。例如 $P=\mathbb R^d$、$f\equiv1$ 时没有面约束可供组合,但 $\lambda_0=1$ 正好给出证书。

调度中使用这一形式的经典路线可追溯到 Feautrier Part I;多维逐层构造见 Part II。这里采用 $Az+b\ge0$ 号向;若资料改用 $Az\le b$,乘子和常数式必须随之重推,不能机械照抄。

非空、等式和参数条件

应用定理前必须处理以下边界。

  1. 非空性。 若 $P=\varnothing$,命题“对所有 $z\in P$”空真,但上面的非空版本不能直接套用。调度器应先删除空依赖分支,或把空性证书作为独立分支处理。
  2. 闭的非严格线性约束。 普通形式接受 $Az+b\ge0$,不直接接受严格不等式、同余或非线性项。
  3. 等式。 $Ez=e$ 可展开为 $Ez-e\ge0$ 与 $-Ez+e\ge0$,两条各配非负乘子;若保留为等式,其乘子应是自由变量,而不是强行非负。
  4. 参数上下文。 对参数化依赖,令 $z=(x,y,p)$,并把 $C(p)$ 与 source/sink 域、依赖约束一并放入 $Az+b\ge0$。漏掉参数上下文会扩大或改变全称域。
  5. 乘子是常数未知量。 $\lambda$ 可和调度系数一起求解,但不能依赖 $z$;否则出现未知量乘未知量,有限系统不再是这里的线性系统。

整数严格时间与尺度

若调度时间戳已经规定为整数,对 $(x,y)\in\Delta_{S\to T}$,严格先后

$$ \theta_S(x,p)<\theta_T(y,p) $$

等价于把

$$ f(x,y,p)=\theta_T(y,p)-\theta_S(x,p)-1 $$

要求为非负。Farkas 处理的是这个含常数 $-1$ 的仿射式;不能只证明差值 $\ge0$,那只能得到弱满足。

若 LP 阶段允许有理调度系数,则某个合法差值可能是 $1/3>0$。在尚未固定尺度时,$>0$ 与 $\ge1$ 并不等价。可在得到有限个有理系数后用所有分母的公倍数统一放大时间戳,或预先规定归一化的整数系数;只有完成这种尺度约定,才可使用单位间隔形式。

手算示例

从无限实例约束到有限线性系统:完整系数对齐

设 source 实例为 $S(i)$,sink 实例为 $T(j)$。先采用实松弛后的非空依赖多面体

$$ P=\{(i,j)\in\mathbb R^2\mid i\ge0,\ j-i-1\ge0,\ 3-j\ge0\}. $$

取 $z=(i,j)^T$,则

$$ A= \begin{bmatrix} 1&0\\ -1&1\\ 0&-1 \end{bmatrix}, \qquad b= \begin{bmatrix} 0\\-1\\3 \end{bmatrix}, \qquad Az+b\ge0. $$

待求的一维仿射调度是

$$ \theta_S(i)=\alpha_Si+\beta_S, \qquad \theta_T(j)=\alpha_Tj+\beta_T. $$

整数严格先后要求,对 所有 $(i,j)\in P$,

$$ \begin{aligned} f(i,j) &=\theta_T(j)-\theta_S(i)-1\\ &=-\alpha_Si+\alpha_Tj+(\beta_T-\beta_S-1)\ge0. \end{aligned} $$

这是一族随 $(i,j)$ 变化的无限约束。由于 $P$ 非空,affine Farkas 给出有限个乘子,使

$$ \begin{aligned} f(i,j)\equiv{}&\lambda_0 +\lambda_1 i +\lambda_2(j-i-1) +\lambda_3(3-j),\\ &\lambda_0,\lambda_1,\lambda_2,\lambda_3\ge0. \end{aligned} $$

右侧完整展开为

$$ (\lambda_1-\lambda_2)i +(\lambda_2-\lambda_3)j +(\lambda_0-\lambda_2+3\lambda_3). $$

分别对齐 $i$ 系数、$j$ 系数和常数项,得到

$$ \boxed{ \begin{aligned} -\alpha_S&=\lambda_1-\lambda_2,\\ \alpha_T&=\lambda_2-\lambda_3,\\ \beta_T-\beta_S-1 &=\lambda_0-\lambda_2+3\lambda_3,\\ \lambda_0,\lambda_1,\lambda_2,\lambda_3&\ge0. \end{aligned}} $$

左侧原本说“每个依赖实例都合法”,右侧只剩 3 个系数等式和 4 个非负条件。它们对调度未知数 $\alpha_S,\alpha_T,\beta_S,\beta_T$ 与 Farkas 乘子都是线性的,因为 $A,b$ 是依赖多面体的已知系数,乘子没有与调度未知量相乘。

现在完整复算 identity 解:

$$ \alpha_S=\alpha_T=1, \qquad \beta_S=\beta_T=0, $$

并取

$$ \lambda_2=1, \qquad \lambda_0=\lambda_1=\lambda_3=0. $$

三个等式逐条成为

$$ -1=0-1, \qquad 1=1-0, \qquad 0-0-1=0-1+0. $$

即 $-1=-1$、$1=1$、$-1=-1$,且所有乘子非负。代回恒等式得到

$$ f(i,j)=j-i-1, $$

恰好是第二条依赖面约束。常数 $-1$、向量 $b$ 中的 $-1,3$,以及 $\lambda_0$ 都参与常数项对齐;省略其中任何一个都会得到另一套错误系统。

参数化依赖的有限化模式

若依赖分支写成

$$ P_{S\to T} =\{z=(x,y,p)\in\mathbb R^d\mid Az+b\ge0\}, $$

其中各行同时包括 $C(p)$、source/sink 域与依赖约束,而调度差减一写成

$$ f(z)=c(\gamma)^Tz+d_0(\gamma), $$

$\gamma$ 表示全部待求调度系数,那么对每个已确认非空的凸分支引入一组独立乘子并添加

$$ c(\gamma)=A^T\lambda, \qquad d_0(\gamma)=\lambda_0+b^T\lambda, \qquad \lambda_0,\lambda\ge0. $$

这就是量词到有限约束的完整链:

$$ \Delta_{S\to T} \longrightarrow \forall z\in P:\ f(z)\ge0 \longrightarrow \text{Farkas 乘子证书} \longrightarrow \text{有限 LP/ILP 约束}. $$

以上模式每次只要求全称域 $P$ 的约束矩阵 $A,b$ 已知。对多维调度,当前层可令 $f=d_r$,在已知 residual dependence 上证明弱满足;哪些整数实例严格满足 $d_r\ge1$,则要等当前维系数选定后再计算。前层距离为零的实例必须继续约束,不能因本层只证明 $d_r\ge0$ 就丢弃。

多维 residual 的顺序有限化

对一个固定候选调度,第 8 章的

$$ U_r=U_{r-1}\cap\{z\mid d_r(z)=0\} $$

只是集合定义,因为所有 $d_r$ 已知。合成未知调度时,本章明确采用以下顺序算法;对析取关系,步骤中的 Farkas 系统按每个非空凸分支分别建立。

  1. 输入已知 residual。 第 $r$ 轮开始时,$U_{r-1}$ 已有只含程序变量 $z$ 和已知数值系数的表示。首轮 $U_0=\Delta_{S\to T}$ 来自依赖分析;后续各轮的表示来自已固定的前一维。若某个实松弛分支写成

    $$ U_{r-1}=\{z\mid A_{r-1}z+b_{r-1}\ge0\}, $$

    则 $A_{r-1},b_{r-1}$ 在本轮不是求解变量。

  2. 求当前维。 令当前差值为

    $$ d_r(z)=c_r(\gamma_r)^Tz+e_r(\gamma_r), $$

    其中 $\gamma_r$ 收集第 $r$ 维未知调度系数。在已知 $U_{r-1}$ 上对 $d_r\ge0$ 应用 Farkas,得到

    $$ c_r(\gamma_r)=A_{r-1}^T\lambda^{(r)}, \qquad e_r(\gamma_r)=\lambda_0^{(r)}+b_{r-1}^T\lambda^{(r)}. $$

    因为 $A_{r-1},b_{r-1}$ 已知,这些式子对 $\gamma_r,\lambda^{(r)}$ 仍是线性的。调度器在该轮的进展、独立性与性能准则下选择一个解。

  3. 固定当前维并计算新 residual。 固定所有语句的 $\gamma_r$ 后,$d_r$ 成为已知仿射式。整数时间下再计算

    $$ K_r=U_{r-1}\cap\{z\mid d_r(z)\ge1\}, \qquad U_r=U_{r-1}\cap\{z\mid d_r(z)=0\}. $$

    $K_r$ 由本维严格承载;$U_r$ 是下一轮的 residual dependence。若 $U_r$ 为空,构造结束。

  4. 下一维重新建模。 若 $U_r\ne\varnothing$,先把这个已知集合化为所选实松弛、integer hull 或非空分支的有限描述,再为第 $r+1$ 维引入全新的 Farkas 乘子并重复步骤 1–3。

这个“已知 $U_{r-1}$ → 求并固定当前维 → 计算已知 $U_r$ → 下一维重新建模”的次序避免了双线性。若不固定 $\gamma_r$,把 $d_r(\gamma_r,z)=0$ 直接加入下一层前提,则下一层约束矩阵会成为 $A_r(\gamma_r)$。下一次系数对齐含

$$ c_{r+1}(\gamma_{r+1}) =A_r(\gamma_r)^T\lambda^{(r+1)}, $$

右侧出现上一维未知系数 $\gamma_{r,a}$ 与下一层未知乘子 $\lambda_b^{(r+1)}$ 的乘积。无论把等式拆成两条不等式还是使用自由乘子,这种乘积都是双线性的,不是普通 LP/ILP 约束。联合求所有维需要另行给出有界的离散选择、indicator/big-M 或其他经过证明的线性化;本章没有构造这种编码,也不声称上述逐维公式组成一个联合 ILP。

整数语义的三条路径

真实依赖实例属于整数点。设某个凸分支的实描述为 $P\subseteq\mathbb R^d$,实际实例为 $P\cap\mathbb Z^d$。必须明确选择以下路径之一。

路径一:对实松弛使用 Farkas——可靠但仅充分

若证明 $f\ge0$ 对整个 $P$ 成立,它当然对 $P\cap\mathbb Z^d$ 成立,所以结果对整数程序安全。但反向未必成立。

最小反例是

$$ P=[0,\tfrac12], \qquad P\cap\mathbb Z=\{0\}, \qquad f(x)=-x. $$

在唯一整数点 $x=0$ 上,$f(0)=0\ge0$;但在分数点 $x=1/2$ 上,$f=-1/2<0$。因此要求实松弛上非负会排除一个在所有整数实例上合法的候选。除非已知 $P$ 是 integral polyhedron,否则不能把这条路径称为整数精确。

路径二:先取 integer hull——仿射检查的精确路径

定义整数凸包

$$ H=\operatorname{conv}(P\cap\mathbb Z^d). $$

对仿射 $f$,

$$ f\ge0\text{ on }P\cap\mathbb Z^d \iff f\ge0\text{ on }H. $$

正向成立是因为非负半空间是凸集,包含所有整数点就包含它们的凸包;反向由 $P\cap\mathbb Z^d\subseteq H$ 立即得到。若取得

$$ H=\{z\mid A_Hz+b_H\ge0\} $$

的有限有理描述并确认它非空,就可在 $H$ 上应用普通 affine Farkas,精确刻画该整数点集上的仿射非负性。对有理多面体,integer hull 仍是有理多面体;但计算它的 H-representation 及其描述规模本身可能很昂贵。若整数点集为空,也仍须先处理空关系。

路径三:一般 Presburger 集合——不能直接套普通 Farkas

一般 Presburger 关系可以含同余、析取、非凸空洞和尚未消去的整数存在量词,例如

$$ (x\equiv1\pmod3\land x\ge0) \quad\lor\quad (x\equiv2\pmod5\land x\le20). $$

它不是单个 $Az+b\ge0$ 实多面体。普通 Farkas 不理解“只取某些剩余类”,也不编码析取。可选策略是:先分解为有限个非空可处理分支;对同余引入整数变量或按剩余类参数化;计算实际整数集合的凸包并取得 H-representation;或者保留 Presburger 结构,改用 Omega/整数线性算术/量词消去方法。不能删除同余与析取后,假装得到的实松弛仍是原集合的精确表示。

调度优化目标:合法域之上再选择

合法性、可行性与目标函数是三层不同问题

完整逻辑顺序是:

  1. 合法性条件规定每条 source → sink 依赖必须严格词典序向前;
  2. 有限化在选定的实松弛或 integer hull 上,把全称非负条件变为有限线性约束;
  3. LP/ILP 可行域询问是否存在满足这些约束的调度系数和乘子;
  4. 性能目标在合法可行解中按延迟、并行性、同步、通信、局部性、tileability 或系数大小选择候选。

因此,“Farkas 求出了最优调度”不准确;Farkas 只提供非负性的有限证书。“ILP 解可行”也不自动等于程序语义合法;只有当 ILP 完整编码了全部依赖、分支、严格性和整数尺度时,那个可行域才对应所声称的合法域。

为什么会形成 LP 或 ILP

  • 若调度系数、距离界和乘子允许取有理数,所有约束与目标均线性,可形成 LP;求解后还须按既定尺度清分母并复核严格性。
  • 若要求调度系数直接为整数,当前维的有限系统可形成 ILP。Band、fusion/distribution 或跨维承载等离散决策也可进入 ILP,但前提是另行给出有效界和正确的 indicator/big-M/析取线性化;本章没有给出这种联合编码。
  • 参数化最优值可能需要 parametric LP/ILP;优先并行、再最小通信之类层级偏好常用 lexicographic optimization,不能在没有权重界证明时随意折成一个加权和。

Feautrier Part I 的一维路线把因果约束与 latency/delay 等选取准则连接起来,Part II 则递归构造多维时间。Pluto 类方法进一步用整数优化选择独立、可 tile 的超平面,兼顾并行性与局部性;一手工程论文入口见 Pluto 项目/作者资料页与 Pluto+。这些方法的具体目标并不相同,不能统称成同一个算法。

两个都合法但性能不同的调度

仍取逐元素依赖 $P(i)\to C(i)$。

分阶段调度

$$ \Theta_P(i)=(0,i), \qquad \Theta_C(i)=(1,i) $$

与融合调度

$$ \Theta_P(i)=(i,0), \qquad \Theta_C(i)=(i,1) $$

的依赖距离分别是 $(1,0)$ 和 $(0,1)$,所以都合法。后者常缩短 producer–consumer 距离,降低中间数组工作集;前者可能让两个规则阶段分别向量化、批处理或映射到不同设备。合法性可行域必须同时容纳二者,性能目标和机器代价模型才决定选谁。

常见线性化目标包括:引入变量 $L$ 作为依赖距离或延迟的上界并最小化 $L$,让 producer 与 consumer 更接近;优先让更多依赖在较早维被严格承载,以暴露后续 coincident 维;约束 band 内距离分量非负,以获得可置换、可 tile 的结构。每一种都是合法域上的附加选择,不能替代 $\theta_T-\theta_S$ 的因果约束。

编译器用途

  1. 消去全称实例枚举。 对每个非空凸依赖分支建立 Farkas 乘子,将无限多个实例约束变成有限系数等式与非负条件。
  2. 构造多维调度。 每轮只在已知 residual dependence 上建立弱满足约束;求解并固定当前维后计算新的 $U_r$,再为下一维重新建立 Farkas 系统,直到残余为空。
  3. 选择精度路径。 快速保守实现可对实松弛求证;需要整数精确时可计算 integer hull;同余和析取明显时必须分解或调用 Presburger/Omega 能力。
  4. 连接求解器。 连续变量形成 LP;整数系数和离散结构形成 ILP。求解状态“可行”只说明编码过的系统有解,不能补回遗漏的依赖或参数条件。
  5. 实现层级性能目标。 编译器可先最大化并行/承载,再最小化通信或系数,并保留每层目标的优先级语义。
  6. 生成可审计证书。 调度系数与 Farkas 乘子可代回恒等式,逐项检查变量系数、常数项、乘子非负和依赖分支非空性。

常见误区

  1. 漏掉非空条件。 空依赖分支上的全称命题只是空真,不能无条件引用非空版 affine Farkas 表示。
  2. 删掉 $\lambda_0$。 非负常数本身需要恒真生成元;只组合面约束会丢失合法证书。
  3. 只对齐变量系数。 $d_0=\lambda_0+b^T\lambda$ 与变量等式同样必要;调度严格性中的 $-1$ 不能消失。
  4. 混用不等式号向。 本章固定 $Az+b\ge0$;换成 $Az\le b$ 必须重新推导乘子形式。
  5. 给等式只配一个非负乘子。 等式应拆为两个反向不等式,或使用自由乘子。
  6. 让乘子依赖实例变量。 这会产生未知量乘积,不再是当前有限线性系统。
  7. 漏掉参数上下文。 $C(p)$ 必须进入 $z=(x,y,p)$ 的全称域。
  8. 把实松弛称为整数精确。 它总是安全充分条件,却可能因分数点排除整数上合法的候选。
  9. 把 integer hull 和整数点集混为一物。 前者是连续凸集,后者是离散集合;仿射非负性在二者上的等价需要明确论证。
  10. 把一般 Presburger 公式直接交给 Farkas。 同余、析取和整数存在量词必须先分解、参数化、求凸包,或改用整数方法。
  11. 对有理时间无条件使用差至少 1。 单位间隔依赖整数时间戳或清分母后的归一化尺度。
  12. 把 Farkas、LP/ILP 与性能目标混成一步。 Farkas 有限化合法约束,求解器建立可行解,目标函数才作性能选择。
  13. 把含未知 $d_r$ 的 residual 当成下一层已知域。 这样会让下一层 Farkas 乘子乘上上一维调度系数,形成双线性项。本文必须先固定第 $r$ 维并计算已知 $U_r$,再为下一维建模。

练习

练习 EX09-B01|三角形上的仿射非负性(基础)

对本章三角形 $Q$,用 $f(u,v)=5-2u-v$ 判断它是否处处非负。若是,给出 $\lambda_0,\lambda_1,\lambda_2,\lambda_3$;若否,给出反例点。

答案索引: ANS-EX09-B01

练习 EX09-D01|一维 Farkas 系数对齐(推导)

对 $P=\{x\in\mathbb R\mid x\ge1\land4-x\ge0\}$ 和 $f(x)=ax+b$,按 $Az+b\ge0$ 号向写出含 $\lambda_0$ 的恒等式,并完整对齐 $x$ 与常数项。

答案索引: ANS-EX09-D01

练习 EX09-D02|候选调度的直接检查与证书(推导)

在本章 $(i,j)$ 依赖例中检验候选 $\theta_S(i)=0,\theta_T(j)=j$。先直接求严格合法性仿射式 $f=\theta_T-\theta_S-1$,再找一组非负乘子验证有限系统。

答案索引: ANS-EX09-D02

练习 EX09-D03|等式乘子的两种编码(推导)

把约束 $j=i+1$ 分别用两条反向不等式及非负乘子、一个等式及自由乘子表示,说明两种写法如何互相转换。

答案索引: ANS-EX09-D03

练习 EX09-C01|实松弛与 integer hull(综合)

用 $P=[0,1/2]$、$f(x)=-x$ 解释实松弛为何只给充分条件;再求 $H=\operatorname{conv}(P\cap\mathbb Z)$,说明在 $H$ 上检查为何对仿射式精确。

答案索引: ANS-EX09-C01

练习 EX09-C02|同余集合的 Farkas 边界(综合)

给集合 $S=\{x\in\mathbb Z\mid0\le x\le10\land x\equiv1\pmod3\}$ 引入整数变量 $k$ 写成 $x=3k+1$,解释为何不能直接删除同余后在区间 $[0,10]$ 上声称整数精确。

答案索引: ANS-EX09-C02

练习 EX09-C03|合法调度上的性能代理(综合)

为 $P(i)\to C(i)$ 的两个合法调度各设计一个线性性能代理:一个偏好较短依赖距离,一个偏好阶段分离。说明目标与合法约束各自负责什么,并指出必要的归一化或有界性前提。

答案索引: ANS-EX09-C03

练习 EX09-C04|Residual 合成的顺序有限化(综合)

假设一个两维调度第一维只满足 $d_1\ge0$。按“已知 $U_0$ → 求并固定 $d_1$ → 计算 $U_1$ → 为 $d_2$ 重新建模”写出四步输入输出;再说明若不固定 $d_1$,下一层 Farkas 系数对齐中哪两个未知量会相乘。

答案索引: ANS-EX09-C04

练习 EX09-D04|空依赖分支与空真(推导)

检查空多面体 $P=\{x\mid x\ge0\land-x-1\ge0\}$。说明任意 $f$ 的全称非负命题为何空真,以及调度器应如何处理该依赖分支。

答案索引: ANS-EX09-D04

本章小结

  • 对非空 $P=\{z\mid Az+b\ge0\}$,affine Farkas 把 $f\ge0$ 的全称条件等价改写为 $f\equiv\lambda_0+\lambda^T(Az+b)$,其中 $\lambda_0,\lambda\ge0$。
  • 系数对齐必须同时包含 $c=A^T\lambda$ 和 $d_0=\lambda_0+b^T\lambda$;等式需拆成双向不等式或使用自由乘子。
  • 整数严格调度用 $\theta_T-\theta_S-1\ge0$,但单位间隔依赖整数时间或清分母后的尺度归一化。
  • 完整手算把对所有 $(i,j)$ 的无限约束化为三个系数等式和四个乘子非负条件,identity 解逐项复算成立,常数 $-1$ 未被省略。
  • 多维有限化是顺序过程:每轮 residual 已知,求并固定当前维后才计算 $U_r$;直接联合下一层会产生调度系数与 Farkas 乘子的双线性积,本文不提供联合 ILP 编码。
  • 对整数实例有三条明确路径:实松弛给可靠充分条件;integer hull 给仿射检查的精确路径;一般含同余或析取的 Presburger 集合不能直接套普通 Farkas。
  • Farkas 负责有限化,LP/ILP 负责可行性或优化,性能目标负责在合法解中选择;三者不能混为一谈。
  • Feautrier Part I/II 和 Pluto 类方法都以合法性为底线,再分别组织多维时间及并行、同步、局部性与 tileability 的优化。

第 10 章:调度变换与调度树

直觉

第 8–9 章得到的不是一段新的循环文本,而是一个满足依赖约束的执行顺序。本章把常见循环变换统一看成“替换调度”:实例域和语句语义先保持不变,只把原调度 $\Theta$ 换成候选调度 $\Theta'$,然后重新检查每条 source → sink 依赖是否仍严格向前。

这种视角把两个经常混淆的问题拆开:

  1. 语义合法性:变换后的依赖像是否都落在严格词典序的正向区域;
  2. 性能取舍:合法候选是否改善局部性、并行粒度或向量化,又是否增加边界控制、同步、寄存器压力或代码体积。

Fusion、fission、interchange、skewing、wavefront、strip-mining 和 tiling 都不天然合法,也不天然更快。合法性必须针对完整依赖关系证明;性能只能结合目标机器和代价模型判断。

单个 schedule map 很适合陈述“每个实例映到什么时间戳”,但真实优化还要表达语句分支、顺序或无序组合、band、tiling 层次和附加标记。为此,本章还区分 schedule map 与结构化 schedule tree。后者是编译器表示,不是 Presburger 算术新增的逻辑运算。

形式定义

变换后的依赖像与统一合法性判据

对语句 $S$ 的实例 $x\in D_S(p)$,令候选新调度为

$$ \Theta'_S:D_S(p)\to\mathbb Z^k. $$

对依赖 $\Delta_{S\to T}\subseteq D_S\times D_T$,其调度像定义为

$$ \Delta_{\Theta'}= \{(\Theta'_S(x),\Theta'_T(y))\mid(x,y)\in\Delta_{S\to T}\}. $$

按照全文固定的关系复合方向,也可写成

$$ \Delta_{\Theta'} =\Theta'_T\circ\Delta_{S\to T}\circ(\Theta'_S)^{-1}. $$

这里把调度视为关系,所以 $\Theta'$ 即使不是单射,复合仍有定义。令词典序坏集为

$$ B_{\mathrm{lex}} =\{(u,v)\mid\neg(u\mathrel{\mathrm{lex}<}v)\}. $$

候选调度合法当且仅当对所有依赖分支都有

$$ \boxed{\Delta_{\Theta'}\cap B_{\mathrm{lex}}=\varnothing.} $$

等价地,$\Theta'_T(y)-\Theta'_S(x)$ 的第一个非零分量必须为正。若必须保序的两端被映到同一时间戳,差为零,不满足本教程的严格合法性契约;不能把“代码生成器也许碰巧排对”当作证明。

Schedule map 与 schedule tree 不是同一个对象

Schedule map 是从带语句标识的实例域到共同 schedule space 的映射或关系,例如

$$ \{P(i)\mapsto(i,0),\ Q(i)\mapsto(i,1)\}. $$

它直接表达由时间戳词典序诱导的先后,适合计算依赖像。一个扁平 map 可以编码复杂顺序,却不自然保留“这两条语句是 sequence 的两个分支”“这两维组成可置换 band”或“外层是 tile、内层是 tile 内点”这类结构意图。

Schedule tree 则把这些结构显式分层。下面的图使用 isl 的节点术语;它说明一种合法的结构关系,不表示所有调度树都必须包含这些节点。

flowchart TD
    D["domain:全部待调度实例"] --> C["context:AST 生成可假设的参数/外层约束"]
    C --> Seq["sequence:子 filter 按位置先后"]
    Seq --> FP["filter:P 实例"]
    Seq --> FR["filter:其余实例"]
    FP --> Mark["mark:给子树附加信息"]
    Mark --> BP["band:P 的一组调度维"]
    BP --> LP["leaf"]
    FR --> Set["set:子 filter 间次序未指定"]
    Set --> FQ["filter:Q 实例"]
    Set --> FS["filter:S 实例"]
    FQ --> BQ["band:Q 的调度维"]
    FS --> BS["band:S 的调度维"]
    BQ --> LQ["leaf"]
    BS --> LS["leaf"]

图中节点的作用必须逐项区分:

  • domain 描述整棵树适用的域元素,通常位于根;它不是参数上下文。
  • context 是 AST 生成器支持的 schedule-tree 节点,给出可假设成立的参数和外层 band 约束;它不等同于根 domain,也不保证最终一定生成运行时 guard。
  • filter 只把当前子树限制到一个实例子集,本身不施加次序,也不是 AST 的 if 节点。
  • sequence 的孩子是构成当前域分割的 filters,不同孩子按树中位置排序。
  • set 的孩子同样是 filters,但孩子之间允许任意次序;“未指定次序”不等于已经证明可并行。
  • band 保存一组调度维及其属性。一个 band、一个调度维和一层最终 AST for 之间都没有机械一一对应关系。
  • mark 给子树附加任意信息;它不会自动完成优化或并行化。
  • leaf 不再增加次序,也不必只对应一个源码语句。

这些是 isl 0.28 官方手册中 schedule tree 的工具表示语义(访问日期:2026-07-22),不是 Presburger 算术自身的语法节点。树比单个矩阵或扁平 map 更适合表达分支、融合结构、band 属性与 tiling 层次;若用 isl_schedule_get_map 扁平化,得到的是编码相对次序的 schedule map,不应反过来声称树与 map 是同一个对象。

手算示例

Fusion 与 fission:逐元素生产者—消费者

考虑两个分离循环:

for (int i = 0; i < N; ++i)
  P: tmp[i] = f(in[i]);
for (int i = 0; i < N; ++i)
  Q: out[i] = g(tmp[i]);

假设数组不发生额外别名,唯一相关依赖是

$$ \Delta_{P\to Q} =\{P(i)\to Q(i)\mid0\le i<N\}. $$

原来的分阶段调度,也就是 fission/distribution 形态,为

$$ \Theta_P(i)=(0,i),\qquad \Theta_Q(i)=(1,i). $$

依赖像是

$$ (0,i)\to(1,i), $$

距离恒为 $(1,0)$,故坏集为空。融合调度取

$$ \Theta'_P(i)=(i,0),\qquad \Theta'_Q(i)=(i,1), $$

依赖像变成

$$ (i,0)\to(i,1), $$

距离恒为 $(0,1)$,仍严格词典序向前。因此,对这个分离参考程序的完整依赖集,fusion 合法;若从这个基本融合形态再恢复分阶段调度,fission 也合法。

要展示 fission 的非法边界,必须另换一个原本就按融合顺序执行的参考程序,不能把与分阶段原顺序矛盾的边强加给上面的分离程序。考虑沿 state 传递迭代状态的程序:

state[0] = seed;
for (int i = 0; i < N; ++i) {
  P: tmp[i] = f(state[i], in[i]);
  Q: state[i + 1] = g(tmp[i]);
}

每个 tmp[i]state[i+1] 都只写一次;在无额外别名的前提下,循环内相关真依赖恰为

$$ \Delta_{P\to Q} =\{P(i)\to Q(i)\mid0\le i<N\} $$

$$ \Delta_{Q\to P}^{+} =\{Q(i)\to P(i+1)\mid0\le i<N-1\}, $$

前者由 tmp[i] 的写后读产生,后者由 state[i+1] 的写后读产生。这个融合参考程序的原调度

$$ \Theta^F_P(i)=(i,0),\qquad \Theta^F_Q(i)=(i,1). $$

两条依赖的像分别为

$$ (i,0)\to(i,1) $$

$$ (i,1)\to(i+1,0), $$

距离分别为 $(0,1)$ 和 $(1,-1)$,首个非零分量都为正,所以原融合程序合法。现在候选 distribution/fission 调度取

$$ \Theta^D_P(i)=(0,i),\qquad \Theta^D_Q(i)=(1,i). $$

其中 $P(i)\to Q(i)$ 的像为 $(0,i)\to(1,i)$,距离 $(1,0)$;但 $Q(i)\to P(i+1)$ 的像为

$$ (1,i)\to(0,i+1), $$

距离 $(-1,1)$ 的首个非零分量为负,所以这个 distribution/fission 候选非法。两个参考程序的依赖来源和原执行顺序必须分开:第一个分离程序证明 basic fusion 合法,第二个融合程序证明带迭代状态链时 fission 非法。这也说明 fusion/fission 必须检查各自变换基准的完整依赖并集,不能只看语法上能否合并或拆开两个循环。

融合可能缩短 tmp[i] 的复用距离并减少工作集,也可能增加寄存器压力、妨碍两个阶段各自向量化或把资源特征不同的阶段绑在一起。分离也可能更适合批处理或异构映射;这些都不是由合法性自动推出的性能结论。

Interchange:out-of-place 矩阵转置

考虑:

for (int i = 0; i < M; ++i)
  for (int j = 0; j < N; ++j)
    S: T[j][i] = A[i][j];

前提是 $A$ 只读、每个实例写 $T$ 的不同元素,并且 $A$ 与 $T$ 不别名。于是不同 $S(i,j)$ 之间没有 RAW、WAR 或 WAW 依赖:

$$ \Delta_{S\to S}=\varnothing. $$

原调度和交换后的调度分别为

$$ \Theta(i,j)=(i,j),\qquad \Theta'(i,j)=(j,i). $$

二者的依赖像都为空,特别是

$$ \Delta_{\Theta'}=\varnothing, \qquad \Delta_{\Theta'}\cap B_{\mathrm{lex}}=\varnothing. $$

因此这次 interchange 真空合法。证明的关键是先从访问关系和别名假设得到空依赖,而不是把 interchange 当成普遍合法规则。

作为反例,若另一个程序具有

$$ [i,j]\to[i+1,j-1], $$

identity 下距离为 $(1,-1)$,合法;交换后距离为 $(-1,1)$,非法。即使转置例中交换可能让 $T$ 的写入连续,它也可能同时让 $A$ 的读取跨步;缓存布局、向量化和写分配共同决定实际收益。

Skewing 与 wavefront:时间—空间 stencil

$$ D_S(T,N)=\{(t,i)\in\mathbb Z^2 \mid0\le t<T\land1\le i<N-1\}, $$

其中 $T\ge1,N\ge3$。每个下一时刻实例读取前一时刻的三个邻点。统一把 source 写成 $S(t,i)$,依赖分支为

$$ \Delta_\delta =\{S(t,i)\to S(t+1,i+\delta)\mid \delta\in\{-1,0,1\}\land\text{两端均在域内}\}. $$

原调度为

$$ \Theta(t,i)=(t,i). $$

依赖像是

$$ (t,i)\to(t+1,i+\delta), $$

距离分别为 $(1,-1),(1,0),(1,1)$,首分量都为正,故原顺序合法;但负的空间分量使这两维不满足第 8 章给出的可置换 band 非负充分条件。

取覆盖半径的倾斜系数 2:

$$ \Theta_s(t,i)=(t,2t+i). $$

调度像为

$$ (t,2t+i)\to(t+1,2(t+1)+i+\delta), $$

距离是

$$ (1,2+\delta)\in\{(1,1),(1,2),(1,3)\}. $$

每个分量非负且第一分量严格为正,所以 skew 后合法,并形成适合进一步交换或 tiling 的非负结构。交换倾斜后的两个维度,得到 wavefront 调度

$$ \Theta_w(t,i)=(2t+i,t). $$

依赖像为

$$ (2t+i,t)\to(2(t+1)+i+\delta,t+1), $$

距离

$$ (2+\delta,1)\in\{(1,1),(2,1),(3,1)\}. $$

坏集仍为空。第一维 $w=2t+i$ 对每条依赖都严格增加,所以在只存在这三类依赖且处理好边界的前提下,同一 $w$ 上的实例没有彼此依赖,可作为并行 wavefront 候选;不同 $w$ 仍按顺序推进。

若只取 skew 系数 1,$\delta=-1$ 的 wavefront 第一维距离为 0,完整距离 $(0,1)$ 仍合法,但同一 wavefront 内尚有依赖,不能宣布该 wavefront 完全并行。更大的系数也未必更快:它可能增加前沿数量、负载不均和同步开销。

Strip-mining 与 tiling:矩阵乘更新

用 $U(i,j,k)$ 表示矩阵乘中的一次累加:

for (int i = 0; i < M; ++i)
  for (int j = 0; j < N; ++j)
    for (int k = 0; k < K; ++k)
      U: C[i][j] += A[i][k] * B[k][j];

本例暂时保持给定的顺序归约语义,相关依赖为

$$ \Delta_{U\to U} =\{U(i,j,k)\to U(i,j,k+1)\mid0\le k<K-1\}. $$

原调度

$$ \Theta(i,j,k)=(i,j,k) $$

给出依赖像

$$ (i,j,k)\to(i,j,k+1), $$

距离 $(0,0,1)$,合法。

先对 $i$ 以正整数 $B_i$ strip-mine:

$$ \Theta_{sm}(i,j,k)= \left(\left\lfloor\frac{i}{B_i}\right\rfloor, i\bmod B_i,j,k\right). $$

依赖两端的 $i,j$ 相同,因此依赖像距离为

$$ (0,0,0,1), $$

坏集为空。这里的 floor 和 Euclidean mod 是分段准仿射表达,不能伪装成一个普通仿射矩阵。

再对 $i,j$ 做二维 tiling,取 $B_i,B_j\ge1$:

$$ \Theta_{tile}(i,j,k)= \left( \left\lfloor\frac{i}{B_i}\right\rfloor, \left\lfloor\frac{j}{B_j}\right\rfloor, i\bmod B_i, j\bmod B_j, k \right). $$

同一依赖的调度像距离为

$$ (0,0,0,0,1), $$

仍合法。若继续交换 point-loop 或把 $k$ 提到会改变同一 $(i,j)$ 更新顺序的位置,必须重新计算完整依赖像,不能沿用此处结论。

Tiling 常试图增加块内复用,但收益依赖 tile 大小、缓存容量、替换策略、向量化、并行划分和边缘 tile 控制。过大的 tile、冲突失效或复杂边界可能抵消收益。

Reduction:并行化需要额外的代数与实现契约

考虑:

int sum = 0;
for (int i = 0; i < N; ++i)
  S: sum += a[i];

按原始顺序读—改—写语义,精确顺序依赖至少包含

$$ \Delta_{S\to S} =\{S(i)\to S(i+1)\mid0\le i<N-1\}. $$

原调度 $\Theta(i)=i$ 的依赖像为 $i\to i+1$,距离 1,合法。若“并行化”被粗暴地写成常数调度

$$ \Theta_{par}(i)=0, $$

依赖像变成 $0\to0$,与坏集相交,因而在原依赖和原逐步状态语义下非法。把这些实例直接放入 schedule tree 的 set 也不会消除依赖。

真正的并行归约会改变实现结构:每个 worker 先顺序或向量化地更新私有累加器,再按确定的合并树汇总。此时要为新引入的私有更新与合并语句重新建立域、访问和依赖,证明每个输入恰被使用一次,并声明允许的代数重排。

在无溢出的数学整数模型中,加法可结合、可交换;固定宽度无符号整数若语言定义为模加法,也可在模意义下重排。带未定义溢出的有符号 C、会陷阱的算术、浮点舍入、NaN 与异常标志则需要单独契约。归约识别只提供了优化机会,不自动保证逐位结果、异常行为或性能收益不变。

编译器用途

  1. 以统一判据验证变换。 对 fusion/fission、interchange、skew、wavefront、strip-mining、tiling 的每个候选,计算完整依赖像并与词典序坏集求交。
  2. 区分合法性和 profitability。 调度器先排除非法候选,再用复用距离、并行粒度、同步、代码体积与目标机代价模型排序合法候选。
  3. 用 tree 保留结构意图。 sequence/set + filter 表达语句组织,band 表达成组调度维和属性,tiling 可表现为外 tile band 与内 point band,mark 携带后端信息。
  4. 为代码生成保留恢复信息。 非单射、非幺模或含 floor/mod 的调度不能只靠逆矩阵恢复实例;第 11 章会把调度图和原坐标一起扫描。
  5. 谨慎处理归约。 原依赖下的并行候选可能非法;只有在归约代数、私有化、合并顺序和语言数值语义明确后,才能构造新的合法程序。

Feautrier 的 仿射调度 Part IPart II 是合法多维调度的经典来源;Pluto 的工程路线可从项目与作者资料页进入。这里的 schedule-tree 节点语义只依据 isl 官方手册,不把具体工具表示冒充数学定理。

常见误区

  1. 把变换名当成合法性证明。 每个名字都只描述候选结构;证明对象仍是完整 source → sink 依赖像。
  2. 只检查一个代表距离。 Stencil 的三个 $\delta$ 分支、不同语句边和参数边界都要检查。
  3. 把 fusion 与 fission 当成完全对称的语法操作。 在第二个融合状态链程序中,$Q(i)\to P(i+1)$ 与原融合顺序一致,却使分阶段候选非法;不能把这条边归给第一个分离参考程序。
  4. 认为 interchange 总能改善局部性。 它可能改善一个数组的连续访问,同时恶化另一个数组。
  5. 认为 skew 后自然得到完全并行 wavefront。 必须检查每条依赖在 wavefront 维是否严格增加;零距离仍表示同一前沿内有依赖。
  6. 把 floor/mod 写成普通仿射矩阵。 Strip-mining 和 tiling 使用分段准仿射整数表达。
  7. 把 schedule map 与 schedule tree 视为同一对象。 前者是实例到时间的关系,后者还保留分支和 band 结构。
  8. filter 当成 AST if Filter 只限制子树实例集;最终是否出现 if 由扫描和边界决定。
  9. set 当成并行证明。 任意顺序和安全并行是不同命题,还需依赖、同步、归约和资源分析。
  10. 把一个 band 机械对应一个循环。 AST 生成可缩放、消元、分段、合并或引入 guard。
  11. 把 reduction 标签当成逐位等价证明。 数值语义、私有化和合并树都属于正确性契约。
  12. 把合法候选称为必然加速。 代码体积、边界、同步、缓存、向量化和目标机参数都可能改变结果。

练习

练习 EX10-D01|Fusion/fission 的完整依赖像(推导)

仿照第二个融合状态链程序,先初始化 state[0]state[1],再令 $Q(i)$ 写 state[i+2],并把相关边域取为 $0\le i<N-2$,从而产生 $Q(i)\to P(i+2)$。分别计算原融合调度与候选分阶段调度下两类依赖的像和 $\Theta(\mathrm{sink})-\Theta(\mathrm{source})$,判定哪一种合法。

答案索引: ANS-EX10-D01

练习 EX10-C01|Alias 使空依赖证明失效(综合)

令矩阵为 $N\times N$ 方阵,$T$ 与 $A$ 完全别名,使语句成为原地赋值 $S(i,j):A[j][i]=A[i][j]$。在 identity 原始顺序下构造 $i<j$ 时的 source → sink 冲突边,区分 RAW、WAR 与 WAW,并解释为何 out-of-place 例的空依赖证明失效。

答案索引: ANS-EX10-C01

练习 EX10-D02|Stencil skew 与交换(推导)

对距离为 $(1,-2)$、$(1,0)$、$(1,1)$ 的 stencil,求使 $\Theta_s(t,i)=(t,kt+i)$ 两维距离都非负的最小整数 $k$,再判断交换后的第一维是否对三条边都严格为正。

答案索引: ANS-EX10-D02

练习 EX10-B01|Tile/point 时间戳与恢复(基础)

取 $M=5,N=4,B_i=2,B_j=3$,列出二维 tiling 调度下实例 $(i,j)=(4,3)$ 的完整 tile/point 时间戳,并用 Euclidean 商余恢复 $(i,j)$。

答案索引: ANS-EX10-B01

练习 EX10-D03|Tiled 矩阵乘的归约距离(推导)

在矩阵乘例中,把调度改成 $(\lfloor i/B_i\rfloor,\lfloor j/B_j\rfloor,k,i\bmod B_i,j\bmod B_j)$。计算相邻归约依赖的 source-to-sink 距离并判定合法性;再解释为什么合法仍不代表该顺序更快。

答案索引: ANS-EX10-D03

练习 EX10-B02|Schedule tree 结构(基础)

画一棵只含 domainsequence、两个 filter、两个 bandleaf 的小树,表达所有 $P$ 先于所有 $Q$。指出哪个节点施加跨语句次序,哪个节点只筛选实例。

答案索引: ANS-EX10-B02

练习 EX10-C02|浮点归约的反结合例(综合)

sum 使用 IEEE 754 float。给出 $(a+b)+c\ne a+(b+c)$ 的具体可复算数量级例子,并说明为什么依赖意义上合法的私有化归约仍可能不满足逐位结果不变。

答案索引: ANS-EX10-C02

练习 EX10-D04|非单射调度与严格合法性(推导)

对一个第一维时间戳相同的非单射调度,构造两实例间的真实 source → sink 依赖;说明还需要哪一维或哪种有序结构才能满足严格合法性。

答案索引: ANS-EX10-D04

本章小结

  • 调度变换的统一正确性条件是 $\Delta_{\Theta'}\cap B_{\mathrm{lex}}=\varnothing$;方向始终是 source 时间早于 sink 时间。
  • Fusion/fission、interchange、skew/wavefront、strip-mining/tiling 和 reduction 分别用不同程序分析;basic fusion 使用分离参考程序,非法 fission 使用另一个带状态链的融合参考程序,二者不混用依赖来源。
  • Stencil 的 skew 系数 2 把三个距离变成 $(1,1),(1,2),(1,3)$,交换后的 wavefront 距离为 $(1,1),(2,1),(3,1)$;同一前沿是否可并行取决于第一维是否对全部依赖严格增加。
  • Strip-mining 和 tiling 的 floor/mod 是整数准仿射表达;依赖不涉及被重排维并不免除完整复查。
  • 原始顺序归约不能靠常数调度或 set 直接并行;私有化与合并引入了需要重新证明的新程序结构和数值语义契约。
  • Schedule map 直接表达实例到时间的关系,schedule tree 显式表达 domain/context、sequence/set、filter、band 和 mark 等结构;两者严格区分。
  • Schedule tree 是 isl 的工具表示,不是 Presburger 算术本身;filter 不是 AST if,set 不是并行证明,band 也不与最终循环机械一一对应。
  • 合法性只给出语义可行边界,不保证局部性、并行性或运行时间必然改善。

第 11 章:整数扫描与代码生成

直觉

合法调度仍然只是“实例应按什么顺序出现”的数学对象。代码生成还要把这个顺序恢复成有限的 forif 和语句调用,并对所有合法参数保证三件事:

  1. 原域中的每个整数实例都被生成,因而不漏点
  2. 每个原实例只生成一次,因而不重复
  3. 生成顺序遵守变换后调度,并能从生成位置恢复正确的原语句实例和访问下标。

所以代码生成不是“把调度矩阵的每一行抄成一层循环”。它是在参数上下文中扫描变换后调度图的整数点:先按调度时间排序,再恢复原坐标。边界需要投影和消元;整数格点会带来 floor、ceil、min、max、stride、整除 guard 和参数分支。Schedule 维可以被缩放、合并或消去,也可能产生没有原像的洞;最终 AST 循环与 schedule 维没有机械一一对应关系。

本章先给出扫描问题的教学定义,再完整推导三角域、同余域和边缘 tile 三类边界。随后用最小反例说明 Fourier–Motzkin 只对实投影精确,直接用于整数投影会丢失同余。最后把这些数学现象与 isl AST 的对象和节点术语对齐。

形式定义

从调度图定义整数扫描

令参数 $p\in\mathbb Z^q$ 满足上下文 $C(p)$,带语句标识的实例并集记为

$$ D(p)=\biguplus_S D_S(p). $$

给定调度映射 $\Theta$,保留调度时间 $t$ 与原实例 $x$ 的图关系:

$$ G_\Theta(p) =\{(t,x)\mid x\in D(p)\land t=\Theta(x)\}. $$

代码生成的核心任务可表述为:在 $C(p)$ 内,枚举 $G_\Theta(p)$ 的整数点,使 $t$ 按词典序非降;对同一时间戳上互不依赖的实例,使用一个明确的次级顺序或结构化 set 语义;随后从 $(t,x)$ 中取回带语句标识的 $x$,生成对应 user statement。若同一时间戳上存在必须严格保序的依赖,则问题早已是非法调度,不能靠扫描器补救。

保留 $x$ 很重要。只有在调度是一一映射且逆变换适合整数计算时,才可以仅由 $t$ 直接求逆。非幺模、非单射、含 floor/mod 或引入 tile 坐标的调度,都不应被草率地当作普通矩阵换基。Bastoul 的 PACT 2004 作者公开稿通过把新调度维放在原坐标之前并扫描扩展多面体,专门处理一般变换下的实例恢复;这里采用的是对应的教学性图关系,而不声称复现其内部实现。

对固定参数 $p$,令 $E(p)$ 是生成 AST 在该参数下实际发生的动态 user 节点执行事件集合。一个事件至少记作

$$ e=(u,\ell), $$

其中 $u$ 标识静态 AST user 节点及其原语句身份;若同一原语句被版本化到多个 AST 位置,$u$ 还包含该 AST 位置身份。向量 $\ell$ 收集该事件外围各层循环迭代值。只有沿实际控制流到达并执行了 user 节点才形成事件:某次包络循环迭代若 guard 为假,它不产生 user 事件,因而不进入 $E(p)$;同一个外围循环元组若先后执行 $P$ 和 $Q$ 两个 user 节点,则因 $u$ 不同而形成两个可区分事件。

每个 user 表达式携带恢复出的原语句实参。由此定义恢复映射

$$ \rho:E(p)\to\biguplus_S D_S(p), $$

把一次动态 user 执行事件还原成带语句标识的原实例。对生成器的点集正确性,可用一个满射条件和一个唯一性条件概括:

$$ \rho[E(p)]=\biguplus_S D_S(p), $$

$$ \forall [x]_S\in\biguplus_T D_T(p):\quad \left|\rho^{-1}[\{[x]_S\}]\right|=1. $$

第一式给出覆盖,第二式排除同一原实例由多个动态 user 事件重复产生;合起来使 $\rho$ 成为 $E(p)$ 到不交并实例域的双射。执行次序是双射之外的独立条件。 若动态 trace 的先后关系记为 $\prec_E$,则每条 $([x]_S,[y]_T)\in\Delta_{S\to T}$ 都必须令唯一事件 $e_x\in\rho^{-1}[\{[x]_S\}]$、$e_y\in\rho^{-1}[\{[y]_T\}]$ 满足 $e_x\prec_E e_y$,并与 $\Theta_S(x)\mathrel{\mathrm{lex}<}\Theta_T(y)$ 一致。实际 user 节点还必须把 $x$ 正确代回原语句参数与访问下标。

Identity、非幺模时间与 tile 坐标

Identity 基线。

$$ D_N=\{i\in\mathbb Z\mid0\le i<N\}, \qquad \Theta(i)=i. $$

则 $G_\Theta=\{(i,i)\mid0\le i<N\}$,直接得到:

for (int i = 0; i < N; ++i)
  S(i);

非幺模时间。 改取 $\Theta(i)=2i$。精确调度像是

$$ \{t\in\mathbb Z\mid0\le t<2N\land t\equiv0\pmod2\}, $$

而不是整个整数区间 $[0,2N)$。可扫描原坐标,也可显式扫描偶数时间:

for (int t = 0; t < 2 * N; t += 2)
  S(t / 2);  // t 可整除 2

若错误地令 t++ 并无条件调用 S(t / 2),奇数时间没有原像,且 C 的整数除法还会把相邻两个时间映到同一实例,既生成伪点又造成重复。

Tile 坐标。 对正整数 $B$,定义 Euclidean 商余

$$ ii=\left\lfloor\frac{i}{B}\right\rfloor, \qquad r=i-Bii, \qquad0\le r<B. $$

扩展图保留 $(ii,r,i)$ 以及等式 $i=Bii+r$。Euclidean 除法定理保证每个 $i$ 的 $(ii,r)$ 唯一,因此可以按 tile、再按 tile 内位置排序,同时无歧义恢复 $S(i)$。这不是说三维 schedule 必然生成三层循环;等式消元后常只需要 tile loop 和 point loop。

整数边界的规范形式

固定外层变量和参数后,若内层整数变量 $z$ 满足多条有理线性界

$$ z\ge \frac{a_r}{q_r}\quad(q_r>0), \qquad z\le \frac{b_s}{d_s}\quad(d_s>0), $$

则精确整数区间为

$$ \max_r\left\lceil\frac{a_r}{q_r}\right\rceil \le z\le \min_s\left\lfloor\frac{b_s}{d_s}\right\rfloor. $$

max 合并下界,min 合并上界;若下界大于上界,该分支为空,可以表现为外层参数分支或运行时 guard。同余约束不能仅靠区间界恢复,通常还需要 stride、整除 guard 或显式整数商变量。

这里的 floor/ceil 是数学取整。对正除数 3,

$$ \left\lfloor-\frac13\right\rfloor=-1, \qquad \left\lceil-\frac13\right\rceil=0. $$

而 C 的整数 / 对有符号数向 0 截断,-1 / 3 为 0;C 的 % 也不是一般意义下取非负 Euclidean 余数。只在已证明被除数非负时,普通 /% 才可直接充当这些数学运算。否则生成器必须使用语义明确的 floor_divceil_div、Euclidean modulo,或经证明等价的调整公式。

手算示例

三角域:内层上界依赖外层变量

令参数上下文为 $N\ge0$,实例域为

$$ D_N=\{(i,j)\in\mathbb Z^2 \mid0\le i<N\land0\le j\le i\}. $$

采用 identity 调度 $\Theta(i,j)=(i,j)$。先扫描外层 $i$。把 $0\le i<N$ 留作外层边界;固定 $i$ 后,所有含 $j$ 的约束已经是

$$ j\ge0, \qquad j\le i. $$

下界的 max 只有 0,上界的 min 只有 $i$,因此得到:

for (int i = 0; i < N; ++i)
  for (int j = 0; j <= i; ++j)
    S(i, j);

取 $N=4$,原域与循环都枚举

(0,0)
(1,0) (1,1)
(2,0) (2,1) (2,2)
(3,0) (3,1) (3,2) (3,3)

共有 10 个不同点。逐向证明如下:

  • 生成点包含于原域。 外层保证 $0\le i<4$,内层保证 $0\le j\le i$,所以每个生成点属于 $D_4$。
  • 原域包含于生成点。 任取 $(i,j)\in D_4$,其 $i$ 落在外层唯一一次迭代中,其 $j$ 落在该次内层区间 $[0,i]$ 中,所以一定生成,不漏点。
  • 唯一性。 循环变量的一次取值唯一决定 $(i,j)$;两个不同迭代对不可能得到同一坐标,所以不重复。

更一般地,若固定外层后同时得到 $2j\ge i-1$、$3j\ge p$、$j\le i$、$2j\le N-1$,精确界应写成

$$ \max\left( \left\lceil\frac{i-1}{2}\right\rceil, \left\lceil\frac p3\right\rceil \right) \le j\le \min\left( i, \left\lfloor\frac{N-1}{2}\right\rfloor \right). $$

哪一项实际取到 max/min 会随参数和外层变量变化;生成器可以保留 min/max 表达式,也可以分成若干参数/外层条件分支。后者可能简化每个分支的边界,却增加代码体积。

同余域:stride 与 guard

$$ D_N=\{i\in\mathbb Z \mid0\le i<N\land i\equiv1\pmod3\}, \qquad N\ge0. $$

引入整数商 $q$,把同余精确写为

$$ i=1+3q. $$

代入区间约束:

$$ 0\le1+3q<N. $$

左侧给出

$$ q\ge\left\lceil-\frac13\right\rceil=0, $$

右侧因整数严格不等式等价于 $1+3q\le N-1$,得到

$$ q\le\left\lfloor\frac{N-2}{3}\right\rfloor. $$

直接用 $i=1+3q$ 可生成 stride 版本:

for (int i = 1; i < N; i += 3)
  S(i);

也可扫描包络区间并保留 guard:

for (int i = 0; i < N; ++i)
  if (i % 3 == 1)
    S(i);

此 guard 中 $i\ge0$,所以 C % 与所需非负余数一致。若下界允许负数,应改用 Euclidean modulo 判断,或写成“存在整数 $q$ 使 $i=1+3q$”的等价实现,不能未经处理沿用 i % 3 == 1

取 $N=8$:

definition: {1, 4, 7}
stride:     {1, 4, 7}
q=0,1,2:    {1, 4, 7}

不漏点来自:每个满足 $i\equiv1\pmod3$ 的整数都存在 $q\in\mathbb Z$ 使 $i=1+3q$,而区间约束恰把 $q$ 限到 0、1、2。不重复来自:若 $1+3q_1=1+3q_2$,则 $q_1=q_2$。Stride 直接编码了这个单射;guard 版本中每个 $i$ 也只被外层循环访问一次。

边缘 tile:min(N, (ii+1)B) 的来源

为了同时显示左右边缘,令

$$ D=\{i\in\mathbb Z\mid L\le i<N\}, \qquad B\ge1, L<N. $$

以 0 为 tile 原点,定义

$$ ii=\left\lfloor\frac{i}{B}\right\rfloor. $$

包含原域点的第一个和最后一个 tile 编号是

$$ ii_{min}=\left\lfloor\frac LB\right\rfloor, \qquad ii_{max}=\left\lfloor\frac{N-1}{B}\right\rfloor. $$

固定 $ii$ 后,tile 自身给出半开区间

$$ iiB\le i<(ii+1)B, $$

原域给出 $L\le i<N$。两组下界取 max、上界取 min,得到交集

$$ \max(L,iiB)\le i<\min(N,(ii+1)B). $$

因此一般代码为:

for (int ii = floor_div(L, B);
     ii <= floor_div(N - 1, B);
     ++ii)
  for (int i = max(L, ii * B);
       i < min(N, (ii + 1) * B);
       ++i)
    S(i);

右边缘的 min(N, (ii+1)B) 不是经验补丁,而是原域与 tile 区间相交的精确上界;左边缘的 max(L,iiB) 完全对称。

当 $L=0,N>0$ 时,tile 个数为

$$ \left\lfloor\frac{N-1}{B}\right\rfloor+1 =\left\lceil\frac NB\right\rceil, $$

可写成熟悉的形式:

for (int ii = 0; ii < ceil_div(N, B); ++ii)
  for (int i = ii * B;
       i < min(N, (ii + 1) * B);
       ++i)
    S(i);

ceil_div(N,B) 在 $N\ge0,B>0$ 时可实现为 $(N+B-1)/B$,但这个公式可能溢出,也不能无条件推广到负 $N$。一般生成器要使用目标整数类型上经过证明的安全实现。

复算 $L=1,N=8,B=3$:

ii=0: i=1,2
ii=1: i=3,4,5
ii=2: i=6,7

合并得到 $\{1,2,3,4,5,6,7\}$,恰是原域。不漏点:任取原点 $i$,唯一的 $ii=\lfloor i/B\rfloor$ 位于外层范围,且 $i$ 同时满足原区间和该 tile 区间。不重复:不同 tile 的半开区间 $[iiB,(ii+1)B)$ 两两不交,同一 tile 的 point loop 也不重复取值。

Fourier–Motzkin:实投影会丢掉整数同余

Fourier–Motzkin elimination 的基本直觉是:要消去变量 $y$,把给出 $y$ 下界和上界的不等式两两配对,生成只含其余变量的必要约束。对实数线性不等式,这给出精确投影;对整数点,它可能只给出实包络。

最小反例取

$$ P=\{(x,y)\in\mathbb R^2 \mid x-2y\le0\land-x+2y\le0\}. $$

两条不等式合起来就是 $x=2y$。第一条给 $2y\ge x$,第二条给 $2y\le x$。在实数上消去 $y$ 时,上下界配对只产生恒真式 $0\le0$,所以

$$ \operatorname{proj}^{\mathbb R}_x(P)=\mathbb R. $$

但若原变量必须为整数,

$$ \begin{aligned} \operatorname{proj}^{\mathbb Z}_x(P\cap\mathbb Z^2) &=\{x\in\mathbb Z\mid\exists y\in\mathbb Z:x=2y\}\\ &=\{x\in\mathbb Z\mid x\equiv0\pmod2\}. \end{aligned} $$

所有奇数都在实投影中,却没有整数原像。由此不能把 Fourier–Motzkin 说成整数精确消元:floor/ceil 可以把有理上下界收紧到整数区间,但这里没有边界可收紧,同余信息仍需 stride、x % 2 == 0 guard、显式整数商,或 Cooper/Omega 一类整数方法恢复。Cooper 的原文扫描是整数线性算术量词消去的来源;Fourier–Motzkin 的实投影直觉不能替代它。

参数分支、guards 与代码膨胀

扫描多个多面体或多条分段界时,哪一个下界成为 max、哪一个上界成为 min,可能依赖参数。例如

$$ \max(0,P-N)\le i<\min(P,N) $$

在 $P\le N$、$N<P\le2N$、$P>2N$ 等上下文中会简化成不同边界或空域。生成器有三种常见选择:

  1. 保留 max/min 表达式;
  2. 生成参数 if,在每个分支使用更简单的循环;
  3. 扫描较大的包络,再用实例 guard 过滤。

分支越细,循环边界可能越简单,但代码体积和指令缓存压力越大;guard 越多,动态控制开销可能越高。Quilleré、Rajopadhye 与 Wilde 的参数化多面体循环生成论文讨论了高效嵌套循环生成及代码大小与控制开销的权衡;Bastoul 的方法继续面向变换后多面体的扫描和控制简化。二者都不保证任意输入上产生全局最短、无 guard 或最快的代码。

编译器用途

isl 中 schedule、context 与 AST 节点的角色

以下工具术语依据 isl 官方手册 0.28及其 PDF,访问日期均为 2026-07-22

  • Schedule tree(isl_schedule 是结构化调度,包含 domain、band、filter、sequence/set、context、mark 等输入节点。树中最靠近根、同时涉及两个实例并把它们区分开的节点递归决定相对次序。
  • Schedule map(isl_union_map 把域实例映到 schedule space。交给 AST 生成器时,域元素按对应像的词典序访问;它是扁平关系表示,不等同于 schedule tree。
  • AST build context 可由 isl_ast_build_from_context(set) 建立;该集合通常只含参数约束。从 isl_schedule 生成 AST 时,手册要求这里是参数集。它与 schedule tree 中的 context 节点相关但不是同一个对象:前者是 AST build 的初始上下文,后者位于树内并可约束参数和外层 band 维。
  • AST for 节点 表达生成的循环及其迭代器、初始化、条件、步进和主体。一个 for 不保证对应一个原循环或一个 schedule 维。
  • AST if 节点 表达运行时条件分支,可能来自参数分段、边界或 guard;schedule-tree filter 本身不是 AST if
  • AST user 节点 是访问某个域元素时产生的表达式语句,通常携带原语句标识和恢复后的实例实参。它不是原语句体语义保持的自动证明。
  • AST 还可包含 blockmark 节点;mark 可对应调度树标记,但标记的含义仍由使用者约定。

手册给出的稳定入口包括 isl_ast_build_node_from_scheduleisl_ast_build_node_from_schedule_map。AST 表达式支持 minmax、向负无穷取整的正除数商 fdiv_q 以及余数/整除条件,因此分段边界、floor division 和 guards 都是精确整数扫描的正常结果,不是生成失败。

对 schedule tree 输入,AST 生成选项可附在 band;isl_schedule_node_band_tile 会在原 band 与其子树之间创建 point-loop band,使外层表达 tile、内层表达 tile 内点。即便如此,最终 AST 仍由扫描、消元、边界简化和选项共同决定;不能宣布“两个 band 必定原样打印成两层同名 C 循环”。

从数学对象到可执行代码的检查链

编译器至少要完成以下链条:

  1. 在参数上下文内确定带语句标识的整数实例域;
  2. 取得已经由第 8–10 章证明合法的 schedule map 或 schedule tree;
  3. 扫描调度图或等价的扩展整数集合,生成精确上下界、stride、参数分支和 guards;
  4. 证明生成迭代与原实例之间覆盖且唯一;
  5. 在 user 节点恢复原语句实参和数组访问下标;
  6. 检查生成顺序保持全部 source → sink 依赖,并检查目标语言整数除法、溢出和数值语义。

Quilleré–Rajopadhye–Wilde 与 Bastoul 支持的是 polyhedral scanning 和控制结构生成路线;isl 手册支持的是工具对象与 API 语义。它们都不替代依赖合法性、点集双射和原语句体替换正确性的证明。进一步的语义保持视角可参阅 Verified Code Generation for the Polyhedral Model

常见误区

  1. 把代码生成说成逆调度矩阵。 非幺模、非单射、floor/mod 和 tile 坐标都可能没有普通整数逆矩阵。
  2. 扫描调度像的包络而忽略洞。 $t=2i$ 的像只有偶数;扫描所有整数时间会生成无原像点。
  3. 认为 schedule 维与 AST 循环一一对应。 消元、缩放、分段、合并和 guard 都会改变 AST 形状。
  4. 把 $E(p)$ 定义为所有循环迭代元组。 Guard 为假的包络迭代没有 user 事件;同一循环元组又可能执行多个不同 user。事件必须包含 user/语句身份并只收集实际到达者。
  5. 只证明生成点属于原域。 这只能排除伪点,还必须证明每个原点被动态 user 事件覆盖且只被覆盖一次。
  6. 把点集双射当成次序证明。 双射只证明不漏不重;source → sink 的动态执行先后必须另查。
  7. 把数学 floor 当作 C / 对负数,向负无穷取整与向 0 截断不同。
  8. 把 C % 当作 Euclidean modulo。 负被除数时余数符号和剩余类判断必须另行处理。
  9. 用 floor/ceil 代替同余。 它们收紧区间界,却不能从 $x=2y$ 的实投影中恢复“$x$ 为偶数”。
  10. 把 Fourier–Motzkin 称为整数精确消元。 它对实线性投影精确;整数投影还要保留整除和同余。
  11. 漏掉边缘 tile 的 min/max 完整 tile 上界会在最后一块生成越界点,负的左边缘也需要 max
  12. 无条件使用 (N+B-1)/B 公式依赖符号条件且可能溢出;一般情形需语义明确的 ceil division。
  13. 把 schedule-tree filter 当作 AST if 两者属于输入调度结构和输出控制结构的不同层次。
  14. 把 AST 生成成功当成语义证明。 仍需合法调度、点集不漏不重、实例恢复和语句体替换正确。
  15. 认为分支越细代码越好。 参数分段可能降低循环控制,却造成代码膨胀和指令缓存压力。

练习

练习 EX11-B01|三角域 identity 扫描(基础)

对 $D=\{(i,j)\mid0\le i<N\land i\le j<N\}$ 推导 identity 扫描循环。取 $N=4$ 列出全部点,并分别证明不漏点和不重复。

答案索引: ANS-EX11-B01

练习 EX11-D01|负数同余域的 stride(推导)

对 $D=\{i\mid-5\le i<5\land i\equiv1\pmod3\}$,用 Euclidean 商变量推导 stride 的起点与终点;再说明 C 表达式 i % 3 == 1 会漏掉哪些负数点。

答案索引: ANS-EX11-D01

练习 EX11-B02|非幺模调度像扫描(基础)

对调度 $t=3i$、$0\le i<4$,列出精确调度像。分别写出 stride 扫描和包络加整除 guard 的代码,并说明如何恢复 $i$。

答案索引: ANS-EX11-B02

练习 EX11-D02|负左边界的 tile floor(推导)

取 $L=-2,N=5,B=3$,用数学 floor 计算 $ii_{min},ii_{max}$,逐 tile 列出点。再用 C 向 0 截断的 L/B 比较,指出错误的外层起点。

答案索引: ANS-EX11-D02

练习 EX11-D03|二维边缘 tile 枚举(推导)

对二维矩形 $0\le i<M\land0\le j<N$ 做 $2\times3$ tiling。取 $M=3,N=5$,列出四个边缘/完整 tile 的点,并说明 tile 编号与点内坐标为何共同唯一确定原点。

答案索引: ANS-EX11-D03

练习 EX11-D04|Ceil/max 与 floor 边界(推导)

从约束 $3j\ge i-2$、$2j\le N+i$、$j\ge0$ 推导 $j$ 的 ceil/max 下界与 floor 上界;写出内层为空时需要的条件。

答案索引: ANS-EX11-D04

练习 EX11-C01|Fourier–Motzkin 的整数缺口(综合)

对整数等式 $x=3y+1$ 做实 Fourier–Motzkin 消元,比较实投影与整数投影;给出正确的 stride 或 Euclidean guard。

答案索引: ANS-EX11-C01

练习 EX11-B03|Schedule-tree context 与 AST build context(基础)

解释 schedule-tree context 节点与 isl_ast_build_from_context(set) 的区别,并各给出一个它们可以携带的约束例子。

答案索引: ANS-EX11-B03

练习 EX11-C02|参数分段与代码体积(综合)

设计一个参数界,使保留 min/max 只需一份循环,而完全分段需要至少三个参数分支(允许其中包含空域分支)。给出分支覆盖证明,并比较动态分支、代码体积和可优化性的取舍。

答案索引: ANS-EX11-C02

练习 EX11-C03|动态 user 事件的四项审计(综合)

考虑 for ell in L 的包络循环;当 $g(\ell)$ 为真时,依次执行两个静态 user 节点 $u_P(\operatorname{args}_P(\ell))$、$u_Q(\operatorname{args}_Q(\ell))$。写动态事件键,并给出覆盖、唯一、依赖次序、实参恢复四项符号审计条件;说明 guard 为假与同一 $\ell$ 上两个 user 的处理。

答案索引: ANS-EX11-C03

本章小结

  • 代码生成是在参数上下文中按调度时间扫描 $G_\Theta=\{(t,x)\mid x\in D,t=\Theta(x)\}$ 的整数点,并恢复原语句实例;它不是机械地把 schedule 维翻译成 AST 循环。
  • $E(p)$ 只含实际到达的动态 user 执行事件,事件键含 user/语句身份和外围循环值;它通过 $\rho$ 与不交并实例域双射,而 source → sink 动态次序是双射之外的独立条件。
  • Identity 调度可直接扫描原坐标;$t=2i$ 的非幺模调度像含偶数洞结构;tile 坐标依靠 Euclidean 商余唯一恢复原点。
  • 三角域产生依赖外层变量的界;$i\equiv1\pmod3$ 产生 stride 或 guard;边缘 tile 由原域与 tile 区间相交产生 max(L,iiB)min(N,(ii+1)B)
  • 三个小参数枚举分别验证了三角域 $N=4$、同余域 $N=8$ 和 tile $L=1,N=8,B=3$ 的不漏点与不重复。
  • Floor/ceil 是数学取整,不能对负值无条件使用 C 的向 0 截断 / 和非 Euclidean %min/max、stride、guards 与参数分支都可能是精确扫描所必需。
  • Fourier–Motzkin 对实线性投影精确,却会在整数投影 $x=2y$ 中丢掉偶数同余;它不是整数精确消元。
  • isl 的 schedule tree、schedule map、AST build context 与 for/if/user 节点属于不同层次;官方手册不保证 schedule 维与 AST 循环一一对应。
  • Quilleré、Bastoul 与 isl 分别支撑多面体循环生成、变换后扫描和工具表示语义;它们都不自动证明输入调度合法或最终程序值语义保持。

第 12 章:二维 stencil 的端到端推导

直觉

前十一章分别建立了公式、集合、关系、依赖、调度、变换与扫描。本章把它们串成一条可回溯链:每一步只消费前一步已经证明的对象,直到生成代码;若某一步使用近似或额外前提,后面的结论也只能在同一边界内成立。

贯穿程序是一个时间—空间 stencil:

for (int t = 1; t <= T; ++t)
  for (int i = 1; i < N - 1; ++i)
    S: A[t][i] = A[t - 1][i - 1]
                 + A[t - 1][i]
                 + A[t - 1][i + 1];

完整调用链分为九个阶段:

阶段输入输出或检查
1C 源程序与语言前提SCoP、顺序执行语义、完整二维数组模型
2循环边界与参数参数上下文和整数迭代域
3赋值语句三条读访问、一个写访问及精确 live-in
4域、访问、原始顺序三支精确 RAW,方向恒为 source → sink
5RAW 与原调度identity 合法性和逐时间层并行事实
6矩形 tiling 目标skew 坐标及其非负依赖距离
7skew 域与固定 tile 大小矩形 tile、tile wavefront 和并行边界
8合法调度图精确 min/max 边界、AST 形状与伪 C
9生成迭代和工具对象不漏不重、依赖保序及 isl/Omega 表示边界

一个重要结论会贯穿后半章:原 identity 调度已经合法,skew 不是程序正确性的必要条件。本章选择 skew,是为了让所选的轴对齐矩形 tile 具有易证明的非负 tile 依赖,并进一步形成 tile 级 wavefront。

形式定义

阶段 1:程序、内存与语言前提

令参数向量为 $p=(T,N)$,参数上下文为

$$ C(p):T\ge1\land N\ge3. $$

本章的正确性结论还依赖下列显式前提。

  1. $A$ 是完整二维存储,至少覆盖 $A[u,v]$ 的 $0\le u\le T$、$0\le v<N$。不同坐标表示不同抽象内存位置,也不存在破坏这一模型的指针别名。
  2. 原程序按 $(t,i)$ 严格词典序执行;每个实例先完成右侧三个读,再写 $A[t,i]$。三个只读 site 之间无需人为规定顺序。
  3. 本章只重排不同语句实例,不改变单个 $S$ 的表达式、括号、数值类型或异常行为。索引、tile 乘积和边界算术还须在目标整数类型中不溢出;伪 C 用数学整数解释这些控制表达式。
  4. 数组不是 volatile,语句体没有隐藏 I/O、原子操作、同步或其他未建模副作用。

这里不能把 $A$ 静默替换成两行滚动缓冲。滚动缓冲让不同逻辑时间行复用物理地址,会引入新的 WAR/WAW 以及可能不同的 RAW;必须对新访问关系重新分析。

阶段 2–3:参数域、读写关系与 live-in

唯一静态语句 $S$ 的命名实例域为

$$ D_S(p)=\{[t,i]_S\in\mathbb Z^2 \mid1\le t\le T\land1\le i\le N-2\}. $$

参数 $(T,N)$ 受 $C(p)$ 约束,但不是实例 tuple 的坐标。令 $M_A$ 为数组 $A$ 的抽象内存空间,三个读访问和一个写访问均按 instance → memory 定向:

$$ \begin{aligned} R_{-1}&=\{[t,i]_S\to A[u,v]\mid[t,i]_S\in D_S \land u=t-1\land v=i-1\}:D_S\to M_A,\\ R_0&=\{[t,i]_S\to A[u,v]\mid[t,i]_S\in D_S \land u=t-1\land v=i\}:D_S\to M_A,\\ R_{+1}&=\{[t,i]_S\to A[u,v]\mid[t,i]_S\in D_S \land u=t-1\land v=i+1\}:D_S\to M_A,\\ W&=\{[t,i]_S\to A[u,v]\mid[t,i]_S\in D_S \land u=t\land v=i\}:D_S\to M_A. \end{aligned} $$

下标 $(-1,0,+1)$ 是相对于 sink 实例空间坐标 $i$ 的读取偏移,不是 source-to-sink 距离;转为 source 坐标后,空间距离的符号会反转。

域内写只覆盖 $1\le u\le T,\ 1\le v\le N-2$。没有域内 producer 的读所需的 live-in 内存位置,去重后恰为

$$ L_{in} =\{A[0,v]\mid0\le v\le N-1\} \cup \{A[u,0],A[u,N-1]\mid1\le u\le T-1\}. $$

当 $T=1$ 时第二项为空。尤其不能只初始化第 0 行:当 $T>1$ 时,时间行 $1,\ldots,T-1$ 的左右边界也会被后继时间层读取。$A[T,0]$ 和 $A[T,N-1]$ 不被本程序读取,因而不属于本次计算的 live-in。

阶段 4:从同址候选到精确 RAW

对任一读 site $R_\delta$,先沿 source 写实例 → 内存 → sink 读实例构造

$$ \operatorname{Same}_\delta =R_\delta^{-1}\circ W:D_S\to D_S. $$

在 isl 的方向中,这对应 W.apply_range(R_delta.reverse())。随后与原始顺序相交,并对每个 sink 读选择此前最后写。本例中每个域内地址 $A[t,i]$ 恰写一次,所以通过同址和原始顺序过滤的域内写就是唯一 last writer;没有中间同址写需要删除。精确 RAW 因而有三支:

$$ \begin{aligned} \Delta_{-1} &=\{[\tau,j]_S\to[\tau+1,j+1]_S \mid1\le\tau\le T-1\land1\le j\le N-3\},\\ \Delta_0 &=\{[\tau,j]_S\to[\tau+1,j]_S \mid1\le\tau\le T-1\land1\le j\le N-2\},\\ \Delta_{+1} &=\{[\tau,j]_S\to[\tau+1,j-1]_S \mid1\le\tau\le T-1\land2\le j\le N-2\}. \end{aligned} $$

每个有序对的第一元都是 producer/source,第二元都是 consumer/sink。以 sink 坐标重写时,它们分别是

$$ \begin{aligned} [t-1,i-1]_S&\to[t,i]_S &&\text{其中 }2\le t\le T, 2\le i\le N-2,\\ [t-1,i]_S&\to[t,i]_S &&\text{其中 }2\le t\le T, 1\le i\le N-2,\\ [t-1,i+1]_S&\to[t,i]_S &&\text{其中 }2\le t\le T, 1\le i\le N-3. \end{aligned} $$

第一时间层和两侧缺失的 producer 正好由 $L_{\mathrm{in}}$ 解释。本模型中每个内部位置只写一次,故没有域内 WAW;所有对这些位置的读都在其写之后,故没有另加的跨实例 WAR。本章后续合法性输入就是

$$ \Delta_{RAW}=\Delta_{-1}\cup\Delta_0\cup\Delta_{+1}. $$

最后写语义的经典来源是 Feautrier 的 Dataflow Analysis of Array and Scalar References;此处“唯一写使候选直接成为精确 RAW”是针对当前访问关系的推导,不是一般程序的捷径。整数同址和判空可参考 Pugh 的 Omega Test

阶段 5–6:原调度与 skew 调度

原调度为

$$ \Theta_{id}(t,i)=(t,i). $$

调度差始终按 sink 减 source 计算。三支 RAW 的 identity 距离依次是

$$ (1,1),\qquad(1,0),\qquad(1,-1). $$

三者第一个非零分量都是 $+1$,故全都严格词典序向前。特别地,$(1,-1)$ 合法;词典序不要求每一维都非负。外层 $t$ 已严格承载所有依赖,所以保持时间层顺序并在每层结束后同步时,同一固定 $t$ 的不同 $i$ 没有彼此依赖,可以并行。

为了构造本章选择的矩形 tiling,定义 skew 坐标

$$ x=t,\qquad y=t+i,\qquad \Theta_{sk}(t,i)=(x,y)=(t,t+i). $$

三支距离变为

$$ (1,2),\qquad(1,1),\qquad(1,0). $$

它们逐分量非负,并且第一分量严格为正。这一更强性质使 $(x,y)$ 可作为本例的可置换 band,并让每个点依赖经过 floor 分块后具有非减 tile 坐标。skew 的目的正是服务这一 tile 形状与 wavefront 组织;identity 本身已经合法。

阶段 7:矩形 tile 与 tile wavefront

在 skew 坐标中,原域等价于斜带

$$ 1\le x\le T, \qquad x+1\le y\le x+N-2. $$

令 $B_x\ge1,\ B_y\ge1$ 是编译期固定的正整数 tile 大小。定义 Euclidean 商余坐标

$$ \begin{aligned} q_x&=\left\lfloor\frac{x-1}{B_x}\right\rfloor, &r_x&=(x-1)-B_x q_x,&0\le r_x<B_x,\\ q_y&=\left\lfloor\frac{y-2}{B_y}\right\rfloor, &r_y&=(y-2)-B_yq_y,&0\le r_y<B_y. \end{aligned} $$

以偏移 $x-1$ 和 $y-2$ 为 tile 原点,使所有有效 tile 编号非负。定义 tile wavefront

$$ w=q_x+q_y $$

及完整调度

$$ \boxed{ \Theta_{\mathrm{wave}}(t,i)=(w,q_x,r_x,r_y). } $$

合法性分两种情形证明。skew 后每条点依赖都有 $\Delta x=1$、$\Delta y\in\{0,1,2\}$。floor 对非减整数输入单调,因此

$$ \Delta q_x\ge0, \qquad \Delta q_y\ge0. $$

  • 若依赖跨 tile,至少一个 tile 坐标严格增加,所以 $\Delta w=\Delta q_x+\Delta q_y\ge1$,由第一维严格承载。
  • 若依赖留在同一 tile,则 $\Delta w=\Delta q_x=0$,且 $x$ 增加 1 而没有跨越 $q_x$ 边界,所以 $\Delta r_x=1$,由第三维严格承载。

于是每条 source → sink RAW 在 $\Theta_{\mathrm{wave}}$ 下都严格向前。进一步,固定同一 $w$ 的两个不同 tile 不可能存在依赖:若有依赖,$(q_x,q_y)$ 均非减;它们的和又不变,只能推出两坐标都不变,即其实是同一个 tile,矛盾。因此可以并行的是“同一 wavefront 上的不同 tile”,不是同一 wavefront 内任意点,也不是 tile 内的 $t$ 或 $y$ 循环。不同 $w$ 之间仍有 RAW,必须在波次之间完成同步。

矩形 tiling 和 wavefront 调度仍属于合法调度的选择,不能推出必然加速。收益取决于 tile 大小、缓存复用、并行粒度、负载均衡与屏障开销。仿射调度与变换的经典路线见 Feautrier Part IPart II;本节的固定候选已直接逐支验证,无需把性能目标冒充合法性证明。

手算示例

$T=3,N=6$:十二个实例与二十条 RAW 全枚举

此时每个时间层的空间坐标都是 $i=1,2,3,4$,所以域恰有 12 个实例:

$$ D_S(3,6)=\{(t,i)\mid t\in\{1,2,3\}, i\in\{1,2,3,4\}\}. $$

三支 source → sink 依赖完整列为:

读 site$t=1\to2$$t=2\to3$数量
i-1(1,1)->(2,2), (1,2)->(2,3), (1,3)->(2,4)(2,1)->(3,2), (2,2)->(3,3), (2,3)->(3,4)6
$i$(1,1)->(2,1), (1,2)->(2,2), (1,3)->(2,3), (1,4)->(2,4)(2,1)->(3,1), (2,2)->(3,2), (2,3)->(3,3), (2,4)->(3,4)8
i+1(1,2)->(2,1), (1,3)->(2,2), (1,4)->(2,3)(2,2)->(3,1), (2,3)->(3,2), (2,4)->(3,3)6

合计 $6+8+6=20$ 条,所有 source 的时间坐标都比 sink 小 1。该参数下 live-in 是第 0 行的六个位置,加上

$$ A[1,0],A[1,5],A[2,0],A[2,5], $$

共 10 个不同位置。边界位置与 $t=1$ 的读不会被错误接到一个不存在的域内 producer。

逐支代入 identity 与 skew

i-1 读支为例,source → sink 是

$$ (\tau,j)\to(\tau+1,j+1). $$

identity 差为

$$ (\tau+1,j+1)-(\tau,j)=(1,1), $$

skew 差为

$$ (\tau+1,\tau+1+j+1)-(\tau,\tau+j)=(1,2). $$

同理,$i$ 读支给 $(1,0)\mapsto(1,1)$,i+1 读支给 $(1,-1)\mapsto(1,0)$。这一步同时核对了常见符号错误:读取 i-1 对应的 source-to-sink 空间距离是 $+1$,读取 i+1 对应的是 $-1$。

$B_x=2,B_y=3$:tile 分组与 wavefront

继续取 $T=3,N=6$。由

$$ q_x=\left\lfloor\frac{t-1}{2}\right\rfloor, \qquad q_y=\left\lfloor\frac{t+i-2}{3}\right\rfloor $$

得到唯一分组:

$(q_x,q_y)$$w$原坐标 $(t,i)$点数
$(0,0)$0(1,1), (1,2), (1,3), (2,1), (2,2)5
$(0,1)$1(1,4), (2,3), (2,4)3
$(1,0)$1(3,1)1
$(1,1)$2(3,2), (3,3), (3,4)3

四组共 $5+3+1+3=12$ 点,没有漏点或重复。$w=1$ 上有两个不同 tile $(0,1)$ 与 $(1,0)$;逐条检查前述 20 条 RAW,没有一条连接这两个 tile,因此它们可并行。tile $(0,0)$ 到 $w=1$ 以及 $w=1$ 到 tile $(1,1)$ 仍有依赖,所以 $w=0,1,2$ 必须按序完成。

阶段 8:从斜域和 tile 交得到精确 min/max

全局 tile 上界是

$$ Q_x=\left\lfloor\frac{T-1}{B_x}\right\rfloor, \qquad Q_y=\left\lfloor\frac{T+N-4}{B_y}\right\rfloor. $$

因此

$$ 0\le w\le Q_x+Q_y. $$

固定 $w$ 后,合法 tile 坐标满足

$$ \max(0,w-Q_y)\le q_x\le\min(Q_x,w), \qquad q_y=w-q_x. $$

固定 $(q_x,q_y)$ 后,$x=t$ 必须同时属于原时间域和 $x$-tile:

$$ t_{lo}=\max(1,1+B_x q_x), \qquad t_{hi}=\min(T,B_x(q_x+1)). $$

再固定 $t$,$y=t+i$ 必须同时属于斜域和 $y$-tile:

$$ y_{lo}=\max(t+1,2+B_yq_y), \qquad y_{hi}=\min(t+N-2,1+B_y(q_y+1)). $$

只有 $y_{lo}\le y_{hi}$ 时该 tile 在当前时间行有点;for (y = y_lo; y <= y_hi; ++y) 会自然跳过空区间。还原 $i=y-t$ 后,第一组界给 $i\ge1$,第二组给 $i\le N-2$。四个 max/min 项分别来自原域与矩形 tile 的交,不是补丁:删掉任一项都会在斜带或边缘 tile 处漏点或越界。

扫描斜域到循环 AST 的经典路线可参阅 Quilleré、Rajopadhye 与 Wilde 的多面体扫描工作和 Bastoul 的作者公开稿。本节公式是对当前域的直接消元;引用不替代下面的不漏不重证明。

阶段 8:生成后的教学性伪 C

下面代码按 $(w,q_x,x,y)$ 的等价词典序扫描实现 $\Theta_{\mathrm{wave}}$。在固定 tile 内,$(x,y)$ 与 $(r_x,r_y)$ 只相差由 tile 坐标确定的常量,所以顺序一致。

// Preconditions:
//   T >= 1, N >= 3; Bx >= 1, By >= 1 are compile-time constants.
//   A is the full two-dimensional array described above; no harmful aliasing.
//   All index and boundary arithmetic below is representable without overflow.
// Live-ins:
//   A[0][0..N-1] and A[1..T-1][0], A[1..T-1][N-1].
int Qx = (T - 1) / Bx;          // numerator is nonnegative
int Qy = (T + N - 4) / By;      // numerator is nonnegative

for (int w = 0; w <= Qx + Qy; ++w) {
  int qx_lo = max(0, w - Qy);
  int qx_hi = min(Qx, w);

  // Only distinct tiles on this fixed wavefront have been proved independent.
  // The implicit end-of-loop barrier is required before advancing to w + 1.
  #pragma omp parallel for schedule(static)
  for (int qx = qx_lo; qx <= qx_hi; ++qx) {
    int qy = w - qx;
    int t_lo = max(1, 1 + qx * Bx);
    int t_hi = min(T, (qx + 1) * Bx);

    for (int t = t_lo; t <= t_hi; ++t) {
      int y_lo = max(t + 1, 2 + qy * By);
      int y_hi = min(t + N - 2, 1 + (qy + 1) * By);

      for (int y = y_lo; y <= y_hi; ++y) {
        int i = y - t;
        A[t][i] = A[t - 1][i - 1]
                    + A[t - 1][i]
                    + A[t - 1][i + 1];
      }
    }
  } // implicit OpenMP barrier: wavefront w is complete here
}

若不使用 OpenMP,删除 pragma 后代码仍按合法顺序串行执行。若使用 OpenMP,必须同时满足本章证明的完整二维 $A$、无有害别名、仅有三支 RAW、语句体无隐藏副作用等前提;不得添加 nowait 而又不提供等价屏障,也不得把 pragma 下移到 tile 内的 $t$ 或 $y$ 循环。平台还必须支持在当前上下文合法使用 OpenMP worksharing;这段代码只标出经依赖证明允许的位置,不声称完成线程数、调度策略和异常传播等工程配置。

阶段 9:点集双射与依赖保序

生成点不会越出原域。 代码中的 $t$ 同时满足 $1\le t\le T$ 和所属 $x$-tile 的区间;$y$ 同时满足 $t+1\le y\le t+N-2$ 和所属 $y$-tile 的区间。因此 $i=y-t$ 满足 $1\le i\le N-2$,每次执行都对应 $D_S$ 中的实例。

原域点不会遗漏。 任取 $(t,i)\in D_S$,令 $x=t,y=t+i$。Euclidean 除法唯一给出

$$ q_x=\left\lfloor\frac{x-1}{B_x}\right\rfloor, \qquad q_y=\left\lfloor\frac{y-2}{B_y}\right\rfloor, \qquad w=q_x+q_y. $$

这些值落入外层范围,而 $(t,y)$ 同时满足相应 tile 区间与斜域区间,所以循环一定生成该点。

原域点不会重复。 Euclidean 商余使每个 $(x,y)$ 的 $(q_x,r_x,q_y,r_y)$ 唯一,$w$ 又由 $(q_x,q_y)$ 唯一决定;每层单位步长循环也不重复取值。因此一个原实例只对应一次生成迭代。

生成顺序保持依赖。 对跨 tile RAW,wavefront 坐标严格增加;对 tile 内 RAW,$r_x$ 严格增加。故每条 source → sink 都在 sink 执行前完成。OpenMP 只并行同一 $w$ 的不同 tile,波次末屏障恢复跨 $w$ 的先后。

四项合起来给出本例的语义链:生成迭代与原实例一一对应,实例实参 $i=y-t$ 恢复正确,且所有精确 RAW 保序。由于语句体原样保留且没有其他可观察副作用,变换保持本模型内的值语义。若换成滚动缓冲、可能别名的指针或新增语句,这份证明的访问与依赖前提失效,必须重建模型。

isl 可解析片段

下列每一段都是可交给相应 isl set/map 或 union set/map 读取接口的字符串;$S$ 与 $A$ 是 tuple 名。它们只描述数学对象,不是一个完整绑定程序。

[T,N] -> { [] : T >= 1 and N >= 3 }

[T,N] -> { S[t,i] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }

[T,N] -> { S[t,i] -> A[t-1,i-1] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }
[T,N] -> { S[t,i] -> A[t-1,i] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }
[T,N] -> { S[t,i] -> A[t-1,i+1] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }
[T,N] -> { S[t,i] -> A[t,i] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }

[T,N] -> { S[t,i] -> [t,i] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }
[T,N] -> { S[t,i] -> [t,t+i] :
  T >= 1 and N >= 3 and 1 <= t <= T and 1 <= i <= N-2 }

三支已经求得的精确 RAW 可组成一个 union map:

[T,N] -> {
  S[ts,is] -> S[ts+1,is+1] :
    T >= 1 and N >= 3 and 1 <= ts <= T-1 and 1 <= is <= N-3;
  S[ts,is] -> S[ts+1,is] :
    T >= 1 and N >= 3 and 1 <= ts <= T-1 and 1 <= is <= N-2;
  S[ts,is] -> S[ts+1,is-1] :
    T >= 1 and N >= 3 and 1 <= ts <= T-1 and 2 <= is <= N-2
}

这里的 transformed schedule 是可解析的 skew map;上述 RAW 是分析结果。仅把 domain、access 与 schedule 字符串放在一起,不会自动完成 last-write 选择,实际程序还要调用相应 flow/dependence API。对象和 API 语义以 isl 官方手册 为准,不能由这些片段反推所有绑定具有相同命令行语法。

Tiling 与 Omega 风格伪表示

下面第一段明确是教学性 tiling 伪表示,不承诺可直接输入:若 $(B_x,B_y)$ 是运行时符号参数,Bx*qxBy*qy 是变量乘变量,符号除数的 floor 也不是普通 Presburger 线性项。实际 isl tiling 应把 tile size 固定为字面正整数,或通过具体版本的 schedule-tree/band tiling API 构造。

Skew: S[t,i] -> [x=t, y=t+i]
Tile: [x,y] -> [qx=floor((x-1)/Bx), qy=floor((y-2)/By),
                 rx=(x-1) mod Bx, ry=(y-2) mod By]
Wavefront:
  S[t,i] -> [floor((t-1)/Bx) + floor((t+i-2)/By),
             floor((t-1)/Bx),
             (t-1) mod Bx,
             (t+i-2) mod By]

下面第二段是Omega 风格伪表示,不是已验证可运行脚本。Omega Calculator 及后继/封装的方言、声明和对象接口并不完全统一,使用前必须适配目标工具;数组标签由关系变量名承担。

symbolic T, N;
D := {[t,i] : T >= 1 && N >= 3 && 1 <= t && t <= T
                  && 1 <= i && i <= N-2};
Rminus := {[t,i] -> [u,v] : [t,i] in D && u = t-1 && v = i-1};
Rzero  := {[t,i] -> [u,v] : [t,i] in D && u = t-1 && v = i};
Rplus  := {[t,i] -> [u,v] : [t,i] in D && u = t-1 && v = i+1};
W      := {[t,i] -> [u,v] : [t,i] in D && u = t   && v = i};
Identity := {[t,i] -> [t,i] : [t,i] in D};
Skew     := {[t,i] -> [t,t+i] : [t,i] in D};

DeltaMinus := {[ts,is] -> [ts+1,is+1] : 1 <= ts && ts <= T-1
                                             && 1 <= is && is <= N-3};
DeltaZero  := {[ts,is] -> [ts+1,is]   : 1 <= ts && ts <= T-1
                                             && 1 <= is && is <= N-2};
DeltaPlus  := {[ts,is] -> [ts+1,is-1] : 1 <= ts && ts <= T-1
                                             && 2 <= is && is <= N-2};

编译器用途

  1. 建立可审计流水线。 前端提取参数上下文、域、访问和原始顺序;依赖分析得到精确 RAW;调度器只在这些边上选择合法候选;AST 生成器再扫描调度图。
  2. 定位近似来源。 若别名分析保守、访问非仿射或 flow 只取同址候选,后续调度和并行性也只能保守;生成出代码不会提高上游模型精度。
  3. 分开合法性和收益。 identity 已合法且能逐时间层并行;skew/tiling 是为了不同的局部性与 tile 并行形状,是否更快必须测量。
  4. 验证并行位置。 本例唯一证明的 tile 级位置是固定 $w$ 下的不同 tile;屏障、完整二维存储和无别名都是证明的一部分。
  5. 审计 AST。 除了查看循环边界,还要检查每个原实例恰生成一次、i=y-t 恢复正确、三支 source → sink RAW 均向前。
  6. 区分工具输入。 核心域、访问、identity/skew 和 RAW 给出 isl 可解析字符串;符号 tile size 与 Omega 文本明确停留在伪表示层。

常见误区

  1. 把读偏移当依赖距离。 i-1 读支的 source-to-sink 空间距离是 $+1$,i+1 读支才是 $-1$。
  2. 把依赖写成 sink → source。 三支关系的第一元始终是 producer,调度差始终是 sink 减 source。
  3. 遗漏 source 域与 live-in。 $t=1$ 没有域内 producer;左右边界还分别让两条邻点分支缺失。
  4. 只初始化第 0 行。 当 $T>1$ 时,中间时间行的左右边界也是 live-in。
  5. 把 $(1,-1)$ 判成非法。 identity 的时间维已经严格承载该边。
  6. 声称合法性必须 skew。 identity 已合法;skew 只服务本章选择的矩形 tiling 与 wavefront。
  7. 把同一 wavefront 全部点无条件并行。 只证明了相同 $w$ 的不同 tile 无依赖;tile 内仍按 $(t,y)$ 顺序执行。
  8. 去掉波次屏障。 不同 $w$ 之间存在 RAW;nowait 需要另一个等价完成机制,不能直接删除同步。
  9. 漏掉边缘 min/max tile 矩形必须与时间范围和斜带的两条边同时相交。
  10. 把符号 tile 大小当普通 Presburger 输入。 运行时 $B_x q_x$ 是变量乘变量;工具 tiling 要固定大小或使用专门 API。
  11. 把完整二维 $A$ 换成滚动缓冲仍沿用证明。 地址复用改变 WAR/WAW/RAW,必须重分析。
  12. 把 AST 生成成功当语义证明。 仍须证明不漏、不重、实例恢复和依赖保序。
  13. 照抄工具风格文本。 isl 片段按对象解析,Omega 与符号 tiling 段明确只是伪表示;方言边界不能省略。

练习

练习 EX12-B01|小规模域、RAW 与 live-in(基础)

取 $T=2,N=5$,枚举域、三支精确 RAW 和去重后的 live-in 位置;分别核对每支关系的 source/sink 边界。

答案索引: ANS-EX12-B01

练习 EX12-D01|一般 skew 的距离与下界(推导)

对一般 skew $\Theta_k(t,i)=(t,kt+i)$,统一计算 $\Theta_k(\mathrm{sink})-\Theta_k(\mathrm{source})$ 的三支距离,给出使第二分量全非负的最小整数 $k$,并说明 $k=0$ 为何仍保持词典序合法。

答案索引: ANS-EX12-D01

练习 EX12-C01|Tile、wavefront 与点数全枚举(综合)

取 $T=4,N=5,B_x=3,B_y=2$,按定义列出所有非空 tile、wavefront 和点数,检查同一 wavefront 的不同 tile 之间是否存在 RAW,并证明点集不漏不重。

答案索引: ANS-EX12-C01

练习 EX12-D02|精确 y 边界与删项反例(推导)

从 $x+1\le y\le x+N-2$ 与一个固定 $y$-tile 的闭区间重新推导 $y_lo$、$y_hi$;分别删去两个 max 候选与两个 min 候选中的一项,并各给出越界、错 tile 或重复点反例。

答案索引: ANS-EX12-D02

练习 EX12-C02|滚动缓冲的新访问与潜在 hazard(综合)

把物理存储改成 A[t % 2][i]。写出新的 instance → memory 读写关系,并指出会出现哪些潜在 source → sink WAR/WAW;不要沿用本章的并行结论,直到完成新的精确依赖分析。

答案索引: ANS-EX12-C02

本章小结

  • 从 C 到生成代码的九阶段链是:程序前提、参数/域、访问/live-in、精确 RAW、identity、skew、tile/wavefront、AST/伪 C、语义与工具审计。
  • 域为 $1\le t\le T,\ 1\le i\le N-2$;完整二维 $A$ 的精确域内依赖只有三支 RAW,方向均为 source → sink。
  • $T=3,N=6$ 时共有 12 个实例和 $6+8+6=20$ 条 RAW;第 0 行与中间时间层左右边界共同构成 live-in。
  • identity 距离为 $(1,1),(1,0),(1,-1)$,已经合法;skew $(t,t+i)$ 把它们变成逐分量非负的 $(1,2),(1,1),(1,0)$,只为本章的矩形 tiling 目标服务。
  • $\Theta_{\mathrm{wave}}=(q_x+q_y,q_x,r_x,r_y)$ 合法;同一 wavefront 的不同 tile 可以并行,tile 内仍保持顺序,不同波次之间必须有屏障。
  • 精确代码边界来自斜域与 tile 的交:时间使用 max/min,空间使用 max(t+1,...)min(t+N-2,...);它们同时处理边缘 tile。
  • Euclidean tile 分解给出不漏不重,调度距离证明给出依赖保序;二者与正确实例恢复共同构成生成代码的语义检查。
  • isl 核心片段可按集合/映射对象解析;符号 tile size 和 Omega 文本是明确标注的伪表示。滚动缓冲、别名或新语句都会改变证明前提,必须重新分析。

附录:练习答案、符号速查与延伸阅读

本附录按稳定练习 ID 给出可核对答案。依赖关系始终按 source → sink 读取,访问关系始终按 instance → memory 读取;调度距离统一取

$$ d=\Theta(\mathrm{sink})-\Theta(\mathrm{source}). $$

参考答案:第 1 章

参考答案 EX01-B01|矩形域枚举与计数

$D_{\mathrm{rect}}(2,3)$ 中 $i=0,1$,$j=0,1,2$,所以点集为

$$ \{(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)\}. $$

在 $N,M\ge0$ 下,每个 $i$ 对应 $M$ 个 $j$,共有 $NM$ 个整数点;若任一尺寸为 0,公式同样给出 0。

参考答案 EX01-D01|三角域计数与语言边界

$D_{\mathrm{tri}}(5)$ 的点为

(0,0)
(1,0) (1,1)
(2,0) (2,1) (2,2)
(3,0) (3,1) (3,2) (3,3)
(4,0) (4,1) (4,2) (4,3) (4,4)

点数是 $1+2+3+4+5=15$。一般地,

$$ \sum_{i=0}^{N-1}(i+1)=\frac{N(N+1)}2. $$

右式是分析者在元层面总结点数的闭式,不是定义域的 Presburger 公式。域公式仍只有 $0\le i<N$、$0\le j\le i$ 等线性约束;把 $N(N+1)$ 放进待判定公式才会引入变量乘变量。

参考答案 EX01-B02|仿射下标判定

  • A[2*i+N] 是仿射访问:2 是固定系数,$N$ 是参数。
  • A[i+j] 是仿射访问:下标是两个实例坐标的线性和。
  • A[i*j] 不是仿射访问:它含两个一般变量的乘积。
  • A[index[i]] 不能仅由 $i$ 和参数精确写成经典仿射访问:物理地址取决于运行时数组值。

参考答案 EX01-C01|参数化斜三角域

取参数上下文

$$ C(N,M):N\ge0\land M\ge0, $$

语句域为

$$ D_S=\{[i,j]_S\mid0\le i<N\land i\le j<M\}. $$

若 $N>M$,域通常不为空;只是 $i\ge M$ 的外层迭代没有内层点。非空实例实际满足 $0\le i<M$,点数为

$$ \sum_{i=0}^{M-1}(M-i)=\frac{M(M+1)}2. $$

只有 $M=0$ 时整个域为空。

参考答案:第 2 章

参考答案 EX02-B01|同余的量词形式与自由变量

$$ x\equiv2\pmod5 \iff\exists k\in\mathbb Z:\ x=5k+2. $$

$k$ 被量词绑定,故自由变量集合为 $\operatorname{FV}=\{x\}$。模数 5 是固定常数。

参考答案 EX02-D01|Presburger 可定义性判定

  • $x=4y-N$ 可定义:4 是固定系数,$N$ 只线性出现。
  • $x=Ny$ 一般不可定义:$N$ 与 $y$ 都是变量。
  • $x=y+z$ 可定义。
  • $x=|y|$ 可写成有限析取

$$ (y\ge0\land x=y)\lor(y\le0\land x=-y). $$

$y=0$ 时两支重叠不改变定义的关系。

参考答案 EX02-D02|固定步长循环建模

存在计数器形式为

$$ \{i\in\mathbb Z\mid\exists k\in\mathbb Z:\ k\ge0\land i=2+4k\land i\le20\}. $$

等价同余形式为

$$ \{i\in\mathbb Z\mid2\le i\le20\land i\equiv2\pmod4\}. $$

$k=0,1,2,3,4$ 分别给出 $\{2,6,10,14,18\}$;$k=5$ 得 22,越过上界。

参考答案 EX02-B02|整数版与自然数版真值

方程 $2x+1=0$ 的唯一有理解是 $x=-1/2$,不是整数。因此它在 $\mathbb Z$ 上为假,在 $\mathbb N$ 上也为假。这道题答案唯一,却不能区分两个论域;例如 $\exists x:x+1=0$ 才会在 $\mathbb Z$ 上为真(见证 $-1$)、在 $\mathbb N$ 上为假。

参考答案 EX02-C01|析取域的参数边界

  • $N=0$ 时,$0\le i<0$ 与 $0\le i<0$ 两支都空,结果为空集。
  • $N=2$ 时,第一支给 $\{0,1\}$,第二支给 $\{4,5\}$,结果为 $\{0,1,4,5\}$。

整数 2、3 没有任一分支见证,不能以凸包区间 $[0,5]$ 代替该析取集合。

参考答案:第 3 章

参考答案 EX03-D01|偶数区间的量词消去

从 $c$ 向上的最小偶数在 $c$ 偶时为 $c$,在 $c$ 奇时为 $c+1$。所以量词自由式可写为

$$ (c\equiv0\pmod2\land c\le d) \lor (c\equiv1\pmod2\land c+1\le d). $$

整数同余按 Euclidean 剩余类解释,因此该式对负 $c$ 也成立。

参考答案 EX03-D02|带正下界的三角投影

$$ \exists j:\ 1\le j\le i\land0\le i<N \iff1\le i<N. $$

正向由 $1\le j\le i$ 得 $i\ge1$;反向对任意 $1\le i<N$ 取见证 $j=1$。它与下界 $j\ge0$ 的普通三角域投影不同。

参考答案 EX03-B01|仿射像与同余类

$$ \exists x\in\mathbb Z:\ z=4x+1 \iff z\equiv1\pmod4. $$

它没有 $z\ge1$ 的下界,例如 $x=-1$ 给 $z=-3$。反过来,条件 $z\ge1$ 会错误加入 2、3、4 等非目标剩余类。

参考答案 EX03-C01|析取投影构造

$$ X=\{(i,j)\in\mathbb Z^2\mid (0\le i\le1\land j=0) \lor(4\le i\le5\land j=1)\}. $$

第一支以 $j=0$ 为见证,第二支以 $j=1$ 为见证,所以

$$ \operatorname{proj}_i(X)=\{0,1\}\cup\{4,5\}. $$

整数 2、3 在任一分支都没有 $j$ 见证,故投影仍是两个分离区间。

参考答案 EX03-B02|查询种类辨析

  1. 固定 $N=N_0$ 后,$\exists i:\varphi(i,N_0)$ 是可满足性查询。
  2. 令 $p$ 收集自由参数、$C(p)$ 为参数上下文,则完整查询是 $$ \forall p:\ C(p)\Rightarrow \forall i:\bigl(\varphi(i,p)\Rightarrow\psi(i,p)\bigr). $$ 这是相对于参数上下文的有效性或全称蕴含查询;等价地,可检查 $C(p)\land\varphi(i,p)\land\neg\psi(i,p)$ 是否不可满足。若参数已固定为某个合法值,就只闭包 $i$。
  3. 求 $\exists j:\varphi(i,j)$ 的无 $j$ 公式,是投影,也就是存在量词消去。

若第 1 项不固定 $N$,其结果是保留参数 $N$ 的可行条件,本质上同样是把 $i$ 投影掉;因此“可满足性”和“投影”取决于哪些变量被固定、哪些被保留。

参考答案:第 4 章

参考答案 EX04-B01|Relation 的 domain/range/inverse/image

对 $R=\{i\to j\mid0\le i<8\land j=3i+2\}$,

$$ \begin{aligned} \operatorname{domain}(R)&=\{i\mid0\le i<8\},\\ \operatorname{range}(R)&=\{j\mid2\le j\le23\land j\equiv2\pmod3\},\\ R^{-1}&=\{j\to i\mid0\le i<8\land j=3i+2\}. \end{aligned} $$

偶数输入子集为 $\{0,2,4,6\}$,其像为 $\{2,8,14,20\}$。逆关系若写成除法形式,必须保留 $j-2$ 可被 3 整除的条件。

参考答案 EX04-D01|奇偶三角域投影

对 $N\ge1$,任取 $0\le i<N$,选 $j=i$ 即满足 $i\le j<N$ 和同奇偶,故 $i$ 投影为 $[0,N)\cap\mathbb Z$。任取 $0\le j<N$,同样选 $i=j$,故 $j$ 投影也相同。

$N=0$ 时原集及两投影均空;$N=1$ 时原集只有 $(0,0)$,两投影均为 $\{0\}$。

参考答案 EX04-D02|三关系复合与 isl 调用顺序

类型链为 $X\xrightarrow{A}Y\xrightarrow{B}Z\xrightarrow{C}W$,所以

$$ (C\circ B\circ A)(x,w) \iff\exists y\in Y\,\exists z\in Z:\ A(x,y)\land B(y,z)\land C(z,w). $$

对应 isl 调用为

A.apply_range(B).apply_range(C)

第一步得到 $B\circ A:X\to Z$,第二步得到 $C\circ B\circ A:X\to W$。

参考答案 EX04-D03|Euclidean floor 与 modulo 展开

Floor 图可写为

$$ q=\left\lfloor\frac{i-4}{5}\right\rfloor \iff5q\le i-4<5(q+1). $$

当 $i=-2$ 时,$i-4=-6$,唯一商是 $q=-2$,因为 $-10\le-6<-5$。Euclidean 余数图为

$$ \exists k\in\mathbb Z:\ i=5k+r\land0\le r<5. $$

当 $i=-2$ 时取 $k=-1,r=3$,即 $-2=5(-1)+3$。这与 C 对负数的向 0 截断除法不同。

参考答案 EX04-C01|访问复合的类型与方向

$W_S:D_S\to M$,$R_T^{-1}:M\to D_T$,所以

$$ R_T^{-1}\circ W_S:D_S\to D_T. $$

它先从 source 写实例走到内存,再沿读访问逆关系走到 sink 读实例,是 $S\to T$ 同址候选;isl 写作 W_S.apply_range(R_T.reverse())

反式 $W_S^{-1}\circ R_T:D_T\to D_S$ 从 $T$ 走回 $S$,方向相反。二者都只是同址候选;精确 RAW 还需原始事件顺序与 last-write 条件。

参考答案:第 5 章

参考答案 EX05-B01|同余类的线性集表示

在 $\mathbb N$ 上,所求集合为

$$ L(2;5)=\{2+5n\mid n\in\mathbb N\}. $$

对应 Presburger 公式是

$$ x\ge0\land\exists n\in\mathbb N:\ x=2+5n, $$

等价地可写成 $x\ge0\land x\equiv2\pmod5$。

参考答案 EX05-D01|二维生成元枚举与成员见证

一般点为

$$ (x,y)=(0,1)+n_1(2,0)+n_2(0,3)=(2n_1,1+3n_2). $$

在 $n_1+n_2\le3$ 下:

$$ \begin{array}{c|l} n_1+n_2&\text{点}\\ \hline 0&(0,1)\\ 1&(2,1),(0,4)\\ 2&(4,1),(2,4),(0,7)\\ 3&(6,1),(4,4),(2,7),(0,10) \end{array} $$

共 10 个互异点。回到不带截断的完整线性集,$(4,7)$ 有见证 $(n_1,n_2)=(2,2)$,所以属于;$(3,7)$ 不属于,因为第一坐标恒为偶数,不可能满足 $2n_1=3$。

参考答案 EX05-D02|从整数到自然数的差编码

令 $z=u-v$,其中 $u,v\in\mathbb N$。不等式变为

$$ u-v\le-2\iff u+2\le v. $$

同余的整数商也要差编码。写 $q=q_+-q_-$,$q_+,q_-\in\mathbb N$,则

$$ u-v=1+3(q_+-q_-) \iff u+3q_-=v+1+3q_+. $$

令 $E(u,v)$ 表示差编码后的自然数关系。仅把 $u,v$ 保留为自由变量时,完整公式为

$$ E(u,v)\iff u,v\in\mathbb N\land \exists q_+,q_-\in\mathbb N: \bigl(u+2\le v\land u+3q_-=v+1+3q_+\bigr). $$

参考答案 EX05-C01|$\mathbb Z^2$ 的有限半线性分解

定义

$$ L_{\mathbb Z}(b;p_1,p_2) =\{b+n_1p_1+n_2p_2\mid n_1,n_2\in\mathbb N\}. $$

$$ \begin{aligned} L_{++}&=L_{\mathbb Z}((0,0);(1,0),(0,1)),\\ L_{-+}&=L_{\mathbb Z}((-1,0);(-1,0),(0,1)),\\ L_{+-}&=L_{\mathbb Z}((0,-1);(1,0),(0,-1)),\\ L_{--}&=L_{\mathbb Z}((-1,-1);(-1,0),(0,-1)). \end{aligned} $$

四支分别覆盖 $x,y\ge0$、$x\le-1,y\ge0$、$x\ge0,y\le-1$、$x,y\le-1$,其并恰为 $\mathbb Z^2$。允许周期向量含负坐标;要求非负的是系数 $n_r$。

参考答案 EX05-C02|四类对象与表示成本

这里区分:单个凸多面体格点集 $P\cap\mathbb Z^d$、有限个此类集合的并、一般 Presburger/半线性集;连续多面体 $P$ 本身不放入离散包含链。

对象单个 $P\cap\mathbb Z^d$有限并Presburger/半线性理由
$\{0,2,4,6\}$单个一维凸区间若含 0、2,也含 1;四个单点之并可表示
$\{2n\mid n\in\mathbb N\}$无穷多个奇数孔洞不能由有限个一维区间或射线持续排除
固定 $N$ 的 $T_N$它是一个有理三角形的全部格点
题设两个矩形的整数点并任一含 $(1,0)$、$(3,0)$ 的凸集也含被排除的 $(2,0)$

固定 $N$ 的三角域若逐点写成零周期半线性并,需要 $\Theta(N^2)$ 个分支,而多面体不等式仍为常数规模;偶数集则用一个周期生成元很紧凑,却不能用有限个普通凸分支表示。因此集合类包含不保持表示成本。

参考答案 EX05-C03|单个同余类不是单凸多面体格点集

设 $m\ge2$、$0\le r<m$。反设一维凸多面体 $P$ 满足

$$ P\cap\mathbb Z=\{r+km\mid k\in\mathbb N\}. $$

右侧含相邻类内点 $r+km$ 与 $r+(k+1)m$。凸性迫使两点间整段属于 $P$,特别是整数 $r+km+1\in P\cap\mathbb Z$。但 $m\ge2$ 时该点不与 $r$ 模 $m$ 同余,矛盾。

参考答案:第 6 章

参考答案 EX06-B01|仿射读写访问建模

类型和对象为

$$ \begin{aligned} C&=\{N\in\mathbb Z\mid N\ge0\},\\ D_S&=\{S[i]\mid0\le i<N\},\\ R_S&=\{S[i]\to A[a]\mid a=i\}:D_S\to M_A,\\ W_S&=\{S[i]\to B[b]\mid b=2i+1\}:D_S\to M_B,\\ \Theta_S&=\{S[i]\to[i]\}:D_S\to\mathbb Z. \end{aligned} $$

参数 $N$ 只出现在上下文和域界中,不是实例 tuple 坐标;两条访问均按 instance → memory 读取。

参考答案 EX06-B02|三角写域建模与枚举

以 $S(i,j)$ 写 $X[i,j]$ 为例:

$$ \begin{aligned} C&=\{N\in\mathbb Z\mid N\ge0\},\\ D_S&=\{S[i,j]\mid0\le j\le i<N\},\\ W_S&=\{S[i,j]\to X[a,b]\mid a=i\land b=j\},\\ \Theta_S&=\{S[i,j]\to[i,j]\}. \end{aligned} $$

$N=3$ 时实例为

$$ S[0,0],S[1,0],S[1,1],S[2,0],S[2,1],S[2,2], $$

共 6 个。

参考答案 EX06-D01|位移消费者的域与读关系

消费者只在安全内点执行,所以

$$ \begin{aligned} D_T&=\{T[j]\mid1\le j<N\},\\ R_T&=\{T[j]\to B[b]\mid b=j-1\}:D_T\to M_B. \end{aligned} $$

当 $N\ge2$ 时,$j=1$ 读 $B[0]$,$j=N-1$ 读 $B[N-2]$,故地址范围为 $0\le b<N-1$;当 $N=1$ 时,消费者域与地址集均为空。题面选择缩域语义,因此不需要假设外部 B[-1] 边界值。

参考答案 EX06-C01|矩阵乘初始化与同维时间戳

设参数 $M,N,K\ge0$,初始化与更新使用不同 tuple:

$$ \begin{aligned} D_I&=\{I[i,j]\mid0\le i<M\land0\le j<N\},\\ W_I&=\{I[i,j]\to C[a,b]\mid a=i\land b=j\},\\ \Theta_I(i,j)&=(i,j,-1),\\ D_U&=\{U[i,j,k]\mid0\le i<M\land0\le j<N\land0\le k<K\},\\ R_U^A&=\{U[i,j,k]\to A[a,c]\mid a=i\land c=k\},\\ R_U^B&=\{U[i,j,k]\to B[c,b]\mid c=k\land b=j\},\\ R_U^C=W_U^C&=\{U[i,j,k]\to C[a,b]\mid a=i\land b=j\},\\ \Theta_U(i,j,k)&=(i,j,k). \end{aligned} $$

固定 $(i,j)$ 时,$(i,j,-1)\mathrel{\mathrm{lex}<}(i,j,0)$,所以初始化严格早于第一次更新。也可把初始化末维设为 0、更新末维设为 $k+1$。

参考答案 EX06-B03|间接访问的建模边界

A[B[i]] 的物理下标是运行时读取的数据值 $B[i]$,不是 $i,N$ 的固定系数仿射式。经典静态仿射模型不能精确写出这一访问。可保留为不可解释访问、借助别名或值域分析构造保守过近似,或用运行时检查选择特化路径;直接改写成 A[i] 会改变程序语义。

参考答案:第 7 章

参考答案 EX07-B01|两语句 shift 的精确 RAW

域和访问为

$$ \begin{aligned} D_P&=\{P[i]\mid0\le i<N\},&W_P&=\{P[i]\to A[a]\mid a=i\},\\ D_Q&=\{Q[j]\mid1\le j<N\},&R_Q&=\{Q[j]\to A[a]\mid a=j-1\}. \end{aligned} $$

同址候选为

$$ R_Q^{-1}\circ W_P =\{P[i]\to Q[j]\mid i=j-1\} =\{P[i]\to Q[i+1]\mid0\le i<N-1\}. $$

原程序先执行全部 $P$,再执行全部 $Q$,故每个 source $P[i]$ 早于 sink $Q[i+1]$;两者之间没有其他地址 $A[i]$ 的写,所以 source 是 last write。上式即精确 RAW。

参考答案 EX07-D01|删除覆盖写后的 RAW 重算

原例在同一地址上有 $S[i]\prec U[i]\prec T[i]$,其中 $S,U$ 写、$T$ 读。原候选含 $S[i]\to T[i]$ 与 $U[i]\to T[i]$;前一支被中间写 $U[i]$ 覆盖,精确 RAW 只留 $U[i]\to T[i]$。

删除 $U$ 后,从新访问重建候选只剩 $S[i]\to T[i]$,中间写集合为空,故

$$ \operatorname{Covered}=\varnothing, \qquad \Delta_{\mathrm{RAW}}=\{S[i]\to T[i]\}. $$

因此必须重算,不能只从旧精确关系中删除含 $U$ 的边。

参考答案 EX07-D02|四次连续写的精确 WAW 链

设对每个 $i$,四个同址写满足

$$ P[i]\prec Q[i]\prec R[i]\prec Z[i]. $$

有序同址候选有 $P\to Q,P\to R,P\to Z,Q\to R,Q\to Z,R\to Z$ 六支。按 next-write 只保留 source 后第一次同址写,精确 WAW 为

$$ \{P[i]\to Q[i]\}:D_P\to D_Q \;\cup\; \{Q[i]\to R[i]\}:D_Q\to D_R \;\cup\; \{R[i]\to Z[i]\}:D_R\to D_Z. $$

其余三支都越过了更早的同址写。

参考答案 EX07-D03|模 3 排除伪冲突

同址要求

$$ 3i=3j+1\iff3(i-j)=1. $$

左边模 3 为 0,右边模 3 为 1,因此没有整数解,source $S$ 到 sink $T$ 的 RAW 候选和精确 RAW 都为空。若只用实地址区间包络,$[0,3N-3]$ 与 $[1,3N-2]$ 在 $N\ge2$ 时相交,会产生伪冲突;错误来自丢失同余信息。

参考答案 EX07-C01|矩阵乘初始化 RAW 与归约边

沿用 EX06-C01。固定 $(i,j)$,初始化写 $C[i,j]$ 后,第一次更新 $U[i,j,0]$ 读同址且中间无写,所以

$$ \Delta_{\mathrm{init}} =\{I[i,j]\to U[i,j,0]\mid0\le i<M\land0\le j<N\land K>0\}:D_I\to D_U. $$

相邻更新间的精确循环携带 RAW 为

$$ \Delta_{\mathrm{red}} =\{U[i,j,k]\to U[i,j,k+1]\mid0\le i<M\land0\le j<N\land0\le k<K-1\}:D_U\to D_U, $$

其中 source 是 $k$,sink 是 $k+1$。$K=0$ 时两类边都空;$K=1$ 时只有初始化边。

参考答案 EX07-C02|Covered 差集与 lexmax 等价

对同一地址 $m$,设 $w_1\prec w_2\prec w_3\prec r$。候选为

$$ \{w_1\to r,w_2\to r,w_3\to r\}. $$

差集法中,$w_1\to r$ 被 $w_2$ 或 $w_3$ 覆盖,$w_2\to r$ 被 $w_3$ 覆盖,只剩 $w_3\to r$。Lexmax 法对固定 $(r,m)$ 选择所有先行写中的最大事件时间,同样得到 $w_3$。两法都依赖完整事件序和按地址选择。

参考答案 EX07-C03|多地址 last-write 后投影

设 $S$ 先写 $A[i]$ 与 $B[i]$,中间 $U$ 只写 $A[i]$,最后 $T$ 读两者。按 $A[i]$ 选择,$U$ 是 last write,得到 $U[i]\to T[i]$;按 $B[i]$ 选择,中间无覆盖写,得到 $S[i]\to T[i]$。

先保留访问 site 与地址。记写事件为 $u_A(i),s_B(i)\in E_W$,读事件为 $t_A(i),t_B(i)\in E_R$,则 last-write 的结果是事件—地址—事件三元组

$$ \begin{aligned} F_{\mathrm{RAW}} ={}&\{(u_A(i),A[i],t_A(i))\mid0\le i<N\}\\ &\cup\{(s_B(i),B[i],t_B(i))\mid0\le i<N\} \subseteq E_W\times M\times E_R. \end{aligned} $$

令 $\iota:E_W\cup E_R\to\biguplus_X D_X$ 抹去 access-site 身份并恢复其语句实例。它在事件三元组集合上的实例投影明确定义为

$$ \Pi_\iota(F) =\{\iota(e_s)\to\iota(e_t)\mid \exists m:(e_s,m,e_t)\in F\}. $$

于是 $\Pi_\iota(F_{\mathrm{RAW}})$ 是先按地址完成 last-write、再删去地址与 site 身份的结果,具体得到两支带类型的实例关系

$$ \begin{aligned} \Delta^A_{U\to T} &=\{U[i]\to T[i]\mid0\le i<N\}:D_U\to D_T,\\ \Delta^B_{S\to T} &=\{S[i]\to T[i]\mid0\le i<N\}:D_S\to D_T. \end{aligned} $$

也就是说,$\Pi_\iota(F_{\mathrm{RAW}})$ 恰含这两支。若先投影地址,只看到 $U$ 位于 $S,T$ 之间便删除 $S\to T$,会误删 $B$ 地址上的真实 flow。

参考答案 EX07-C04|RMW phase 与内部 WAR

对 $N=3$ 的 sum += A[i],令

$$ r_i=(i,0),\qquad w_i=(i,1). $$

动态事件序为

$$ r_0\prec w_0\prec r_1\prec w_1\prec r_2\prec w_2. $$

每个读事件后的第一次同址写就是本实例 $w_i$,所以精确 WAR 为

$$ \{r_0\to w_0,r_1\to w_1,r_2\to w_2\}. $$

候选 $r_i\to w_{i+1}$ 被 $w_i$ 覆盖。这三条是语句内部 read-before-write phase 边,不要求实例调度满足不可能的 $\theta(i)<\theta(i)$;跨实例累积顺序由 RAW/WAW 等另行表达。

参考答案:第 8 章

参考答案 EX08-B01|Shift 候选调度合法性

依赖从 source $i$ 指向 sink $i+1$,故

$$ d(i)=\theta(i+1)-\theta(i). $$

$$ \begin{array}{c|c|c} \theta(i)&d(i)&\text{一维严格合法性}\\ \hline 2i+3&2&\text{合法}\\ -2i&-2&\text{非法}\\ 7&0&\text{非法} \end{array} $$

常数项若只是多维前缀,仍可由后续维承载;作为完整一维调度则没有严格次序。

参考答案 EX08-B02|Producer/consumer 常数次序

对 $P(i)\to C(i)$,原距离为

$$ \Theta_C(i)-\Theta_P(i)=(i,0)-(i,1)=(0,-1), $$

首个非零分量为负,非法。只把消费者常数改为 2:

$$ \Theta_P(i)=(i,1),\qquad\Theta_C(i)=(i,2), $$

距离变为 $(0,1)$,严格 lex-positive。

参考答案 EX08-D01|Lex-positive 与 permutable band

距离 $(1,-3)$ 的首个非零分量为正,所以完整二维调度合法。但 permutable band 的常用充分条件要求带内活动依赖逐分量非负,第二分量 $-3$ 违反条件。交换两维后距离为 $(-3,1)$,首分量为负,调度非法。因此 lex-positive 弱于带内逐分量非负。

参考答案 EX08-D02|Residual dependence 分层

令初始关系为 $U_0=\Delta$。第一维给

$$ K_1=\{e\in U_0\mid d_1(e)=1\}, \qquad U_1=\{e\in U_0\mid d_1(e)=0\}. $$

第一维严格承载 $K_1$,只弱满足 $U_1$。第二维在 $U_1$ 上恒为 2,所以

$$ K_2=\{e\in U_1\mid d_2(e)=2\}=U_1, \qquad U_2=\{e\in U_1\mid d_2(e)=0\}=\varnothing. $$

题面没有给出实例边,不能进一步杜撰端点枚举。

参考答案 EX08-C01|两支依赖下的 identity/interchange

第一支 $(i,j)\to(i,j+1)$ 的距离为

$$ d_{\mathrm{id}}=(0,1),\qquad d_{\mathrm{swap}}=(1,0), $$

两者都合法。第二支 $(i,j)\to(i+1,j-2)$ 的距离为

$$ d_{\mathrm{id}}=(1,-2),\qquad d_{\mathrm{swap}}=(-2,1). $$

Identity 对两支均合法,interchange 因第二支首分量为负而非法。不能以第一支或平均距离代替完整依赖并集。

参考答案 EX08-D03|Stencil skew 系数下界

按本章约定,source 为 $(t-1,i+\delta)$,sink 为 $(t,i)$。对

$$ \Theta_k(t,i)=(t,kt+i), $$

距离为 $(1,k-\delta)$。当 $\delta=-1,0,1$ 时依次为 $(1,k+1),(1,k),(1,k-1)$。第二分量全部非负要求 $k-1\ge0$,故最小整数 $k=1$。

参考答案 EX08-C02|Sequence 与 fusion 的性能权衡

$N=3$ 时,分阶段顺序是

P(0), P(1), P(2), C(0), C(1), C(2)

融合顺序是

P(0), C(0), P(1), C(1), P(2), C(2)

两者都满足 $P(i)\to C(i)$。Fusion 可缩短中间值复用距离、减小工作集,却可能增加寄存器压力并妨碍每个阶段单独向量化。Sequence 可提供规则的长向量循环、批处理或异构阶段,却需要保存完整中间数组。实际选择取决于缓存、SIMD、资源、设备切换与同步成本,不存在无条件赢家。

参考答案 EX08-D04|后续负维不推翻词典序合法性

$$ \Theta_S(i)=(0,i),\qquad\Theta_T(i)=(0,i+1), $$

则 $S(i)\to T(i)$ 的二维距离为 $(0,1)$。再令第三维 source 为 100、sink 为 0,完整距离为

$$ (0,1,-100). $$

词典序在第二维正值 1 处已决定 sink 更晚,第三维不再影响该边,故调度仍合法。

参考答案:第 9 章

参考答案 EX09-B01|三角形上的仿射非负性

本章三角形为

$$ Q=\{(u,v)\in\mathbb R^2\mid u\ge0\land v\ge0\land3-u-v\ge0\}. $$

点 $(3,0)\in Q$,但

$$ f(3,0)=5-2\cdot3-0=-1<0. $$

所以 $f$ 并非在 $Q$ 上处处非负,不存在证明这个假命题的非负 Farkas 乘子组。

参考答案 EX09-D01|一维 Farkas 系数对齐

采用号向

$$ g_1(x)=x-1\ge0, \qquad g_2(x)=4-x\ge0. $$

非空区间上的 affine Farkas 恒等式为

$$ ax+b=\lambda_0+\lambda_1(x-1)+\lambda_2(4-x), \qquad \lambda_0,\lambda_1,\lambda_2\ge0. $$

对齐 $x$ 与常数项得到

$$ a=\lambda_1-\lambda_2, \qquad b=\lambda_0-\lambda_1+4\lambda_2. $$

参考答案 EX09-D02|候选调度的直接检查与证书

依赖域含 $i\ge0$ 与 $j-i-1\ge0$。候选 $\theta_S(i)=0,\theta_T(j)=j$ 的严格合法性式为

$$ f(i,j)=\theta_T(j)-\theta_S(i)-1=j-1. $$

由 $j\ge i+1$、$i\ge0$ 得 $j-1\ge i\ge0$。Farkas 证书是

$$ j-1=1\cdot i+1\cdot(j-i-1). $$

因此两条相应面约束的乘子取 1,$\lambda_0=0$,其余面乘子取 0。展开后 $i$ 系数 $1-1=0$、$j$ 系数 1、常数 $-1$,全部对齐。

参考答案 EX09-D03|等式乘子的两种编码

令 $h(i,j)=j-i-1$。把 $h=0$ 写成 $h\ge0$、$-h\ge0$ 时,两条约束分别乘 $\lambda_+,\lambda_-\ge0$,贡献为

$$ \lambda_+h+\lambda_-(-h)=(\lambda_+-\lambda_-)h. $$

令自由乘子 $\mu=\lambda_+-\lambda_-\in\mathbb R$,即得到 $\mu h$。反向地,任意自由 $\mu$ 可取

$$ \lambda_+=\max(\mu,0), \qquad \lambda_-=\max(-\mu,0). $$

所以“两条不等式加非负乘子”与“一个等式加自由乘子”等价。

参考答案 EX09-C01|实松弛与 integer hull

对 $P=[0,\tfrac12]$ 与 $f(x)=-x$,

$$ P\cap\mathbb Z=\{0\}, $$

所以整数点上 $f(0)=0\ge0$。但实点 $x=1/2$ 上 $f=-1/2<0$,说明在实松弛上证明非负是整数正确性的充分条件,却非必要条件。

整数凸包为

$$ H=\operatorname{conv}(P\cap\mathbb Z)=\{0\}. $$

仿射函数在 $H$ 上非负当且仅当它在原整数点上非负:整数点凸组合上的函数值就是相应函数值的凸组合。

参考答案 EX09-C02|同余集合的 Farkas 边界

先把整数见证保留为 lifted set:

$$ \widetilde S =\{(x,k)\in\mathbb Z^2\mid0\le x\le10\land x=3k+1\}. $$

原来的一维集合不是 $\widetilde S$ 本身,而是它在 $x$ 坐标上的投影:

$$ S=\operatorname{proj}_x(\widetilde S) =\{x\in\mathbb Z\mid \exists k\in\mathbb Z:\ 0\le x\le10\land x=3k+1\}. $$

可行 $k=0,1,2,3$,故 $S=\{1,4,7,10\}$。若删除同余只保留 $[0,10]$,整数 0、2、3、5 等都会成为伪点;对该实松弛使用普通 Farkas 至多给安全的充分条件,不能称为原同余集合上的整数精确证书。精确处理需保留整数 $k$、分余数支或采用整数方法。

参考答案 EX09-C03|合法调度上的性能代理

取两个已满足 source → sink 合法性的候选:融合候选 $\Theta_P(i)=(i,0),\ \Theta_C(i)=(i,1)$ 的依赖距离是 $(0,1)$;阶段候选 $\Theta_P(i)=(0,i),\ \Theta_C(i)=(1,i)$ 的依赖距离是 $(1,0)$。把第一距离分量归一化为 $0\le d_1\le1$,定义有界线性代理

$$ J=d_1. $$

最小化 $J$ 时,融合候选得分 0、阶段候选得分 1,因此偏好较短的首维距离与局部复用;最大化同一个 $J$ 时,两者得分仍分别为 0、1,因此偏好阶段分离。合法约束负责排除任何使真实依赖不严格词典序向前的调度,目标只在该可行域内排序候选。若没有 $0\le d_1\le1$ 这类系数界或尺度归一化,最大化目标可能仅靠整体放大时间戳而无界;缓存、SIMD、设备批处理与同步成本也可能使代理与实测最优不一致。

参考答案 EX09-C04|Residual 合成的顺序有限化

顺序链为:

  1. 输入已知 $U_0=\Delta$ 与第一维调度模板,建立第一维有限线性约束。
  2. 求解并固定第一维系数,得到已知距离 $d_1$。
  3. 计算 $U_1=\{e\in U_0\mid d_1(e)=0\}$;$K_1=U_0\setminus U_1$ 已由第一维严格承载。
  4. 只以已知 $U_1$ 为输入,为第二维重新建立 Farkas 系统。

若第 2 步不固定,$U_1$ 的约束矩阵含上一维未知调度系数 $\gamma$;下一维又为这些约束引入未知乘子 $\lambda$,展开出现 $\lambda\gamma$ 的双线性积,不是普通 LP/ILP。

参考答案 EX09-D04|空依赖分支与空真

$$ P=\{x\mid x\ge0\land-x-1\ge0\} $$

同时要求 $x\ge0$ 与 $x\le-1$,所以 $P=\varnothing$。命题 $\forall x\in P:f(x)\ge0$ 对任意 $f$ 都空真,因为没有反例点。非空版本的 affine Farkas lemma 不能机械套用;调度器应先删除空依赖分支,或把空性作为独立逻辑分支处理。

参考答案:第 10 章

参考答案 EX10-D01|Fusion/fission 的完整依赖像

两类边为

$$ \begin{aligned} \Delta_{PQ}&=\{P(i)\to Q(i)\mid0\le i<N\},\\ \Delta_{QP}&=\{Q(i)\to P(i+2)\mid0\le i<N-2\}. \end{aligned} $$

原融合调度 $\Theta_P(i)=(i,0),\Theta_Q(i)=(i,1)$ 下,

$$ \begin{aligned} P(i):(i,0)&\to Q(i):(i,1),&d_{PQ}&=(0,1),\\ Q(i):(i,1)&\to P(i+2):(i+2,0),&d_{QP}&=(2,-1). \end{aligned} $$

两支都 lex-positive。候选分阶段调度 $\Theta'_P(i)=(0,i),\Theta'_Q(i)=(1,i)$ 下,

$$ d'_{PQ}=(1,0), \qquad d'_{QP}=(-1,2). $$

第二支首个非零分量为负,所以 distribution/fission 非法。初始化 state[0]state[1] 只补齐最初输入,不改变循环内边域。

参考答案 EX10-C01|Alias 使空依赖证明失效

令 $T$ 与 $A$ 是同一行主序 $N\times N$ 数组,语句为 $S(i,j):A[j,i]=A[i,j]$,原序为 $i$ 外层、$j$ 内层。对 $0\le i<j<N$:

  • source $S(i,j)$ 读 $A[i,j]$,写 $A[j,i]$;
  • sink $S(j,i)$ 随后读 $A[j,i]$,写 $A[i,j]$。

因此

$$ \{S(i,j)\to S(j,i)\mid0\le i<j<N\} $$

既是 RAW(source 写 $A[j,i]$,sink 读),也是 WAR(source 读 $A[i,j]$,sink 写)。写映射对实例仍是单射,因此不同实例间没有 WAW。Out-of-place 例的空依赖结论依赖 $A$ 与 $T$ 不别名;仅知道“可能别名”而没有具体布局时,只能给保守候选,不能列出唯一精确边。

参考答案 EX10-D02|Stencil skew 与交换

原三支距离为 $(1,-2),(1,0),(1,1)$。变换 $(t,i)\mapsto(t,kt+i)$ 后得到

$$ (1,k-2),\quad(1,k),\quad(1,k+1). $$

逐分量非负要求 $k\ge2$,故最小整数 $k=2$,三支变为 $(1,0),(1,2),(1,3)$。交换两维后是 $(0,1),(2,1),(3,1)$:第一支不由新第一维严格承载,但第二维为正,所以完整调度对三支仍 lex-positive。

参考答案 EX10-B01|Tile/point 时间戳与恢复

对 $(i,j)=(4,3)$、$(B_i,B_j)=(2,3)$,Euclidean 商余为

$$ q_i=\left\lfloor\frac42\right\rfloor=2, \quad r_i=4-2\cdot2=0, \qquad q_j=\left\lfloor\frac33\right\rfloor=1, \quad r_j=3-3\cdot1=0. $$

完整时间戳为 $(q_i,q_j,r_i,r_j)=(2,1,0,0)$。由 $i=B_iq_i+r_i=4$、$j=B_jq_j+r_j=3$ 恢复原点;余数范围保证唯一性。

参考答案 EX10-D03|Tiled 矩阵乘的归约距离

相邻归约边为 source $U(i,j,k)$ 到 sink $U(i,j,k+1)$。在调度

$$ \left( \left\lfloor\frac{i}{B_i}\right\rfloor, \left\lfloor\frac{j}{B_j}\right\rfloor, k, i\bmod B_i, j\bmod B_j \right) $$

下,距离为 $(0,0,1,0,0)$,严格 lex-positive。合法性不保证加速;仍需评价 $k$ 连续性、A/B/C 复用、缓存容量、向量化、归约压力与并行粒度。

参考答案 EX10-B02|Schedule tree 结构

domain {P(i); Q(i)}
└── sequence
    ├── filter {P(i)}
    │   └── band [i]
    │       └── leaf
    └── filter {Q(i)}
        └── band [i]
            └── leaf

sequence 按孩子位置施加“所有 P 先于所有 Q”的跨语句次序;filter 只筛选实例,不自行增加时间先后;band 规定各分支内部的 $i$ 次序。把 sequence 换成 set 也不会自动证明并行安全。

参考答案 EX10-C02|浮点归约的反结合例

取单精度数量级

$$ a=10^{20},\qquad b=-10^{20},\qquad c=3.14. $$

在通常 round-to-nearest 下,$a+b=0$,故 $(a+b)+c\approx3.14$。而 $c$ 远小于 $b$ 在该数量级的一个 ULP,$b+c$ 会舍入回 $b$,于是 $a+(b+c)=0$。私有化和树形合并改变括号结构,因此即使依赖意义上合法,常规 IEEE 语义也不保证逐位相同;需要 fast-math、容差或可重现归约等显式契约。

参考答案 EX10-D04|非单射调度与严格合法性

取真实边 $S(0)\to S(1)$,完整一维候选 $\theta(i)=0$ 把 source 与 sink 都映到 0,距离为 0,不满足严格词典序。问题不在“非单射”本身,而在该真实边没有任何维承载。

增加后续维 $\Theta(i)=(0,i)$ 后,距离为 $(0,1)$;也可把两端置于有序 sequence 子树。只要完整调度的某个首个非零分量为正,就可以在较早维同值。

参考答案:第 11 章

参考答案 EX11-B01|三角域 identity 扫描

由 $0\le i<N$ 与 $i\le j<N$ 得

for (int i = 0; i < N; ++i)
  for (int j = i; j < N; ++j)
    S(i, j);

$N=4$ 时点集为

$$ \begin{aligned} &(0,0),(0,1),(0,2),(0,3),\\ &(1,1),(1,2),(1,3),\\ &(2,2),(2,3),\\ &(3,3), \end{aligned} $$

共 $4+3+2+1=10$ 点。覆盖性:任意域点的 $i$ 落入外层、$j$ 落入该内层区间。唯一性:循环计数器对唯一确定 $(i,j)$,每个点只生成一次。

参考答案 EX11-D01|负数同余域的 stride

用 Euclidean 商写 $i=1+3q$。边界给

$$ -5\le1+3q<5 \iff -2\le q<\frac43. $$

所以 $q=-2,-1,0,1$,对应 $i=-5,-2,1,4$。可生成:

for (int q = -2; q <= 1; ++q) {
  int i = 1 + 3 * q;
  S(i);
}

C/C++ 截余数随被除数带符号,-5 % 3-2 % 3 都不是 1,因此 guard i % 3 == 1 会漏掉 $-5,-2$ 两个点。它不能直接充当 Euclidean 同余判定。

参考答案 EX11-B02|非幺模调度像扫描

$0\le i<4$、$t=3i$ 的精确调度像为 $\{0,3,6,9\}$。Stride 版本为

for (int t = 0; t <= 9; t += 3)
  S(t / 3);

包络加 guard 版本为

for (int t = 0; t <= 9; ++t)
  if (t % 3 == 0)
    S(t / 3);

只有 stride 或整除 guard 保证 $t$ 可被 3 整除后,$i=t/3$ 才是精确恢复;无 guard 扫描会制造无原像时间点。

参考答案 EX11-D02|负左边界的 tile floor

对 $L=-2,N=5,B=3$,数学 floor 给

$$ ii_{\min}=\left\lfloor\frac{-2}{3}\right\rfloor=-1, \qquad ii_{\max}=\left\lfloor\frac{4}{3}\right\rfloor=1. $$

$$ \begin{array}{c|c} ii&\text{点}\\ \hline -1&-2,-1\\ 0&0,1,2\\ 1&3,4 \end{array} $$

C 表达式 L/B 向 0 截断为 0,会错误地漏掉 $ii=-1$ tile 及点 $-2,-1$。

参考答案 EX11-D03|二维边缘 tile 枚举

对 $0\le i<3,0\le j<5$ 做 $2\times3$ tiling:

$$ \begin{array}{c|l|c} (q_i,q_j)&\text{点}&\text{点数}\\ \hline (0,0)&i\in\{0,1\},\ j\in\{0,1,2\}&6\\ (0,1)&i\in\{0,1\},\ j\in\{3,4\}&4\\ (1,0)&i=2,\ j\in\{0,1,2\}&3\\ (1,1)&i=2,\ j\in\{3,4\}&2 \end{array} $$

总数 $6+4+3+2=15=3\cdot5$。恢复式

$$ i=2q_i+r_i,\ 0\le r_i<2; \qquad j=3q_j+r_j,\ 0\le r_j<3 $$

具有唯一 Euclidean 商余,所以 tile 编号和点内坐标共同唯一确定原点;边缘 tile 只是合法余数取值变少。

参考答案 EX11-D04|Ceil/max 与 floor 边界

三条约束分别给

$$ j\ge\left\lceil\frac{i-2}{3}\right\rceil, \qquad j\le\left\lfloor\frac{N+i}{2}\right\rfloor, \qquad j\ge0. $$

所以

$$ j_{\mathrm{lo}}=\max\left(0,\left\lceil\frac{i-2}{3}\right\rceil\right), \qquad j_{\mathrm{hi}}=\left\lfloor\frac{N+i}{2}\right\rfloor. $$

闭区间内层仅当 $j_{\mathrm{lo}}\le j_{\mathrm{hi}}$ 时非空;半开循环可写 j < j_hi + 1

参考答案 EX11-C01|Fourier–Motzkin 的整数缺口

把 $x=3y+1$ 拆成

$$ x-3y-1\le0, \qquad -x+3y+1\le0. $$

对任意实数 $x$,取 $y=(x-1)/3$,所以实 Fourier–Motzkin 投影是 $\mathbb R$。若 $x,y\in\mathbb Z$,精确投影为

$$ \{x\in\mathbb Z\mid x\equiv1\pmod3\}. $$

有界扫描应把起点对齐到余数 1 后取 stride 3,或用 Euclidean guard $(x-1)\bmod3=0$。实消元后的 floor/ceil 不能自动恢复同余。

参考答案 EX11-B03|Schedule-tree context 与 AST build context

Schedule-tree context 是树节点,在其子树下增加已知参数或外层 band 约束,例如 $N\ge1\land B=32$。isl_ast_build_from_context(set) 的集合则在创建 AST build 时提供初始外部参数事实,例如 $N\equiv0\pmod4\land M\ge N$;它不是树节点。

两者都可携带参数事实,但所有权和生命周期不同,不能把 build 的参数集叫作树中节点,也不能假设树节点自动包含所有调用现场事实。

参考答案 EX11-C02|参数分段与代码体积

取 $N>0,P\ge0$,扫描

$$ \max(0,P-N)\le i<\min(P,N). $$

保留 max/min 只需一份循环。完全分段可写成

$$ \begin{array}{c|c} \text{参数区}&i\text{ 的范围}\\ \hline 0\le P\le N&0\le i<P\\ N<P<2N&P-N\le i<N\\ P\ge2N&\varnothing \end{array} $$

三支覆盖 $P\ge0$ 且互不重叠。单体版本减小代码体积,却保留动态 min/max;分段可常量化边界并删空支,却增加参数分支、代码尺寸和编译时间。热区参数稳定且专门化收益大时可偏好分段,指令缓存紧张或参数很多时可偏好单体版本。

参考答案 EX11-C03|动态 user 事件的四项审计

令包络坐标 $\ell\in L$,guard 为 $g(\ell)$,两个静态节点为 $u_P,u_Q$。实际动态事件集为

$$ E=\{(u_P,\ell),(u_Q,\ell)\mid\ell\in L\land g(\ell)\}. $$

Guard 为假时该 $\ell$ 不产生事件;同一 $\ell$ 的两个事件由静态 user 身份区分,并有 $(u_P,\ell)\prec(u_Q,\ell)$。令恢复映射 $\rho(u,\ell)$ 给出带语句身份的原实例,则:

  1. 覆盖: $\rho[E]=\biguplus_u D_u$。
  2. 唯一: 对每个原实例 $d$,$|\rho^{-1}[\{d\}]|=1$。
  3. 依赖次序: 对每条 source → sink 依赖 $d_s\to d_t$,其唯一事件 $e_s,e_t$ 满足动态序 $e_s\prec e_t$。
  4. 实参恢复: 每个 user 实参 $\operatorname{args}_u(\ell)$ 等于 $\rho(u,\ell)$ 的原实例坐标,代入访问关系得到原语句的同一内存位置。

覆盖与唯一给出点集双射,不能替代第 3 项的顺序证明。

参考答案:第 12 章

参考答案 EX12-B01|小规模域、RAW 与 live-in

取 $T=2,N=5$,域为

$$ D_S=\{S[1,1],S[1,2],S[1,3],S[2,1],S[2,2],S[2,3]\}. $$

三支精确 source → sink RAW 为

$$ \begin{aligned} \Delta_{-1}&=\{S[1,1]\to S[2,2],S[1,2]\to S[2,3]\},\\ \Delta_0&=\{S[1,1]\to S[2,1],S[1,2]\to S[2,2],S[1,3]\to S[2,3]\},\\ \Delta_{+1}&=\{S[1,2]\to S[2,1],S[1,3]\to S[2,2]\}. \end{aligned} $$

共 $2+3+2=7$ 条。去重 live-in 为

$$ \{A[0,0],A[0,1],A[0,2],A[0,3],A[0,4],A[1,0],A[1,4]\}, $$

即第 0 行五点加第 1 行两侧边界,共 7 个位置。逐支列出的 source 与 sink 空间坐标均落在 $1\le i<N-1$ 内。

参考答案 EX12-D01|一般 skew 的距离与下界

对 $\Theta_k(t,i)=(t,kt+i)$,三支距离为

$$ \begin{array}{c|c} \text{source}\to\text{sink}&\Theta_k(\text{sink})-\Theta_k(\text{source})\\ \hline S(\tau,j)\to S(\tau+1,j+1)&(1,k+1)\\ S(\tau,j)\to S(\tau+1,j)&(1,k)\\ S(\tau,j)\to S(\tau+1,j-1)&(1,k-1) \end{array} $$

第二分量全部非负当且仅当 $k\ge1$,故最小整数 $k=1$。$k=0$ 时距离为 $(1,1),(1,0),(1,-1)$,首分量仍全为正,所以原调度保持词典序合法;$k=1$ 是构造逐分量非负 band 的要求,不是原合法性的必要条件。

参考答案 EX12-C01|Tile、wavefront 与点数全枚举

$T=4,N=5$ 时每层 $i=1,2,3$,共 12 点。定义

$$ q_x=\left\lfloor\frac{t-1}{3}\right\rfloor, \qquad q_y=\left\lfloor\frac{t+i-2}{2}\right\rfloor, \qquad w=q_x+q_y. $$

$$ \begin{array}{c|c|l|c} (q_x,q_y)&w&\text{原坐标 }(t,i)&\text{点数}\\ \hline (0,0)&0&(1,1),(1,2),(2,1)&3\\ (0,1)&1&(1,3),(2,2),(2,3),(3,1),(3,2)&5\\ (0,2)&2&(3,3)&1\\ (1,1)&2&(4,1)&1\\ (1,2)&3&(4,2),(4,3)&2 \end{array} $$

总数 $3+5+1+1+2=12$,与原域点数相同;Euclidean 商定义使每点只落入一个 tile,因此不漏不重。只有 $w=2$ 含两个 tile。若有同 wavefront 跨 tile RAW,skew 后 tile 坐标应逐分量非减且至少一维严格增,使 $w$ 严格增,矛盾;枚举中 $S(3,3)$ 只流向 $w=3$,$S(4,1)$ 无下一时间层。

参考答案 EX12-D02|精确 y 边界与删项反例

固定 $x=t$ 与 $y$-tile $q_y$。斜带和 tile 分别给

$$ x+1\le y\le x+N-2, \qquad 2+B_yq_y\le y\le1+B_y(q_y+1). $$

所以

$$ \boxed{ y_{\mathrm{lo}}=\max(x+1,2+B_yq_y), \qquad y_{\mathrm{hi}}=\min(x+N-2,1+B_y(q_y+1)) } $$

且只在 $y_{\mathrm{lo}}\le y_{\mathrm{hi}}$ 时执行。取 $B_y=2,N=5$:

  • 删 $x+1$:$x=4,q_y=1$ 会允许 $y=4$,即 $i=0$,越出域。
  • 删 $2+B_yq_y$:$x=1,q_y=1$ 会把属于 $q_y=0$ 的 $y=2,3$ 重复放入本 tile。
  • 删 $x+N-2$:$x=1,q_y=2$ 会允许 $y=6,7$,超过域上界 4。
  • 删 $1+B_y(q_y+1)$:$x=1,q_y=0$ 会允许属于 $q_y=1$ 的 $y=4$。

参考答案 EX12-C02|滚动缓冲的新访问与潜在 hazard

物理位置写成 $A[b,v]$,其中 $b\in\{0,1\}$。访问关系为

$$ \begin{aligned} W={}&\{S[t,i]\to A[b,v]\mid[t,i]\in D_S\land0\le b<2 \land b\equiv t\pmod2\land v=i\},\\ R_\delta={}&\{S[t,i]\to A[b,v]\mid[t,i]\in D_S\land0\le b<2 \land b\equiv t-1\pmod2\land v=i+\delta\}, \quad\delta\in\{-1,0,1\}. \end{aligned} $$

物理行每两步复用,产生 source → sink WAW 候选

$$ \Delta_{\mathrm{WAW}}^{\mathrm{roll}} =\{S[t,i]\to S[t+2,i]\mid1\le t\le T-2\land1\le i\le N-2\}, $$

以及每个读 site 的 WAR 候选

$$ \Delta_{\mathrm{WAR},\delta}^{\mathrm{roll}} =\{S[t,i]\to S[t+1,i+\delta]\mid 1\le t\le T-1\land1\le i\le N-2\land1\le i+\delta\le N-2\}. $$

WAR 的 source 先读物理行 $(t-1)\bmod2$,sink 随后因 $(t+1)\bmod2=(t-1)\bmod2$ 覆盖同址。边界读若没有域内后续写,不进入该支。变换前还需把这些候选与原 RAW 一起按事件序和 last/next-write 精确化,不能沿用完整二维数组的并行结论。

术语与符号速查

下表中的“对象边界”用于提醒相邻概念不可互换;公式中的实例坐标、调度时间与内存下标均取整数。

术语或符号定义直觉与编译器用途对象边界
仿射表达式(affine expression)$a_0+\sum_i a_ix_i$,系数是固定整数或有理数表示域界、数组下标和调度分量2*i+N 可;一般变量乘积 N*i 不可
准仿射表达式(quasi-affine expression)在仿射式外允许固定正分母的 floor/ceil 和 Euclidean mod 等受控运算表示 strip-mining、tile 坐标和整数边界固定 tile 大小可;两个符号变量相乘仍不可
准多项式(quasi-polynomial)在参数的各个余数类或更一般的周期格上分别等于一个多项式的函数表示参数化整数点计数或代价,例如偶/奇 $N$ 使用不同多项式它是计数/值函数,不是准仿射坐标映射的同义词
Presburger 算术含加法、序、固定整数倍、布尔连接词和量词的一阶整数算术为整数域、关系和判空提供可判定逻辑无一般变量乘法;可判定不等于总是计算便宜
Presburger 集/关系由 Presburger 公式定义的命名整数 tuple 集或 tuple 间关系统一表示迭代域、访问、依赖和调度自由变量决定维数;量化变量不出现在输出 tuple
线性集$L(b;p_1,\ldots,p_k)=\{b+\sum_r n_rp_r\mid n_r\in\mathbb N\}$用基点和有限周期生成无限离散集非负的是系数,不是向量子空间
半线性集(semilinear set)有限多个线性集之并描述 Presburger 集的周期结构可有无限孔洞,不等于单个凸多面体格点集
有理凸多面体(polyhedron)有限个有理线性等式/不等式的实解集 $P\subseteq\mathbb R^d$几何化约束,支持投影、凸优化和 Farkas 证书$P$ 是连续对象,不是循环整数实例本身
多面体整数点集$P\cap\mathbb Z^d$把连续多面体限制到可执行的整数实例与 $P$、integer hull 及一般 Presburger 集都不同
整数凸包(integer hull)$\operatorname{conv}(P\cap\mathbb Z^d)$用连续凸集精确承载整数点上的仿射非负性它仍是连续凸集,不是原离散点集
投影(projection)$\operatorname{proj}_I(X)=\{x_I\mid\exists x_{\bar I}:(x_I,x_{\bar I})\in X\}$,即保留坐标 $I$ 并对其余坐标作存在量化忘掉坐标,相当于存在量词消去整数投影可能保留同余;不能直接用实包络替代
严格词典序(strict lexicographic order)两向量不等时,由首个不同分量决定大小;该分量较小者严格在前定义多维调度先后及 lexmin/lexmax后续负分量不会推翻更早的正分量;完全相等不构成严格在前
SCoP控制和内存访问可由静态仿射/Presburger 对象精确描述的程序区域是经典多面体优化的输入边界数据依赖分支、间接访问和隐藏副作用通常越界
参数向量 $p$编译时符号化、执行中只读的整数,例如 $(T,N)$参数化同一族域和调度参数不是语句实例 tuple 坐标
参数上下文 $C(p)$只约束参数的公式,例如 $T\ge1\land N\ge3$限定所有后续对象的合法参数区与 schedule-tree context、AST build context 分层不同
迭代域 $D_S(p)$静态语句 $S$ 的全部动态实例集合把一次源语句的执行命名为整数点Tuple 名 $S$ 是 identity;$S[i]$ 与 $T[i]$ 不同
抽象内存空间 $M$由数组名和下标 tuple 区分的逻辑位置集合为别名和同址分析提供共同中间空间物理别名假设必须显式进入模型
读/写访问 $R_S,W_S$$D_S\to M$,从语句实例映到读取或写入位置连接程序实例与内存,构造同址候选方向恒为 instance → memory
原始事件序顺序程序中读写事件的动态先后,含语句内 phase过滤逆序候选并定义 last/next-write实例级调度未必能区分同一 RMW 的读和写
同址候选由访问及逆关系复合得到的共享地址实例对是依赖分析的候选起点尚未加入原序和覆盖写,不能称精确依赖
依赖 $\Delta_{S\to T}$$D_S\to D_T$,source 实例必须先于 sink 实例规定任何合法变换必须保持的因果顺序第一 tuple 永远是 source,第二 tuple 是 sink
RAW / flowSource 写、sink 读同址,source 是 sink 前最后写表示值从 producer 流向 consumer候选写读冲突还要做 last-write
WAR / antiSource 读、sink 随后写同址,sink 是 source 后第一次相关写防止后写过早覆盖尚未完成的读RMW 内部 read → write 常属于 phase 边
WAW / outputSource 写、sink 随后写同址,通常保留 next-write 链保持最终写入次序连续四写精确链只有三条相邻边
Live-in被域内实例读取、却没有域内先行 producer 的内存位置描述区域外必须提供的输入边界是内存位置集,不等于“第一轮所有读”的粗略说法
精确依赖同址候选结合原序和 last/next-write 后的关系为调度合法性提供真实约束按地址选择完成前不能投影掉地址
调度 $\Theta_S$$D_S\to\mathbb Z^k$,把实例映到有序时间戳用统一时间空间表达循环变换合法调度不要求全局单射,但每条真实边必须严格向前
调度距离$d=\Theta_T(y)-\Theta_S(x)$直接检查 source → sink 的词典序符号本教程始终是 sink 减 source,不得交换
Schedule map带语句身份的实例到 schedule space 的扁平映射/关系便于计算依赖像与按时间扫描不自然保留分支、band 和 tiling 结构
Schedule tree由 domain、context、sequence/set、filter、band 等节点组成的结构化调度保留语句组织、层次和 band 属性是工具表示,不是 Presburger 算术新运算
BandSchedule tree 中组织一组连续调度维的节点表示可整体变换、tiling 或标注的一组维一个 band 不机械对应一个 AST 循环
Permutable band允许带内维交换的 band;常用充分条件是活动依赖逐分量非负为 interchange 和矩形 tiling 提供结构入口完整距离 lex-positive 不足以推出可置换
Coincident 维对相关依赖无需承载顺序、可作为并行候选的调度维帮助标注潜在并行循环仍要检查归约、同步、别名和资源约束
Residual relation $U_r$前 $r$ 维距离均为 0、尚未严格承载的依赖子集逐维构造多维调度下一维建模前必须先固定上一维并算出 $U_r$
仿射 Farkas 引理(affine Farkas lemma)在非空实/有理多面体上,仿射式处处非负当且仅当它可写成非负面约束乘子与非负常数生成元 $\lambda_0$ 的组合把全称合法性有限化为有限的系数约束等价针对该实/有理多面体;用于整数域的实松弛时通常只给安全充分条件,整数精确性需在 integer hull 上应用或另用整数方法
Strip-mining用 Euclidean 商余把一维拆为块号与块内位置构造固定大小分块Floor/mod 是准仿射,不是普通仿射矩阵
Tiling对一个 band 的多维坐标做 strip-mining 并组织 tile/point 次序改善局部性、并行粒度或通信负坐标需数学 floor/mod;性能收益不必然
AST从域与调度扫描得到的 forifblockmarkuser 节点树把变换顺序恢复为目标控制结构生成成功不自动证明语义保持
动态 user 事件 $E(p)$参数 $p$ 下实际到达的 (user 身份, 外围迭代值) 事件通过恢复映射与原实例域建立点集双射Guard-false 循环迭代不进入 $E$;同一循环 tuple 可有多个 user
恢复映射 $\rho$$E(p)\to\biguplus_S D_S(p)$把生成 AST 事件还原为原语句实例双射只证明不漏不重,依赖次序另行检查
Stride / guardStride 只枚举某余数类;guard 在整数包络内筛成员恢复同余、整除和分段条件负数时 C % 不能未经规范化代替 Euclidean modulo
Floor / ceil 边界$z\ge a/q$ 取 $\lceil a/q\rceil$,$z\le b/q$ 取 $\lfloor b/q\rfloor$,$q>0$把有理界收紧成精确整数循环界负数时数学 floor/ceil 不等于 C 向 0 截断 /

关系运算速查

记 $\operatorname{Rel}(X,Y)=2^{X\times Y}$,并设 $R,S\in\operatorname{Rel}(X,Y)$、$Q\in\operatorname{Rel}(Y,Z)$。补集总是相对于显式 universe。复合固定为先走 $R$、再走 $Q$。

运算类型签名逻辑定义几何直觉编译器用途微型例子
Union $R\cup S$$\operatorname{Rel}(X,Y)^2\to\operatorname{Rel}(X,Y)$$(R\cup S)(x,y)\iff R(x,y)\lor S(x,y)$合并两个分支合并多个读 site、语句或依赖分支$\{0\to a\}\cup\{1\to b\}=\{0\to a,1\to b\}$
Intersection $R\cap S$同上$(R\cap S)(x,y)\iff R(x,y)\land S(x,y)$同时施加两组条件候选与原序、上下文或坏集相交$\{0\to a,1\to b\}\cap\{1\to b,2\to c\}=\{1\to b\}$
Difference $R\setminus S$同上$(R\setminus S)(x,y)\iff R(x,y)\land\neg S(x,y)$从一组边删除另一组Candidate \ Covered、删除已承载依赖$\{0\to a,1\to b\}\setminus\{1\to b\}=\{0\to a\}$
Complement $c_U(R)=U\setminus R$固定 $U\subseteq X\times Y$ 时,$c_U:2^U\to2^U,\ R\mapsto U\setminus R$$(U\setminus R)(x,y)\iff U(x,y)\land\neg R(x,y)$在给定全集内取反构造调度坏集或 guard 的补支$U=\{0,1\}\times\{a,b\}$、$R=\{0\to a,1\to b\}$ 时补集为 $\{0\to b,1\to a\}$
Projection $\pi_{X,Y}$$2^{X\times Y\times Z}\to2^{X\times Y}$$\pi_{X,Y}(A)=\{(x,y)\mid\exists z:(x,y,z)\in A\}$忘掉坐标消去地址、辅助商或 tile 内坐标$\{(0,a,7),(0,b,8)\}$ 投影前两维得 $\{(0,a),(0,b)\}$
Domain $\operatorname{domain}(R)$$\operatorname{Rel}(X,Y)\to2^X$$\{x\mid\exists y:R(x,y)\}$有至少一个输出的输入求有访问或有后继的实例$R=\{0\to a,2\to b\}$ 的 domain 为 $\{0,2\}$
Range $\operatorname{range}(R)$$\operatorname{Rel}(X,Y)\to2^Y$$\{y\mid\exists x:R(x,y)\}$可由某输入到达的输出求访问地址集或调度像上例 range 为 $\{a,b\}$
Inverse $R^{-1}$$\operatorname{Rel}(X,Y)\to\operatorname{Rel}(Y,X)$$R^{-1}(y,x)\iff R(x,y)$把每条边反向从内存位置回到读/写实例$\{0\to a,2\to b\}^{-1}=\{a\to0,b\to2\}$
Composition $Q\circ R$$\operatorname{Rel}(Y,Z)\times\operatorname{Rel}(X,Y)\to\operatorname{Rel}(X,Z)$$(Q\circ R)(x,z)\iff\exists y:R(x,y)\land Q(y,z)$先走 $R$,再走 $Q$写实例 → 内存 → 读实例;映射依赖到时间$R=\{0\to a\}$、$Q=\{a\to10\}$ 得 $Q\circ R=\{0\to10\}$
Image $R[A]$$\operatorname{Rel}(X,Y)\times2^X\to2^Y$$R[A]=\{y\mid\exists x\in A:R(x,y)\}$把输入集合沿关系向前送求实例子集的访问地址或调度像对 $R=\{0\to a,1\to b\}$、$A=\{1\}$,像为 $\{b\}$
Preimage $R^{-1}[B]$$\operatorname{Rel}(X,Y)\times2^Y\to2^X$$R^{-1}[B]=\{x\mid\exists y\in B:R(x,y)\}$找会落入目标集的输入把地址集或 guard 拉回实例域对上例 $B=\{b\}$,preimage 为 $\{1\}$;这里是集合运算,不是把结果当成 inverse relation
Lexmin $\operatorname{lexmin}(R)$$\operatorname{Rel}(X,Y)\to\operatorname{Rel}(X,Y)$对 fiber $R(x)=\{y\mid R(x,y)\}$,仅当它非空且存在达到的 lex 最小元 $y_*$ 时保留 $(x,y_*)$每个输入选最早输出选择最早事件或规范扫描代表$p\to\{(0,2),(0,1)\}$ 选 $p\to(0,1)$;空 fiber 不产边,$\{(0,n)\mid n\in\mathbb Z\}$ 无 lexmin
Lexmax $\operatorname{lexmax}(R)$同上仅当 fiber 非空且存在达到的 lex 最大元 $y^*$ 时保留 $(x,y^*)$每个输入选最后输出(sink,address) 选此前最后写同一有限 fiber 选 $p\to(0,2)$;空 fiber 不产边,向上无界 fiber 无 lexmax

对整数 fiber,有限性足以保证 lexmin/lexmax 存在;更一般时必须检查相应极值确实达到。逐坐标下界可保证 lexmin 的递归选择,逐坐标上界可保证 lexmax;仅有一个粗糙的词典序下界并不充分,例如 $\{(0,n)\mid n\in\mathbb Z\}$ 没有 lex 最小元。

三个高频类型链是

$$ \begin{aligned} W_S:D_S\to M,\quad R_T^{-1}:M\to D_T &\Longrightarrow R_T^{-1}\circ W_S:D_S\to D_T,\\ \Theta_S^{-1}:\mathbb Z^k\to D_S,\quad \Delta:D_S\to D_T,\quad \Theta_T:D_T\to\mathbb Z^k &\Longrightarrow \Theta_T\circ\Delta\circ\Theta_S^{-1}:\mathbb Z^k\to\mathbb Z^k,\\ R:X\to Y,\quad B\subseteq Y &\Longrightarrow R^{-1}[B]\subseteq X. \end{aligned} $$

最后一行的 $R^{-1}[B]$ 是 preimage 记号:可理解为 inverse relation $R^{-1}$ 对 $B$ 的 image,但“取得一组输入”与“构造整条逆关系”是两个不同操作。

延伸阅读路径

路径一:逻辑基础——从可判定性到半线性结构

  1. 先读 Presburger 1929 工作的英文译注稳定存档,建立语言边界、完备性和可判定性的历史坐标。
  2. 再读 Cooper 1972 的原文扫描,沿“存在量词等于投影”理解整数消元为何产生整除与同余。
  3. 最后读 Ginsburg–Spanier 1966 的原文,核对 modified Presburger formulas 与 $\mathbb N^d$ 半线性集的等价。

适合配做 EX02-D01/D02、EX03-D01、EX05-D02/C01/C03。阅读时必须标出论域是 $\mathbb N$ 还是 $\mathbb Z$;整数版需要显式差编码等搬运,可判定性也不意味着低复杂度。

路径二:依赖分析——从整数判空到精确 last-write

  1. 读 Pugh 的 The Omega Test,关注整数仿射约束的可行性、投影及编译器依赖问题。
  2. 接着读 Feautrier 1991 的Dataflow Analysis of Array and Scalar References,把同址候选、原始顺序和 last-write/覆盖写分成不同阶段。
  3. 用 EX04-C01、EX07-B01 至 EX07-C04、EX12-B01 逐条标出 source、sink、共享地址和中间写。

这条路线回答为什么 $R_T^{-1}\circ W_S$ 只给候选、为什么删除覆盖写会恢复更早 producer。Omega 支持整数可行性检查,但不替代事件顺序和 last-write 语义。

路径三:自动调度——从合法仿射时间到性能目标

  1. 依次读 Feautrier 1992 Part IPart II,跟踪调度合法性、逐维构造和 Farkas 有限化。
  2. 再读 Pluto 项目/作者资料Pluto+,观察并行性、局部性和工程目标怎样进入候选选择。
  3. 用 EX08-C01/C02、EX09-D02/C03/C04、EX10-D01/D02/D03 重算 identity、fusion、skew 和 tile 的完整依赖像。

核心边界是:合法可行域与性能目标是两层问题;普通 Farkas 工作在实/有理多面体上,对整数实例必须声明采用实松弛的安全充分条件,或先换成 integer hull。构造 residual 时要先固定上一维。

路径四:代码生成——从多面体扫描到语义审计

  1. 读 Quilleré–Rajopadhye–Wilde 2000 的参数化嵌套循环生成论文,建立扫描整数点和调度像的算法视角。
  2. 再读 Bastoul 2004 的作者公开稿,关注 CLooG 风格边界、参数分支和非简单可逆变换。
  3. 最后读 Verified Code Generation for the Polyhedral Model,把“生成循环”提升为覆盖、唯一、恢复和顺序保持的证明义务。

适合配做 EX11-B01、EX11-D01/D04、EX11-C01/C03、EX12-C01/D02。需要始终区分数学 floor/mod 与目标语言除法、实投影与整数同余、schedule 维与 AST 循环。

路径五:isl/工具实践——用对象类型贯穿全链

  1. isl 官方手册为主线,按 set/basic set、map、union map、schedule/schedule tree、AST build 的次序阅读对象和接口。
  2. 用 EX04-D02/C01 核对 apply_range 的复合方向;用第 6–7 章核对 instance → memory 与 source → sink tuple 类型;用第 8–10 章核对 schedule tree;用第 11–12 章核对 AST build 和 user 实参。
  3. 每次调用前先写数学签名。例如 W.apply_range(R.reverse()) 的结果必须是写实例域到读实例域。

isl 手册是工具对象和 API 语义来源,不替代 Presburger、半线性、精确 flow、仿射调度或扫描正确性的原始定理。终点不是记住打印文本,而是能从程序前提一路追踪到域、访问、依赖、调度、扫描和四项 AST 审计。