自動差別化

画像 プログラミングにおいて、教訓の1つは機能を複製しないことです。 そうでない場合、一部のセクションが他のセクションに非自明に依存するコードを取得します。 いくつかのタスクを実装する場合、この原則に従うのは簡単ですが、他のタスクでは問題が発生します。関数とその派生物の操作を必要とするそれほど複雑ではない数学アルゴリズムを使用するソフトウェアを検討してください。

f(a : double ) : double

{

a*a + 3 * a

}



df(a : double ) : double

{

2*a + 3

}







明らかに、少なくともコードfとdfは機能的に依存しており、おそらく機能の重複が見られます。 派生物の定義を思い出して、それに応じてdfコードを修正すれば、状況を修正できます。



df(a : double ) : double

{

def delta = 0.1;

(f(a+delta)-f(a))/delta

}






この場合、機能の重複を取り除きましたが、デルタパラメーターに最適な値がないため、プログラムの精度は支払われました。



真面目なエンジニアは、たとえばmatlabでプログラミングし、お気に入りのプログラミング言語にさらにコードを生成することで、この問題を解決できます。 しかし、コード生成は悪であるという意見があるため、別の方法について説明します。



虚数単位iは、方程式x 2 +1 = 0の解であると仮定されます。類推により、方程式x 2 = 0を解き、ゼロに等しくない別の虚数単位dを導入します。 次に、テイラー級数の関数の展開を思い出してください。

f(x + h)= f(x)+ f ^ {(1)}(x)h + \ frac {1} {2} f ^ {(2)}(x)h ^ 2 + \ frac {1 } {6} f ^ {(3)}(x)h ^ 3 + \ドット








虚数単位をhに置き換え、d 2 = 0という事実を使用すると、次のようになります。

f(x + d)= f(x)+ f '(x)d






したがって、点xで関数fの導関数の値を見つけるには、数fの虚数部(x + d)の係数を取得すれば十分です。 現代の言語では、複素数を扱うクラスを定義することは問題ではありません。これらの拡張数を扱うクラスを簡単に定義できます。 次の例は、Nemerleに翻訳されています。

public class Dual

{

public this (real : double , imaginary : double )

{

this .real = real;

this .imaginary = imaginary;

}



real : double ;

imaginary : double ;



public Real : double { get { real } }

public Imaginary : double { get { imaginary } }



public static @+(a : Dual, b : Dual) : Dual

{

Dual(a.real + b.real, a.imaginary + b.imaginary)

}



public static @-(a : Dual, b : Dual) : Dual

{

Dual(a.real - b.real, a.imaginary - b.imaginary)

}



public static @*(a : Dual, b : Dual) : Dual

{

Dual(a.real * b.real, a.real * b.imaginary + a.imaginary * b.real)

}



public static @/(a : Dual, b : Dual) : Dual

{

a*Dual(1/b.real, - b.imaginary / (b.real*b.real))

}



public static @:(k : double ) : Dual

{

Dual(k,0)

}

}










これで、記事の冒頭から例を書き換えることができます。

f(a : Dual) : Dual

{

a*a + 3.0 * a

}



f(a : double ) : double

{

f(Dual(a,0)).Real

}



df(a : double ) : double

{

f(Dual(a,1)).Imaginary

}








もちろん、派生物のコードは無料で入手できます。 このアプローチの短所は、2進数を扱うために基本関数を再定義する必要があることですが、得られた式のおかげで難しくありません。正弦過負荷は以下のとおりです。

public Sin(a : Dual) : Dual

{

Dual( Math .Sin(a.Real), Math .Cos(a.Real)*a.Imaginary)

}








もっと欲しい:

画像 自動差別化
画像 二重番号
画像 自動差別化
画像 自動ディエンティフィケーション、C ++テンプレートおよび

写真測量
画像 ネメルル




コンピューターサイエンスのブログを作成して、この投稿を投稿したかったのですが、ハブで一時的に新しいブログを作成できないことを願っています。そのため、「異常なプログラミング」ブログに掲載しました。 Computer Scienceブログは、言い換え、翻訳、Computer Scienceの定義に該当する記事の注釈、pdfへのリンクなどを書くことができる場所になる予定でした。 このブログで記事を書きたい人は誰でも、そのオープンを待つのではなく、「コンピューターサイエンスへ」というタグを付けて「異常なプログラミング」で書くことをお勧めします。



All Articles