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;之前取得的副本不受影响。
日常任务
选择容器
| 你想要 | 使用 | 教程 |
|---|---|---|
| 设置并累加单变量系数 | DensePolynomial | mutable/dense |
| 在添加时保持多变量项有序 | TermPolynomial | mutable/term |
| 以 添加或设置多变量项 | SparsePolynomial | mutable/sparse |
| 累加命名变量多项式 | ContextPolynomial | mutable/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转换。
后续步骤
- 上面链接的各容器教程。
- mutable API 和 mutable 设计,后者列出了与
immut的所有差异。 - 面向值的层请参见 immut 教程。