0

C# と F# の間で自動微分を機能させるのに問題があります。

C# には、double を受け取って double を返す関数があります。

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 を Price(..) 関数に入力してタイプ Diff を生成する必要があります。次に、このタイプを Differente(..) 関数に入力して、別のタイプ Diff を返します。

ただし、私の C# 関数は double でのみ機能します (C# プログラムの他の場所で使用されているため、このままにしておきたいと思います)。

これを解決するために考えることができる唯一の方法は、すべての関数を 2 回記述することです。これは明らかにひどいものです。

1) 毎回差別化されたバージョンを書いたほうがいいかもしれません 2) これはあまり拡張可能なモデルではありません

これを回避する方法、または double 関数を Diff 関数 (できれば F#) に強制する方法はありますか。理想的には、(double -> double) 関数をスローして Diff.ToString() を取得したいだけです。

これが完全に曖昧であるか、理解できない場合は申し訳ありません。不明な点があればコメントで質問にお答えします。

これに対する解決策があることを願っています!前もって感謝します、

アシュリー

4

3 に答える 3

3

既存の C# 関数を使用する方法はありません。また、 type のメンバーを操作できる関数に持ち上げる簡単な方法もありませんDiff。関数がコンパイルされると不透明になり、内部構造は使用できなくなります。できることは、double 引数を指定して関数を呼び出し、double の結果を取得することだけです。さらに、メソッドは、とにかくクラスPriceで定義していない操作を使用します(および)。Diff(\)Pow

あなたの目的でそれが受け入れられるかどうかはわかりませんが、可能な代替策の 1 つはPrice、F# で関数の汎用インライン バージョンを作成することです。これは、double または s のいずれかで操作できます ( and演算子Diffを追加すると仮定します)。 .(\)Pow

于 2010-09-08T20:13:10.687 に答える
3

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 Expression Tree を作成するコードのように読めます。自動微分を実現するために、演算子のオーバーロードの代わりにソースコードの式ツリー変換を使用できますか?

于 2010-09-08T20:49:56.490 に答える