patternMinor
Discount curve from instant rate
Viewed 0 times
curverateinstantdiscountfrom
Problem
This my first foray in F#, and I cannot think (yet) functional. I have implemented an interface for a discount curve and the implementation for a piecewise constant instant rate implementation.
I would like to have your opinion on how to make this more F#. Should I keep the second input of the constructor as an array or a sequence?
Also, as I pre-compute all possible values between the first point and the end_date, I could have done a tail recursion and lazily populate the cache, but I was wondering about efficiency: I did not have time to write the tail-recursion and do a timing comparison.
I would like to have your opinion on how to make this more F#. Should I keep the second input of the constructor as an array or a sequence?
Also, as I pre-compute all possible values between the first point and the end_date, I could have done a tail recursion and lazily populate the cache, but I was wondering about efficiency: I did not have time to write the tail-recursion and do a timing comparison.
module public DiscountCurve =
type IDiscountCurve =
abstract member Df : System.DateTime -> double
type DfPieceWiseInstant(end_date:System.DateTime, points:(System.DateTime * double)[]) =
let start_date = fst(points.[0])
let end_date = end_date
let cache : double array = Array.zeroCreate ((end_date - start_date).Days + 1)
let points = points
do
cache.[0] <- 1.
for idx in { 0 .. (points.Length - 1) } do
let cache_idx_start = max 1 (fst(points.[idx]) - start_date).Days
let cache_idx_end =
if idx+1 < points.Length then
(fst(points.[idx+1]) - start_date).Days - 1
else
(end_date - start_date).Days - 1
let cache_idx_df = exp (-snd(points.[idx])/365.)
for cache_date in seq { cache_idx_start .. cache_idx_end-1 } do
cache.[cache_date] <- cache.[cache_date-1] * cache_idx_df
interface IDiscountCurve with
member this.Df(date) =
cache.[(date - start_date).Days]Solution
I can't see how tail recursion comes into the picture exactly, but I would start with putting a stop watch around the
For starters, you certainly don't need let bindings for
A quick and simple way to delay populating of the cache until it's needed is to make it lazy.
This way it will only be populated once Df is called, and no work would be done on object's construction.
do that populates the cache and checking how much work it actually needs to do, just to see whether you couldn't get away with what you have now. There's certainly some value in computing only the part of the curve you need, but I'd check how much that would gain you before making that code more complicated.For starters, you certainly don't need let bindings for
end_date and points. You already have them accessible anywhere within your type as they're constructor arguments. You can also drop the {} and seq {} in you for ... in ... do expressions.A quick and simple way to delay populating of the cache until it's needed is to make it lazy.
let cache =
Lazy.Create
let cache = Array.zeroCreate ((end_date - start_date).Days + 1)
(* the entirety of your 'do' goes here *)
cache
interface IDiscountCurve with
member this.Df(date) =
cache.Value.[(date - start_date).Days]This way it will only be populated once Df is called, and no work would be done on object's construction.
Code Snippets
let cache =
Lazy.Create <| fun () ->
let cache = Array.zeroCreate ((end_date - start_date).Days + 1)
(* the entirety of your 'do' goes here *)
cache
interface IDiscountCurve with
member this.Df(date) =
cache.Value.[(date - start_date).Days]Context
StackExchange Code Review Q#58323, answer score: 2
Revisions (0)
No revisions yet.