Question

J'ai un problème pour obtenir automatique Différenciation au travail entre C # et F #.

En C # J'ai une fonction qui prend un double et retourne un double, par exemple:

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

Je pris cette fonction spécifique, comme Math.pow est très prohibitif, et permet seulement un double de ou int est pour ses paramètres.

Je voudrais différencier cette fonction à l'aide Différenciation automatique. Je l'ai écrit la méthode pour cela dans 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"

Malheureusement, je dois nourrir un type Diff dans mon prix (..) fonction pour produire un type Diff, qui est ensuite introduit dans ma fonction Differente (..) pour retourner un autre type Diff.

Mon C # fonction fonctionne cependant uniquement sur des doubles (et je voudrais qu'il reste de cette façon, car il est utilisé dans d'autres endroits dans mon programme C #).

La seule façon que je peux penser à résoudre ce problème est d'écrire toutes les fonctions deux fois, ce qui est évidemment terrible que:

1) je peux tout aussi bien écrire une version différenciée à chaque fois 2) Ceci est pas un modèle très extensible

est-il possible que je peux contourner ce problème, ou peut-être mes doubles fonctions contraindre en fonctions Diff (de préférence en F #). Idéalement, je voudrais juste jeter un (double -> double). Fonction et obtenir un Diff.ToString () sur

Désolé si cela tout à fait vague, voire impossible, de comprendre. Je répondrai à toutes les questions dans les commentaires si cela ne sait pas.

J'espère qu'il ya une solution pour cela! Merci à l'avance,

Ashley

Était-ce utile?

La solution

Vous pouvez réinventer les classes Haskell Type:

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

Ensuite, vous pouvez faire:

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

Et puis avec:

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

Vous pouvez faire ceci:

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

Mais ce n'est pas vraiment assez.

En fait, il se lit presque comme un code qui crée un arbre d'expression LINQ. Peut-être que vous pouvez utiliser Code source transformation de l'arbre d'expression au lieu de surcharge opérateur pour atteindre différenciation automatique

Autres conseils

Il n'y a aucun moyen d'utiliser votre fonction existante C #, ni il un moyen facile de le soulever à une fonction qui pourrait fonctionner sur les membres de type Diff. Une fois que la fonction a été compilé, il est opaque et la structure interne est unavaliable; tout ce que vous pouvez faire est d'appeler la fonction avec un argument de type double et d'obtenir un double résultat. En outre, votre méthode de Price utilise des opérations que vous avez même pas défini dans votre classe Diff de toute façon ((\) et Pow).

Je ne sais pas si ce serait acceptable à vos besoins, mais une alternative possible serait d'écrire une version en ligne générique de votre fonction Price en F #, qui pourrait alors fonctionner soit sur des doubles ou Diffs (en supposant que vous ajoutez les opérateurs de (\) et Pow).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top