Вопрос

У меня проблема с автоматической дифференциацией для работы между 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;
}

Я выбрал эту функцию конкретно, так как математика.

Я хотел бы дифференцировать эту функцию, используя автоматическую дифференциацию. Я написал метод для этого в 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 в свою цену (..) Функцию (..).

Моя функция C # однако работает исключительно на двойных местах (и я хотел бы, чтобы она оставалась таким образом, так как он используется в других местах в моей программе C #.

Единственный способ, которым я могу подумать, чтобы решить, это писать каждую функцию дважды, что, очевидно, ужасно, как:

1) я также могу просто написать дифференцированную версию каждый раз 2) Это не очень расширяемая модель

Итак, есть ли способ, которым я могу обойти это, или, возможно, принуждающуюся двумя двойными функциями в функции diff (желательно в f #). В идеале я бы просто хотел бы бросить (двойную>> двойную) функцию и получить 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).

Я не уверен, будет ли быть приемлемым для ваших целей, но одна возможная альтернатива будет написать общую встроенную версию вашего Price Функция в f #, которая затем может работать в удваиваниях или DiffS (предполагая, что вы добавляете (\) а также Pow операторы).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top