mutable 教程

本教程是原地更新多项式的入门。它介绍你需要的唯一导入、修改与运算符的区别、如何在可变层与不可变层之间切换,以及各表示的教程从哪里继续。

快速开始

moon add Luna-Flow/luna-poly@0.2.0
import {
  "Luna-Flow/luna-poly/mutable",
}
test "mutable quick start" {
  let p = @mutable.DensePolynomial::from_coefficients([1, 2, 3])
  let snapshot = p.copy()
  p.set_coefficient(1, 5)
  p.add_inplace(@mutable.DensePolynomial::from_coefficients([-1, -5, -3]))
  assert_true(p.is_zero())
  inspect(snapshot, content="1 + 2x^1 + 3x^2")
}

set_coefficient 和 add_inplace 会改变 p;之前取得的副本不受影响。

日常任务

选择容器

你想要使用教程
设置并累加单变量系数DensePolynomialmutable/dense
在添加时保持多变量项有序TermPolynomialmutable/term
以 O(log⁡m)O(\log m) 添加或设置多变量项SparsePolynomialmutable/sparse
累加命名变量多项式ContextPolynomialmutable/context

了解哪些操作会修改

以 _inplace 结尾的方法、setter 和 clear 会修改;运算符从不修改:

test "what mutates" {
  let p = @mutable.SparsePolynomial::from_array([([1U], 1)])
  let q = p * p
  inspect(p, content="1 * x")
  p.mul_inplace(p)
  inspect(p, content="1 * x^2")
  assert_true(p == q)
}

跨越到 immut 的边界

在模块边界处进行转换,使调用者拿到的是值:

fn build_power_sum(n : Int) -> @immut.DensePolynomial[Int] {
  let acc : @mutable.DensePolynomial[Int] = @mutable.DensePolynomial::zero()
  for k in 0..<n {
    acc.set_coefficient(k, 1)
  }
  acc.to_immut()
}

test "boundary" {
  inspect(build_power_sum(4), content="1 + 1x^1 + 1x^2 + 1x^3")
}

深入了解

适用于两层的泛型代码

能力 trait 和操作记录对两个门面包都是相同的:

fn[P, A] eval_square(ops : @mutable.UnivariateOps[P, A], p : P, a : A) -> A {
  ops.eval(ops.mul(p, p), a)
}

test "both layers" {
  inspect(eval_square(@mutable.DensePolynomial::ops(), @mutable.DensePolynomial::from_coefficients([1, 1]), 2), content="9")
  inspect(eval_square(@immut.DensePolynomial::ops(), @immut.DensePolynomial::from_coefficients([1, 1]), 2), content="9")
}

泛型地重置缓冲区

每个可变容器都实现 MutablePolynomial(Clearable + Copyable):

fn[P : @mutable.MutablePolynomial] fresh_copy_and_clear(p : P) -> P {
  let c = @mutable.Copyable::copy(p)
  @mutable.Clearable::clear(p)
  c
}

test "generic reset" {
  let t = @mutable.TermPolynomial::from_array([([2U], 1)])
  inspect(fresh_copy_and_clear(t), content="1 * x^2")
  assert_true(t.is_zero())
}

常见陷阱

  • 绑定共享容器。let q = p 不会复制;请使用 p.copy()。
  • 向项数组中做大量加法。TermPolynomial::add_inplace 每次插入一项;累加时优先使用稀疏容器。
  • 上下文不匹配会中止(abort):add_inplace 和 mul_inplace 在上下文不匹配时中止;没有带检查的原地形式。
  • 混用两层。@mutable.DensePolynomial 不是 @immut.DensePolynomial;请用 to_immut / from_immut 转换。

后续步骤