Pregunta

Estoy teniendo problemas para conseguir la diferenciación automática de trabajo entre C # y F #.

En C # Tengo una función que toma un doble y devuelve un doble, por ejemplo:

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

I recogió esta función específica, como la Math.pow es muy prohibitivo, y sólo permite un doble de o int de para sus parámetros.

Me gustaría diferenciar esta función mediante la diferenciación automática. He escrito el método para esto en C #:

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"

Por desgracia, tengo que alimentar a un tipo de diferencias en función de mi Precio (..) para producir un tipo de diferencias, que luego se alimenta en función de mi Differente (..) para devolver otro tipo de diferencias.

Mi C # función embargo funciona únicamente en dobles (y me gustaría que se quede esta manera, ya que se utiliza en otros lugares en mi programa en C #).

La única manera que puedo pensar para resolver esto es escribir cada función dos veces, lo que obviamente es horrible como:

1) que puede que también acaba de escribir una versión diferenciada cada vez 2) Este no es un modelo muy expansible

Entonces, ¿hay alguna manera de evitar esto, o tal vez coaccionar a mis funciones dobles en funciones Diff (preferentemente en C #). Lo ideal sería igual a lanzar una (doble -> doble). Función en y obtener una Diff.ToString () fuera

Lo siento si esto totalmente vaga o imposible de entender. Voy a responder a cualquier pregunta en los comentarios si esto no está claro.

Espero que hay una solución para esto! Gracias de antemano,

Ashley

¿Fue útil?

Solución

Puede reinventar clases de Haskell Tipo:

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

A continuación, puede hacer:

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

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

Usted puede hacer esto:

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

Pero eso no es muy bonita.

De hecho, casi se lee como código que crea un árbol de expresión LINQ. Tal vez se puede utilizar código fuente transformación árbol de expresión en lugar de sobrecarga de operadores para lograr Automática diferenciación

Otros consejos

No hay manera de utilizar su función de C # existente, ni hay ninguna manera fácil de levantar a una función que podría operar sobre los miembros del tipo Diff. Una vez que la función se ha compilado es opaco y la estructura interna es Unavaliable; todo lo que puede hacer es llamar a la función con un doble argumento y obtener un doble resultado. Por otra parte, el método de Price usos operaciones que ni siquiera han definido en su clase Diff todos modos ((\) y Pow).

No estoy seguro de si sería aceptable para sus propósitos, pero una alternativa posible sería escribir una versión en línea genérica de su función Price en Fa #, lo que podría funcionar en dobles o Diffs (suponiendo que se agrega los (\) y Pow operadores).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top