質問
C#とF#の間で動作するために自動差別化を取得するのに問題があります。
C#では、ダブルを取り、ダブルを返す関数があります。
private double Price(double yield)
{
double price;
price = 0;
for (int index = 1; index <= _maturity * _frequency; index++)
{
price += (_coupon / _frequency) * _nominal / Math.Pow(1 + (yield / _frequency), index);
}
price += _nominal / Math.Pow(1 + (yield / _frequency), _maturity * _frequency);
return price;
}
Math.Powは非常に禁止されており、そのパラメーターに対してDoubleまたはIntのみを許可しているため、この機能を特に選択しました。
自動分化を使用してこの関数を区別したいと思います。この方法をF#で書きました:
type Diff(d : double, df : Lazy<Diff>) = class
member x.d = d
member x.df = df
static member (+) (x : Diff, y : Diff) =
Diff(x.d + y.d, lazy (x.df.Value + y.df.Value))
static member (-) (x : Diff, y : Diff) =
Diff(x.d - y.d, lazy (x.df.Value - y.df.Value))
static member (*) (x : Diff, a : double) =
Diff(x.d * a, lazy (x.df.Value * a))
static member (*) (x : Diff, y : Diff) =
Diff(x.d * y.d, lazy ((x.df.Value * y) + (y.df.Value * x)))
override x.ToString() =
x.d.ToString()
end
let rec dZero = Diff(0.0, lazy dZero)
let dConst x = Diff(x, lazy dZero)
let dId x = Diff(x, lazy dConst 1.0)
let Differentiate (x:Diff) = x.df.Value
// Example function
let f (x:Diff) = x*x*x;
// Example usage:
// (f (dId 5)).ToString = "125"
// (Differentiate (f (dId 5))).ToString = "75"
// (Differentiate (Differentate (f (dId 5)))).ToString = "30"
残念ながら、タイプDIFF(..)関数にタイプDIFFをフィードしてタイプDIFFを生成する必要があります。これにより、別のタイプDIFFを返すためにdifferent(..)関数に供給されます。
ただし、C#機能はダブルのみで機能します(C#プログラムの他の場所で使用されているように、このように留まりたいと思います)。
これを解決するために私が考えることができる唯一の方法は、すべての機能を2回書くことです。これは明らかに次のようです。
1)毎回差別化されたバージョンを書くこともできます2)これは非常に拡張可能なモデルではありません
だから、私がこれを回避する方法、またはおそらく私の二重関数をDIFF関数に強制する方法があります(できればF#)。理想的には、(double - > double)関数を投入し、diff.tostring()を取得したいだけです。
これが完全に曖昧または理解することが不可能な場合は申し訳ありません。これが不明であれば、コメントの質問に答えます。
これの解決策があることを願っています!前もって感謝します、
アシュリー
解決
Haskellタイプのクラスを再発明できます。
interface Eq<T>
{
bool Equal(T a, T b);
bool NotEqual(T a, T b);
}
interface Num<T> : Eq<T>
{
T Zero { get; }
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
T Negate(T a);
}
sealed class Int : Num<int>
{
public static readonly Int Instance = new Int();
private Int() { }
public bool Equal(int a, int b) { return a == b; }
public bool NotEqual(int a, int b) { return a != b; }
public int Zero { get { return 0; } }
public int Add(int a, int b) { return a + b; }
public int Subtract(int a, int b) { return a - b; }
public int Multiply(int a, int b) { return a * b; }
public int Negate(int a) { return -a; }
}
その後、あなたはできます:
static T F<M, T>(M m, T x) where M : Num<T>
{
return m.Multiply(x, m.Multiply(x, x));
}
static void Main(string[] args)
{
Console.WriteLine(F(Int.Instance, 5)); // prints "125"
}
そして、と:
class Diff
{
public readonly double d;
public readonly Lazy<Diff> df;
public Diff(double d, Lazy<Diff> df)
{
this.d = d;
this.df = df;
}
}
class DiffClass : Floating<Diff>
{
public static readonly DiffClass Instance = new DiffClass();
private static readonly Diff zero = new Diff(0.0, new Lazy<Diff>(() => DiffClass.zero));
private DiffClass() { }
public Diff Zero { get { return zero; } }
public Diff Add(Diff a, Diff b) { return new Diff(a.d + b.d, new Lazy<Diff>(() => Add(a.df.Value, b.df.Value))); }
public Diff Subtract(Diff a, Diff b) { return new Diff(a.d - b.d, new Lazy<Diff>(() => Subtract(a.df.Value, b.df.Value))); }
public Diff Multiply(Diff a, Diff b) { return new Diff(a.d * b.d, new Lazy<Diff>(() => Add(Multiply(a.df.Value, b), Multiply(b.df.Value, a)))); }
...
}
あなたはこれを行うことができます:
static T Price<M, T>(M m, T _maturity, T _frequency, T _coupon, T _nominal, T yield) where M : Floating<T>
{
T price;
price = m.Zero;
for (T index = m.Succ(m.Zero); m.Compare(index, m.Multiply(_maturity, _frequency)) <= 0; index = m.Succ(index))
{
price = m.Add(price, m.Divide(m.Multiply(m.Divide(_coupon, _frequency), _nominal), m.Power(m.Add(m.Succ(m.Zero), m.Divide(yield, _frequency)), index)));
}
price = m.Add(price, m.Divide(_nominal, m.Power(m.Add(m.Succ(m.Zero), m.Divide(yield, _frequency)), m.Multiply(_maturity, _frequency))));
return price;
}
しかし、それは本当にきれいではありません。
実際、Linq式のツリーを作成するコードのようにほとんど読み取られます。多分あなたは使用することができます ソースコード 表現ツリー変換 それ以外の オペレーターのオーバーロード 達成するために 自動分化?
他のヒント
既存のC#関数を使用する方法も、タイプのメンバーで動作できる関数にそれを持ち上げる簡単な方法もありません Diff
. 。関数がコンパイルされると、それは不透明であり、内部構造は利用できません。できることは、二重引数で関数を呼び出して、二重の結果を取得することだけです。さらに、あなた Price
メソッドは、あなたに定義されていない操作を使用します Diff
とにかくクラス((\)
と Pow
).
それがあなたの目的に受け入れられるかどうかはわかりませんが、1つの考えられる選択肢は、あなたの一般的なインラインバージョンを書くことです Price
F#で機能し、ダブルまたはダブルまたは Diff
s(追加すると仮定します (\)
と Pow
オペレーター)。