elementary チュートリアル

このチュートリアルでは、arithmetic のトレイトに対して書かれた解析的なコードを微分します。Exponential、Logarithmic、Trigonometric の境界を持つ関数を一度だけ書き、Double 上で評価し、Dual[Double] 上で実行してその導関数を得ます。背後にある規則は elementary の設計 にあります。

クイックスタート

moon add Luna-Flow/autodiff@0.2.0
import {
  "Luna-Flow/autodiff/elementary",
}
fn[T : @elementary.Trigonometric + Mul] sin_squared(x : T) -> T {
  let s = @elementary.Trigonometric::sin(x)
  s * s
}

fn main {
  let y = sin_squared(@elementary.Dual::variable(0.5))
  println("sin^2(0.5) = \{y.value()}")
  println("derivative = \{y.tangent()}")
}
sin^2(0.5) = 0.22984884706593015
derivative = 0.8414709848078965

導関数は 2sin⁡xcos⁡x=sin⁡2x2\sin x\cos x = \sin 2x で、ここでは sin⁡1\sin 1 です。

日常的なタスク

対数関数と指数関数

fn[T : @elementary.Exponential + @elementary.Logarithmic + Mul] f(x : T) -> T {
  @elementary.Exponential::exp(x) * @elementary.Logarithmic::ln(x)
}

fn main {
  let y = f(@elementary.Dual::variable(1.0))
  println("f(1) = \{y.value()}, f'(1) = \{y.tangent()}")
}
f(1) = 0, f'(1) = 2.718281828459045

(exln⁡x)′=exln⁡x+ex/x(e^x \ln x)' = e^x \ln x + e^x/x で、x=1x = 1 では ee です。

その他の底

exp2、log2、log10 には底の変換の係数が含まれます:

fn main {
  let x = @elementary.Dual::variable(3.0)
  println("d/dx 2^x at 3     = \{x.exp2().tangent()}")
  println("d/dx log2 x at 3  = \{x.log2().tangent()}")
  println("d/dx log10 x at 3 = \{x.log10().tangent()}")
}
d/dx 2^x at 3     = 5.545177444479562
d/dx log2 x at 3  = 0.48089834696298783
d/dx log10 x at 3 = 0.14476482730108392

ジェネリックなコード中の定数

fn[T : @elementary.Trigonometric + @elementary.Constants + Mul] wave(t : T) -> T {
  let tau : T = @elementary.Constants::tau()
  @elementary.Trigonometric::sin(tau * t)
}

fn main {
  let y = wave(@elementary.Dual::variable(0.0))
  println("slope at 0 = \{y.tangent()}")
}
slope at 0 = 6.283185307179586

定数 τ=2π\tau = 2\pi の接成分は 0 なので、tt だけが微分されます。

正接関数とその極

fn main {
  for a in [0.0, 1.0, 1.5] {
    let y = @elementary.Dual::variable(a).tan()
    println("tan'(\{a}) = \{y.tangent()}")
  }
}
tan'(0) = 1
tan'(1) = 3.425518820814759
tan'(1.5) = 199.8500445264925

導関数 1/cos⁡2a1/\cos^2 a は π/2\pi/2 に近づくにつれて限りなく大きくなります。

さらに進む

  • 解析的トレイトをルートパッケージまたは core の Ring と組み合わせれば、完全なモデルを書けます。autodiff チュートリアル を参照してください。
  • 独自のスカラー型では Exponential、Logarithmic、Trigonometric を実装してください。そうすれば、その型の Dual が同じ規則でそれらを微分します。
  • 定義域をチェックする平方根には SqrtChecked を使います。checked チュートリアル を参照してください。

よくある落とし穴

  • 定義域の外では NaN や無限大になります。 正でない数の ln や 0 での sqrt はチェックされません。
  • トレイトインスタンスはメソッドより多くを必要とします。 Dual[T] 上で @elementary.Exponential::exp を呼び出すには、インスタンスの完全な境界(T 上の Logarithmic と IntegralHomomorphism)が必要です。メソッド x.exp() が必要とするものはより少なくなります。
  • 双曲線関数や逆関数はありません。 sinh、asin、atan などにはまだ双対数の規則がありません。必要な場合は利用可能な関数から合成してください。

次のステップ

  • elementary API にはトレイトと境界が記載されています。
  • dual API には、実際に計算される形ですべての規則が記載されています。
  • arithmetic ではトレイトを文書化しています。