mutable/context 设计
设计目标
可变的 ContextPolynomial[A] 为具名变量多项式提供与其他可变容器相同的原地接口(add_inplace、mul_inplace、clear、copy),而无需再实现一遍上下文、具名求值和代换。
数学背景
其语义与 immut/context 相同:一个满足 的二元组 ,代换为环同态 ,部分求值为以标量进行的代换。可变上下文多项式是一个值为此类二元组的变量;原地操作是在固定环 内的赋值 和 。
设计决策
包裹不可变值的可变单元
选择。 该类型是一个记录,带有一个保存 immut/context 多项式的可变字段。每个查询、求值和代换都转发给所保存的值;add_inplace、mul_inplace 和 clear 计算一个新的不可变值并存入该字段。
原因。 上下文处理是本库中验证规则最多的部分(成员关系、重复、名字解析、上下文相等)。只实现一次可以保证两层接受和拒绝的调用完全相同,并产生相同的规范结果。由于所保存的值是不可变的,共享它是安全的:
copy为 :新单元保存同一个不可变值,之后对任一单元的原地操作只替换该单元的值,而不影响另一个;- 出于同样的原因,
to_immut不经复制地返回所保存的值,from_immut也不经复制地包裹一个值。
单独的代换载荷
这里重新定义了 ContextSubstitutionValue,以便 Polynomial(p) 可以携带可变上下文多项式。代换通过读取所保存的值把每个载荷转换为不可变载荷,然后进行委托。结果是一个新的可变单元;代换或部分求值不会改变接收者。
只添加二元原地操作
原地操作集合为 add_inplace、mul_inplace 和 clear。代换和部分求值返回新单元,与不可变 API 一致,因为代换结果是一个不同的多项式,而不是对旧多项式的更新。可变类型没有 add_checked 或 mul_checked 方法;带检查形式可通过 ops() 或 to_immut() 使用。
清空保留上下文
clear 把值设为同一上下文上的零多项式,以稀疏方式存储。容器仍留在 中,因此之后用 上的多项式调用 add_inplace 仍然有效。
正确性 / 不变量
- 与 immut 语义相同。 每个非修改方法都返回
from_immut(self.to_immut().op(...))。 - 上下文固定。 原地操作遇到不同的上下文时会中止,因此单元的上下文从不改变。
- 隔离。 修改一个单元绝不会改变另一个单元,或用
to_immut得到的不可变值。 - 代价即不可变操作的代价;
copy、from_immut和to_immut为 。
被否决的替代方案
- 在可变 term 和 sparse 容器之上的可变重新实现能允许真正的原地项更新,但会重复每一条验证规则。
- 不提供会修改接收者的代换(
substitute_inplace);代换是作用于值的同态,把结果赋回去只需一行。
边界
- 没有逐项的原地更新;如需此功能,请用
to_sparse_polynomial()转换,并重新绑定结果。 - 类型本身没有带检查的二元方法。
- 所有 immut/context 的边界都适用,包括
from_term_polynomial和from_sparse_polynomial不检查元数这一点。