C# 和 F# 中的自动区分
我在 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# 函数仅适用于双精度(我希望它保持这种方式,因为它在我的 C# 程序的其他地方使用)。
我能想到解决这个问题的唯一方法是将每个函数编写两次,这显然很糟糕:
1)我最好每次都编写一个不同的版本 2)这不是一个可扩展的模型
那么有什么方法可以解决这个问题,或者将我的双函数强制转换为 Diff 函数(最好在 F# 中)。理想情况下,我只想扔一个 (double -> double) 函数并获取 Diff.ToString() 。
抱歉,如果这完全模糊或无法理解。如果不清楚,我会在评论中回答任何问题。
我希望有一个解决方案!预先感谢,
阿什利
I am having a problem getting Automatic Differentiation to work between C# and F#.
In C# I have a function that takes a double and returns a double, say:
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 picked this function specifically, as the Math.pow is very prohibitive, and only allows a double's or int's for its parameters.
I would like to differentiate this function using Automatic Differentiation. I have written the method for this 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"
Unfortunately, I need to feed a type Diff into my Price(..) function to produce a type Diff, which then gets fed into my Differente(..) function to return another type Diff.
My C# function however works solely on doubles (and I would like it to stay this way, as it is used in other places in my C# program).
The only way I can think to solve this is to write every function twice, which is obviously awful as:
1) I may as well just write a differentiated version each time
2) This isn't a very expandable model
So is there any way I can get around this, or perhaps coerce my double functions into Diff functions (preferably in F#). Ideally I would just like to throw a (double -> double) function in and get a Diff.ToString() out.
Sorry if this totally vague or impossible to understand. I will answer any questions in comments if this is unclear.
I hope there is a solution for this! Thanks in advance,
Ashley
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你可以重新发明 Haskell 类型类:
然后你可以这样做:
然后用:
你可以这样做:
但这并不是很漂亮。
事实上,它读起来几乎就像创建 LINQ 表达式树的代码。也许你可以使用
源代码表达式树变换而不是运算符重载来实现自动微分?You can re-invent Haskell Type Classes:
Then you can do:
And then with:
You can do this:
But that's not really pretty.
In fact, it almost reads like code that creates a LINQ Expression Tree. Maybe you can use
Source codeExpression tree transformation instead of Operator overloading to achieve Automatic differentiation?无法使用现有的 C# 函数,也没有任何简单的方法将其提升为可以对
Diff
类型的成员进行操作的函数。一旦函数被编译,它是不透明的并且内部结构不可用;您所能做的就是使用双参数调用该函数并获得双结果。此外,您的Price
方法使用了您甚至还没有在Diff
类上定义的操作((\)
和Pow< /代码>)。
我不确定它是否适合您的目的,但一种可能的替代方案是在 F# 中编写
Price
函数的通用内联版本,然后可以对双精度数或进行操作>Diff
(假设您添加了(\)
和Pow
运算符)。There's no way to use your existing C# function, nor is there any easy way to lift it to a function that could operate on members of type
Diff
. Once the function has been compiled it is opaque and the internal structure is unavaliable; all you can do is call the function with a double argument and get a double result. Furthermore, yourPrice
method uses operations which you haven't even defined on yourDiff
class anyway ((\)
andPow
).I'm not sure if it would be acceptable for your purposes, but one possible alternative would be to write a generic inline version of your
Price
function in F#, which could then operate on either doubles orDiff
s (assuming that you add the(\)
andPow
operators).如果您只需要简单的自动微分,那么前面的“重新实现类型类”答案就完全是矫枉过正了。使用运算符重载并将导数具体化为数组,如我在此项目中所示。您需要的核心类型只是:
然后实现维基百科上显示的运算符翻译,所以Number 上的每个运算符也对 Derivatives 数组进行操作。
您需要将函数定义为对此
Number
类型进行操作,但通过在Number
上定义全套算术运算符,这通常只是更改参数类型,并更改对静态Math.X
函数的任何调用都会调用相应的Number.X
函数,即。Math.Sin(x)
->x.Sin()
。空/空数组主要对原始双精度数进行操作,因此它可能非常接近原始代码的速度。
The previous answers with "re-implementing type classes" are total overkill if you just need simple automatic differentiation. Use operator overloading and reify the derivatives as an array, as I show in this project. The core type you need is just:
Then implement the operator translations shown on Wikipedia, so each operator on Number also operates on the
Derivatives
array.You need to define your functions as operating on this
Number
type, but by defining the full suite of arithmetic operators onNumber
, this is usually just changing the parameter types, and changing any calls to the staticMath.X
functions to a correspondingNumber.X
function, ie.Math.Sin(x)
->x.Sin()
.A null/empty array would mostly be operating on raw doubles, so it could be pretty close to the speed of the original code.