consistency 设计
设计目标
immut 和 mutable 用不同的存储和不同的内核把相同的核心运算实现了两遍,MatrixFn 又以惰性方式实现了第三遍。consistency 包检查这些实现表示的是同一套数学,从而让用户切换表示时结果不变,也让一个包中的内核优化无法悄悄改变语义。
数学背景
一致性即同态性质
设 是保持形状和元素的转换。当 与运算 可交换时,称两个包在该运算上一致:
测试通过共同的观察手段(to_array、to_2d_array 或 to_string)比较两边,这些观察在已知形状的矩阵上是单射。
检验定律而非示例
除了一致性之外,测试还在两个包中检查代数定律:单位律、、乘积的结合律、分配律,以及 。转置乘积定律需要可交换的标量;测试使用 Int。
为何使用小整数
所有检查都使用 Int。整数运算是精确的环 ,即便溢出也是如此,因此每条定律都可以用 == 检验,每次失败都是真正的不一致。若用 Double,不同的求和顺序会合理地产生舍入差异(见 mutable 设计),测试就需要容差,而容差可能掩盖真正的缺陷。基于性质的测试用 quickcheck 随机抽取 整数矩阵,并在每个样本上检查这些定律。
设计决策
独立的包
这些检查同时需要 immut 和 mutable,而两个包都不应依赖对方。由第三个包仅在测试中同时导入二者,可以保持依赖图整洁。它的测试是白盒测试(*_wbtest.mbt),因此可以使用不加限定的辅助函数名。
有文档说明的差异也要测试
在两个包有意不同的地方(例如 set 在 mutable 中原地修改,而在 immut 中返回新值),会有测试把差异固定下来,使其始终是一个决定而不是偶然。
正确性与不变量
对所有被测输入,该包断言:+、*、转置、迹、pow、行列式(整数输入)、构造函数和转换的结果相同;矩阵算术满足半环定律;以及 这类退化形状具有文档所述的行为。
被否决的方案
- 浮点一致性测试。 它们需要容差,测试的是舍入而不是语义;数值精度改在
mutable内部测试。 - 只测试示例。 随机输入能在作者没想到的值(例如负元素和零)上发现不一致。
边界
该包没有公开 API,也不发布供使用。它不测试只存在于一个包中的数值例程(逆矩阵、Cholesky、特征值),也不测试性能。