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
導関数は で、ここでは です。
日常的なタスク
対数関数と指数関数
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
で、 では です。
その他の底
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
定数 の接成分は 0 なので、 だけが微分されます。
正接関数とその極
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
導関数 は に近づくにつれて限りなく大きくなります。
さらに進む
- 解析的トレイトをルートパッケージまたは
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 ではトレイトを文書化しています。