mutable/context 设计

设计目标

可变的 ContextPolynomial[A] 为具名变量多项式提供与其他可变容器相同的原地接口(add_inplace、mul_inplace、clear、copy),而无需再实现一遍上下文、具名求值和代换。

数学背景

其语义与 immut/context 相同:一个满足 f∈R[Γ]f \in R[\Gamma] 的二元组 (Γ,f)(\Gamma, f),代换为环同态 φσ\varphi_\sigma,部分求值为以标量进行的代换。可变上下文多项式是一个值为此类二元组的变量;原地操作是在固定环 R[Γ]R[\Gamma] 内的赋值 f←f+gf \leftarrow f + g 和 f←fgf \leftarrow f g。

设计决策

包裹不可变值的可变单元

选择。 该类型是一个记录,带有一个保存 immut/context 多项式的可变字段。每个查询、求值和代换都转发给所保存的值;add_inplace、mul_inplace 和 clear 计算一个新的不可变值并存入该字段。

原因。 上下文处理是本库中验证规则最多的部分(成员关系、重复、名字解析、上下文相等)。只实现一次可以保证两层接受和拒绝的调用完全相同,并产生相同的规范结果。由于所保存的值是不可变的,共享它是安全的:

  • copy 为 O(1)O(1):新单元保存同一个不可变值,之后对任一单元的原地操作只替换该单元的值,而不影响另一个;
  • 出于同样的原因,to_immut 不经复制地返回所保存的值,from_immut 也不经复制地包裹一个值。

单独的代换载荷

这里重新定义了 ContextSubstitutionValue,以便 Polynomial(p) 可以携带可变上下文多项式。代换通过读取所保存的值把每个载荷转换为不可变载荷,然后进行委托。结果是一个新的可变单元;代换或部分求值不会改变接收者。

只添加二元原地操作

原地操作集合为 add_inplace、mul_inplace 和 clear。代换和部分求值返回新单元,与不可变 API 一致,因为代换结果是一个不同的多项式,而不是对旧多项式的更新。可变类型没有 add_checked 或 mul_checked 方法;带检查形式可通过 ops() 或 to_immut() 使用。

清空保留上下文

clear 把值设为同一上下文上的零多项式,以稀疏方式存储。容器仍留在 R[Γ]R[\Gamma] 中,因此之后用 Γ\Gamma 上的多项式调用 add_inplace 仍然有效。

正确性 / 不变量

  • 与 immut 语义相同。 每个非修改方法都返回 from_immut(self.to_immut().op(...))。
  • 上下文固定。 原地操作遇到不同的上下文时会中止,因此单元的上下文从不改变。
  • 隔离。 修改一个单元绝不会改变另一个单元,或用 to_immut 得到的不可变值。
  • 代价即不可变操作的代价;copy、from_immut 和 to_immut 为 O(1)O(1)。

被否决的替代方案

  • 在可变 term 和 sparse 容器之上的可变重新实现能允许真正的原地项更新,但会重复每一条验证规则。
  • 不提供会修改接收者的代换(substitute_inplace);代换是作用于值的同态,把结果赋回去只需一行。

边界

  • 没有逐项的原地更新;如需此功能,请用 to_sparse_polynomial() 转换,并重新绑定结果。
  • 类型本身没有带检查的二元方法。
  • 所有 immut/context 的边界都适用,包括 from_term_polynomial 和 from_sparse_polynomial 不检查元数这一点。