mutable チュートリアル

このチュートリアルは、多項式をその場で更新するための入口です。必要な 1 つのインポート、変更操作と演算子の違い、ミュータブル層とイミュータブル層の間の行き来、そして各表現のチュートリアルの続きがどこにあるかを示します。

クイックスタート

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 で終わるメソッド、セッター、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")
}

さらに進む

両方の層に対応するジェネリックなコード

能力トレイトと演算レコードは両方のファサードで共通です:

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 は項を 1 つずつ挿入します。累積には疎なコンテナを選んでください。
  • コンテキストの不一致は中断 (abort) する. add_inplace と mul_inplace で起こります。チェック付きのその場更新の形式はありません。
  • 層の混在. @mutable.DensePolynomial は @immut.DensePolynomial ではありません。to_immut / from_immut で変換してください。

次のステップ