Domanda

Sto avendo un problema ottenere differenziazione automatica al lavoro tra C # e F #.

In C # Ho una funzione che prende un doppio e restituisce un double, dire:

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;
}

Ho scelto questa funzione particolare, come Math.pow è molto proibitivo, e consente solo un doppio del o int di per i suoi parametri.

Vorrei differenziare questa funzione utilizzando differenziazione automatica. Ho scritto il metodo per questo in 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"

Purtroppo, ho bisogno di alimentare un tipo Diff nel mio prezzo (..) la funzione di produrre un tipo di Diff, che poi viene immessa nella mia funzione Differente (..) per restituire un altro tipo Diff.

La mia funzione C # invece lavora unicamente su doppie (e vorrei che rimanga in questo modo, in quanto viene utilizzato in altri luoghi nel mio programma C #).

L'unico modo che posso pensare di risolvere questo è quello di scrivere ogni funzione due volte, che è ovviamente terribile come:

1) I può anche semplicemente scrivere una versione differenziata ogni volta 2) Questo non è un modello molto espandibile

Quindi non v'è alcun modo per aggirare il problema, o forse costringere le mie funzioni doppie in funzioni Diff (preferibilmente in F #). Idealmente vorrei solo per lanciare una. (Doppio -> doppia) in funzione e ottenere un Diff.ToString () fuori

Scusate se questo totalmente vaga o impossibile da capire. Io rispondere a qualsiasi domanda nei commenti, se questo non è chiaro.

spero che ci sia una soluzione per questo! Grazie in anticipo,

Ashley

È stato utile?

Soluzione

È possibile reinventare Haskell Tipo Classi:

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; }
}

Poi si può fare:

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"
}

E poi con:

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)))); }
    ...
}

Si può fare questo:

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;
}

Ma non è davvero carina.

In realtà, è quasi legge come codice che crea un albero LINQ Expression. Forse si può usare Il codice sorgente albero di espressione trasformazione al posto di l'overloading degli operatori per ottenere Automatic differenziazione

Altri suggerimenti

Non c'è alcun modo per utilizzare la funzione esistente C #, né v'è alcun modo semplice per sollevarlo a una funzione che potrebbe operare sui membri di tipo Diff. Una volta che la funzione è stato compilato è opaco e la struttura interna è unavaliable; tutto quello che puoi fare è chiamare la funzione con un doppio argomento e ottenere un doppio risultato. Inoltre, il tuo metodo Price usi operazioni che non hai nemmeno definiti sulla classe Diff comunque ((\) e Pow).

Non sono sicuro se sarebbe accettabile per i vostri scopi, ma una possibile alternativa sarebbe quella di scrivere una versione in linea generica della funzione Price in F #, che potrebbe poi operare su entrambi doppie o Diffs (supponendo che si aggiunge le (\) e Pow operatori).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top