never executed always true always false
1 -- GENERATED by C->Haskell Compiler, version 0.28.8 Switcheroo, 25 November 2017 (Haskell)
2 -- Edit the ORIGNAL .chs file instead!
3
4
5 -- |Monte Carlo path generation ('pathGenerator'\/'sobolPathGenerator'\/'next'\/'asset') plus
6 -- 'lsmRegress', a standalone Longstaff-Schwartz early-exercise regression primitive.
7 --
8 -- === Custom early exercise with a Haskell payoff
9 --
10 -- 'lsmRegress' lets a Haskell-defined payoff drive early exercise, something no bound pricing
11 -- engine offers: every early-exercise engine in "QuantLib.PricingEngine" (e.g.
12 -- @mcAmericanEngine@) computes its payoff entirely on the C++ side against a bound @Payoff@.
13 -- 'lsmRegress' is pure regression -- it never sees a payoff at all, so it works for any
14 -- underlying-state-dependent early-exercise payoff, not just a vanilla put\/call. The pattern,
15 -- worked in full in @test\/example\/QuantLib\/Example\/AmericanLSM.hs@:
16 --
17 -- 1. Draw two path sets with 'pathGenerator': a /calibration/ set used only to fit each date's
18 -- regression, and a separate /pricing/ set evaluated against the frozen fit. Splitting the
19 -- sets avoids the in-sample bias a single-pass fit-and-price would have (the same reason
20 -- @mcAmericanEngine@ exposes its own @nCalibrationSamples@ parameter). Use a fixed nonzero
21 -- seed for each -- seed @0@ means \"seed from entropy\" for 'PseudoRandom'.
22 -- 2. Read out the state at every exercise date, across all paths, with 'asset' (or 'assetAt'),
23 -- and transpose ('Data.List.transpose') into one state list per exercise date.
24 -- 3. Walk exercise dates *strictly backward*. At each date:
25 --
26 -- * discount both the calibration and pricing cashflow vectors by the one-step discount
27 -- factor (@discount(t[i+1]) \/ discount(t[i])@ from the underlying yield curve);
28 -- * compute the Haskell payoff at this date for every path in both sets;
29 -- * restrict the regression's fit inputs to *in-the-money calibration paths only*
30 -- (@fitStates@\/@fitTargets@ below);
31 -- * call 'lsmRegress' twice against that one fit -- once evaluating at the calibration
32 -- states (to keep the backward recursion's own targets self-consistent), once at the
33 -- pricing states (the actual out-of-sample continuation-value estimate);
34 -- * exercise wherever @payoff > continuationValue@ (@max(exercise, continuation)@), on each
35 -- path set independently.
36 --
37 -- 4. The pricing set's cashflows, discounted all the way back and averaged, are the estimated
38 -- price. Never evaluate the fit on the calibration set's own state for the reported price --
39 -- that reintroduces the in-sample bias step 1 split the paths to avoid.
40 --
41 -- A rough sketch (see the full example for discounting, ITM filtering, and the backward
42 -- recursion itself):
43 --
44 -- > step df calibS priceS calibCF priceCF = do
45 -- > let calibTargets = map (* df) calibCF -- discount to this date
46 -- > (fitStates, fitTargets) = -- ITM calibration paths only
47 -- > unzip $ filter (inTheMoney . fst) $ zip calibS calibTargets
48 -- > contCalib <- lsmRegress Monomial order fitStates fitTargets calibS
49 -- > contPrice <- lsmRegress Monomial order fitStates fitTargets priceS
50 -- > -- exercise wherever payoff > continuation, on each path set
51 -- > ...
52 --
53 -- Validated in the example against both @mcAmericanEngine@ pricing the equivalent bound vanilla
54 -- option (same process\/grid\/seed) and the published Longstaff-Schwartz (2001) reference value
55 -- for the same benchmark fixture.
56 --
57 -- The same pattern extends to a Haskell-defined /basket/ payoff (several correlated underlyings)
58 -- via 'lsmRegressMulti' \/ 'lsmBasisSize' in place of 'lsmRegress': read each exercise date's state
59 -- for every underlying (still with 'asset'\/'assetAt', once per underlying) into a 'Matrix' of one
60 -- row per path, and guard the ITM-fit-size check with 'lsmBasisSize' instead of the basis order --
61 -- the multi-asset basis has combinatorially many more terms than the scalar case.
62 --
63 -- To keep a fit and evaluate it later, split the combined call: 'lsmFit' returns the basis
64 -- coefficients and 'lsmEvaluate' applies them to new states. Both pick the basis by the state
65 -- matrix's column count -- the scalar basis of 'lsmRegress' at one column, the basis of
66 -- 'lsmRegressMulti' at several -- and share the combined calls' native code, so within one build
67 -- fitting then evaluating gives the combined call's values bit for bit. Across builds the bits are
68 -- not promised: 'lsmEvaluatorIdentity' names the basis revision, QuantLib version, compiler and
69 -- architecture, so a stored fit can be refused elsewhere. It is necessary, not sufficient: a
70 -- library rebuilt under the same version string keeps it.
71 --
72 -- Both Chebyshev types are QuantLib's weighted bases, undefined outside (-1, 1): with a state there
73 -- the least-squares solve of every regression above does not return. Scale the states into that
74 -- interval or choose another 'PolynomialType'.
75 --
76 -- @test\/example\/QuantLib\/Example\/HaskellLSM.hs@ benchmarks 'lsmRegress' against the same
77 -- backward induction with the per-date regression reimplemented from scratch in plain Haskell
78 -- (QuantLib used only for path generation) -- a worked illustration of why this module exposes
79 -- the regression as a batched primitive instead of leaving callers to reinvent it.
80 --
81 -- === Finite-difference PDE solving
82 --
83 -- This module also binds a full-grid finite-difference (FDM) driver, built up across two related
84 -- issues (custom step-condition\/operator hooks, then custom inner-value calculators) and spread
85 -- across several functions with no single overview until now. Worked in full in
86 -- @test\/example\/QuantLib\/Example\/Fdm.hs@ -- every snippet below is a trimmed extract from that
87 -- file; read it end to end for the full picture (discounting, fixtures, imports).
88 --
89 -- In one sentence, for anyone new to FDM pricing: instead of an integral (Monte Carlo) or a
90 -- closed-form formula (an @analytic*Engine@), you discretize the underlying's state space (e.g.
91 -- log-spot) into a grid of points, put the option's payoff on the grid at maturity, and step it
92 -- /backward/ to today, solving a small local linear system at each timestep. Reach for it when you
93 -- need American\/Bermudan-style early exercise (a plain Monte Carlo run can't do backward induction
94 -- the way a grid can) or a process\/payoff with no closed-form price. If a bound @analytic*Engine@
95 -- or @mc*Engine@ already covers your case (see "QuantLib.PricingEngine"), prefer that instead --
96 -- it's simpler, and this module's own examples validate their FDM results against exactly those
97 -- engines.
98 --
99 -- ==== Walkthrough: which function do I actually want?
100 --
101 -- Start here rather than at the reference list below -- picking the right entry point up front
102 -- avoids reading five functions' haddock only to discover a sixth was the one you needed.
103 --
104 -- [@\"I have a grid already, just roll it back\"@] 'fdmRollback'. Supply the grid as a plain
105 -- @[Double]@ (one value per state, at maturity) plus three Haskell closures describing the PDE
106 -- operator, and get the same grid rolled back to today -- no mesher, no
107 -- 'FdmInnerValueCalculator', the simplest possible entry point:
108 --
109 -- > let grid0 = map (\x -> max (exp x - strike) 0) xs -- payoff at maturity, one value per grid point
110 -- > fdmEuro <- fdmRollback 1 applyFn applyDirFn solveFn Nothing [] Douglas grid0 tMat 0 nSteps 0
111 --
112 -- [@\"...and I need early exercise\"@] the same 'fdmRollback' call, plus a /step condition/: a
113 -- @t -> [Double] -> [Double]@ closure called once per outer timestep with the whole current grid,
114 -- returning it clamped to whatever the early-exercise rule requires:
115 --
116 -- > let stepCond _t u = zipWith max u grid0 -- American: value can never fall below intrinsic
117 -- > fdmAmerican <- fdmRollback 1 applyFn applyDirFn solveFn (Just stepCond) stepTimes Douglas grid0 tMat 0 nSteps 0
118 --
119 -- [@\"I'd rather not hand-build the initial grid myself\"@] 'fdmSolve' -- 'fdmRollback''s sibling.
120 -- Same operator\/step-condition\/scheme machinery, but the initial condition comes from an
121 -- 'FdmMesher' plus an 'FdmInnerValueCalculator' evaluated at each node, instead of a grid you
122 -- assembled by hand. Worth it once the mesher is doing real work (e.g. concentrating points near
123 -- a strike or barrier) rather than just wrapping a list you already had:
124 --
125 -- > mesh1d <- predefined1dMesher xs
126 -- > mesher <- fdmMesherComposite [mesh1d]
127 -- > let ivFn _t loc = case loc of [x] -> intrinsicAt x; _ -> error "expected a 1D location"
128 -- > withCustomFdmInnerValueCalculator mesher ivFn ivFn $ \calc ->
129 -- > fdmSolve mesher calc 1 applyFn applyDirFn solveFn Nothing [] Douglas tMat 0 nSteps 0
130 --
131 -- [@\"my payoff is a standard vanilla\/log payoff, I don't want a per-node callback\"@] skip
132 -- 'withCustomFdmInnerValueCalculator' and reach for one of the /native/ calculators instead --
133 -- QuantLib's own built-in 'FdmInnerValueCalculator' subclasses, bound directly so pricing a plain
134 -- payoff doesn't pay a Haskell round-trip per grid node:
135 --
136 -- > logCalc <- fdmLogInnerValue payoff mesher 0 -- striked payoff on a log-spot grid
137 -- > fdmLogEuro <- fdmSolve mesher logCalc 1 applyFn applyDirFn solveFn Nothing [] Douglas tMat 0 nSteps 0
138 --
139 -- 'fdmZeroInnerValue' (always 0), 'fdmCellAveragingInnerValue'\/'withCustomCellAveragingInnerValue'
140 -- (identity or custom @gridMapping@), and 'fdmLogInnerValue' (@gridMapping = exp@, the common case
141 -- on a log-spot grid) round out the set -- see the reference entries below for the exact
142 -- cell-averaging-vs-point-evaluation contract each one has. Reach for
143 -- 'withCustomFdmInnerValueCalculator' only once none of these fit your payoff shape.
144 --
145 -- [@\"my payoff depends on more than one underlying\"@] build one 'Fdm1dMesher' per underlying and
146 -- combine them with 'fdmMesherComposite'; 'fdmLogBasketInnerValue' takes a basket payoff (e.g.
147 -- @Max@, see "QuantLib.Instrument.Option") evaluated across all dimensions at once:
148 --
149 -- > basketMesher <- fdmMesherComposite [mesh1d, mesh1d] -- two correlated log-spot dimensions
150 -- > basketCalc <- fdmLogBasketInnerValue (Max payoff) basketMesher
151 -- > val <- fdmAvgInnerValue basketCalc basketMesher [i, j] tMat -- inspect one node directly
152 --
153 -- [@\"I want to price a swap\/swaption under a calibrated short-rate model\"@] the most specialized
154 -- entry points here: 'fdmAffineG2ModelSwapInnerValue'\/'fdmAffineHullWhiteModelSwapInnerValue'
155 -- drive the same calculator @fdG2SwaptionEngine@\/@fdHullWhiteSwaptionEngine@ already use
156 -- internally. Reach for these directly only when composing your own custom FDM pipeline around
157 -- this calculator; if a plain Bermudan-swaption NPV is all you need, prefer those two
158 -- already-bound black-box engines from "QuantLib.PricingEngine" instead.
159 --
160 -- [@\"I just want one node's value, no PDE solve\"@] 'fdmInnerValue'\/'fdmAvgInnerValue' evaluate
161 -- any bound calculator -- custom or native -- at a single mesher node directly, without
162 -- assembling a whole 'fdmSolve'. Handy as a sanity check while developing (as @Fdm.hs@'s own
163 -- tests do throughout), or whenever a single point's intrinsic value is all you actually need.
164 --
165 -- ==== Technical reference
166 --
167 -- The terse version of the above, for a reader who already knows the vocabulary and wants the
168 -- exact contract rather than the walkthrough's prose.
169 --
170 -- [@Rolling a grid back@] 'fdmRollback' takes a precomputed initial grid (a plain @[Double]@) and
171 -- rolls it back through time via three Haskell-defined operator callbacks
172 -- (@withFdmApply@ et al. below) plus an optional step condition (e.g.
173 -- American\/Bermudan early exercise). These callbacks cross the language boundary once per outer
174 -- timestep, over the /whole/ grid. 'fdmSolve' is the sibling that instead derives its own
175 -- initial grid from a mesher and
176 -- an 'FdmInnerValueCalculator' (below), reusing the same operator\/step-condition machinery.
177 --
178 -- [@Building a grid@] 'Fdm1dMesher's ('predefined1dMesher', 'uniform1dMesher',
179 -- 'concentrating1dMesher', 'fdmBlackScholesMesher', and the other process-specific meshers) each
180 -- describe one PDE dimension; 'fdmMesherComposite' combines one or more into the multi-dimensional
181 -- 'FdmMesher' 'fdmSolve' and 'FdmInnerValueCalculator' operate over. 'fdmMesherLocations' reads a
182 -- dimension's real-valued node locations back out, e.g. to map a flat result array back to
183 -- coordinates. 'gluedMesher' splices two 'Fdm1dMesher's end to end (e.g. a fine mesh near a
184 -- barrier glued to a coarse one further out) -- their ranges must already be ordered and
185 -- non-overlapping, and a shared boundary point is deduplicated automatically.
186 --
187 -- [@Custom inner values, fully general@] 'withCustomFdmInnerValueCalculator' wraps a Haskell
188 -- @t -> location -> value@ pair of functions as an 'FdmInnerValueCalculator'. Unlike every
189 -- callback above, this one crosses the language boundary once /per grid node/ -- there is no
190 -- batched shape for it anywhere in QuantLib or QuantLib-SWIG, so the real per-call cost is
191 -- accepted, matching QuantLib-SWIG's own @FdmInnerValueCalculatorDelegate@ precedent.
192 -- The calculator and native dependents retain both callbacks after the continuation returns;
193 -- callback exceptions are rethrown by the enclosing Haskell call.
194 --
195 -- [@Custom inner values, native@] QuantLib's own concrete 'FdmInnerValueCalculator' subclasses are
196 -- bound directly, for the common cases that don't need a per-node Haskell callback at all:
197 -- 'fdmZeroInnerValue' (always 0), 'fdmCellAveragingInnerValue'\/'fdmLogInnerValue' (a payoff
198 -- cell-averaged -- Simpson-integrated across each grid cell, not just evaluated at its center --
199 -- with an identity or @exp@ value mapping respectively), and 'fdmLogBasketInnerValue' (the
200 -- multi-asset counterpart, one @exp@ mapping per dimension). These retain their payoff,
201 -- including any Haskell callback it owns. There is also
202 -- 'withCustomCellAveragingInnerValue', the one native constructor that /does/ take an explicit
203 -- @gridMapping@ callback, retained by the native calculator. 'fdmAffineG2ModelSwapInnerValue'\/'fdmAffineHullWhiteModelSwapInnerValue' price a swap
204 -- under a calibrated 'QuantLib.Model.G2'\/'QuantLib.Model.HullWhite' model directly -- the same
205 -- calculator @fdG2SwaptionEngine@\/@fdHullWhiteSwaptionEngine@ use internally.
206 --
207 -- [@Inspecting a calculator directly@] 'fdmInnerValue'\/'fdmAvgInnerValue' evaluate any bound
208 -- calculator (custom or native) at a single mesher node, without assembling a whole 'fdmSolve' --
209 -- useful for a targeted self-consistency check, as @Fdm.hs@'s own tests do throughout.
210 --
211 -- === What's deliberately not bound: operators, schemes, boundary conditions
212 --
213 -- QuantLib-SWIG also exposes QuantLib's concrete 'FdmLinearOpComposite' subclasses (@FdmBlackScholesOp@,
214 -- @FdmHestonOp@, @FdmG2Op@, ...), its scheme objects (@DouglasScheme@, @CraigSneydScheme@,
215 -- @HundsdorferScheme@, ...), and its @FdmBoundaryCondition@ family as real C++ objects. hasquant does
216 -- not mirror these, and won't by default -- it's a design boundary already crossed once, not a gap.
217 --
218 -- 'fdmRollback'\/'fdmSolve' take the operator, the implicit-solve step, and the scheme all as Haskell
219 -- closures instead (@applyFn@\/@applyDirFn@\/@solveFn@ above). That's the same "coarsen the
220 -- language-boundary crossing" call already made for step conditions: bind the reusable numerical
221 -- /primitive/ (rollback through a fixed timestep, of an arbitrary tridiagonal\/multi-dimensional
222 -- operator) and let Haskell drive it, rather than bind every concrete operator\/scheme QuantLib ships
223 -- as its own object. @test\/example\/QuantLib\/Example\/Fdm.hs@'s hand-rolled 'operatorBands'\/'applyOp'
224 -- /is/ the replacement for @FdmBlackScholesOp@ + @DouglasScheme@, not a stand-in waiting for those to
225 -- get bound -- pricing a new payoff\/process combination here means writing its operator once in
226 -- Haskell, not calling into fifteen QuantLib operator classes one by one.
227 --
228 -- Binding the operator\/scheme family as objects would add a second, redundant way to drive the same
229 -- 'fdmSolve'\/'fdmRollback' backbone, without extending what's actually solvable -- anything a bound
230 -- @FdmXxxOp@ could do, a Haskell @applyFn@ already can. Revisit only if a concrete need shows up that
231 -- the callback shape genuinely can't express (none has, so far).
232 module QuantLib.Method
233 (
234 -- * Types
235 -- ** Path and random sequences
236 PathGenerator
237 , SamplePath
238 , GaussianRsg
239
240 -- ** Finite differences
241 , Fdm1dMesher
242 , FdmMesher
243 , FdmInnerValueCalculator
244
245 -- * Constructors
246 -- ** Path generation
247 , pathGenerator
248 , sobolPathGenerator
249 -- ** Random sequence generation
250 , gaussianRsg
251 , sobolGaussianRsg
252 -- ** Finite-difference meshers
253 , predefined1dMesher
254 , uniform1dMesher
255 , concentrating1dMesher
256 , concentrating1dMesherMulti
257 , gluedMesher
258 , fdmBlackScholesMesher
259 , fdmCev1dMesher
260 , exponentialJump1dMesher
261 , fdmSimpleProcess1dMesher
262 , fdmHestonVarianceMesher
263 , fdmHestonLocalVolatilityVarianceMesher
264 , fdmMesherComposite
265 -- ** Finite-difference inner-value calculators
266 , withCustomFdmInnerValueCalculator
267 , fdmZeroInnerValue
268 , fdmCellAveragingInnerValue
269 , withCustomCellAveragingInnerValue
270 , fdmLogInnerValue
271 , fdmLogBasketInnerValue
272 , fdmAffineG2ModelSwapInnerValue
273 , fdmAffineHullWhiteModelSwapInnerValue
274
275 -- * Inspectors
276 -- ** Path and random sequences
277 , next
278 , antithetic
279 , nextSequence
280 -- ** Longstaff-Schwartz regression
281 , lsmRegress
282 , lsmBasisSize
283 , lsmRegressMulti
284 , lsmFit
285 , lsmEvaluate
286 , lsmEvaluatorIdentity
287 -- ** Finite differences
288 , fdmRollback
289 , fdmInnerValue
290 , fdmAvgInnerValue
291 , fdmSolve
292 -- ** Paths
293 , weight
294 , assetNumber
295 , pathSize
296 , assetAt
297 , asset
298 -- ** Random sequences and meshers
299 , rsgDimension
300 , lastSequence
301 , pathGeneratorSequence
302 , fdmMesherLocations
303 ) where
304 import qualified Foreign.C.Types as C2HSImp
305 import qualified Foreign.ForeignPtr as C2HSImp
306 import qualified Foreign.Marshal.Utils as C2HSImp
307 import qualified Foreign.Ptr as C2HSImp
308 import qualified System.IO.Unsafe as C2HSImp
309
310
311
312
313
314
315
316 import QuantLib.Internal
317 import qualified QuantLib.Internal.Callback as Callback
318 import QuantLib.Internal.Type hiding (ptr) -- c2hs {#get#} binds its own `ptr'
319 import QuantLib.Internal.Common
320 import QuantLib.Math
321
322 import Foreign.C.String(peekCString)
323 import Foreign.C.Types(CDouble)
324 import Foreign.Ptr(Ptr, nullPtr, castPtr)
325 import Foreign.Marshal.Alloc(alloca)
326 import Foreign.Marshal.Array(moveArray)
327 import Control.Exception(throwIO)
328 import qualified Data.Vector.Storable as V
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 -- A step condition may return its borrowed input, which shares the output buffer.
370 pokeFdmResult :: Int -> Ptr CDouble -> RealVector -> IO ()
371 pokeFdmResult expected out result
372 | V.length result /= expected = throwIO (CallbackResultLength expected (V.length result))
373 | otherwise = V.unsafeWith result $ \p -> moveArray out (castPtr p) expected
374
375 withFdmResult :: (Callback.CallbackArgs -> RealVector -> RealVector) -> (Ptr () -> IO b) -> IO b
376 withFdmResult f use = Callback.withCallback call (`withCallbackPtr` use)
377 where
378 call args = do
379 x <- borrowRealVector (Callback.callbackInput args) (fromIntegral (Callback.callbackSize args))
380 pokeFdmResult (Callback.callbackSize args) (Callback.callbackOutput args) (f args x)
381
382 withFdmApply :: ((Double, Double) -> RealVector -> RealVector) -> (Ptr () -> IO b) -> IO b
383 withFdmApply f = withFdmResult $ \args -> f (Callback.callbackTime1 args, Callback.callbackTime2 args)
384
385 withFdmApplyDirection :: (Int -> (Double, Double) -> RealVector -> RealVector) -> (Ptr () -> IO b) -> IO b
386 withFdmApplyDirection f = withFdmResult $ \args ->
387 f (Callback.callbackDirection args) (Callback.callbackTime1 args, Callback.callbackTime2 args)
388
389 withFdmSolveSplitting :: (Int -> Double -> (Double, Double) -> RealVector -> RealVector) -> (Ptr () -> IO b) -> IO b
390 withFdmSolveSplitting f = withFdmResult $ \args ->
391 f (Callback.callbackDirection args) (Callback.callbackScalar args) (Callback.callbackTime1 args, Callback.callbackTime2 args)
392
393 withMaybeFdmStepCondition :: Maybe (Double -> RealVector -> RealVector) -> (Ptr () -> IO b) -> IO b
394 withMaybeFdmStepCondition Nothing use = use nullPtr
395 withMaybeFdmStepCondition (Just f) use = withFdmResult (f . Callback.callbackTime1) use
396
397 -- |build a multi-asset path generator driven by a pseudo-random number generator (Mersenne Twister, Poisson, or Ziggurat, chosen by the RNG trait) over the given process and time grid.
398 pathGenerator :: (RngTrait) -> (GenStochasticProcess p) -> (TimeGrid) -> (Word) -- ^seed
399 -> (Word) -- ^dimension
400 -> (Bool) -- ^brownian bridge
401 -> IO ((PathGenerator))
402 pathGenerator a1 a2 a3 a4 a5 a6 =
403 let {a1' = fromEnumC a1} in
404 withStochasticProcess a2 $ \a2' ->
405 withTimeGrid a3 $ \a3' ->
406 let {a4' = fromIntegral a4} in
407 let {a5' = fromIntegral a5} in
408 let {a6' = C2HSImp.fromBool a6} in
409 preErrorCheck $ \a7' ->
410 pathGenerator'_ a1' a2' a3' a4' a5' a6' a7' >>= \res ->
411 peekPathGenerator res >>= \res' ->
412 errorCheck a7'>>
413 return (res')
414
415
416
417 -- |build a multi-asset path generator driven by a low-discrepancy (Sobol) sequence, using the given direction integers, over the given process and time grid.
418 sobolPathGenerator :: (SobolDirectionIntegers) -> (GenStochasticProcess p) -> (TimeGrid) -> (Word) -- ^seed
419 -> (Word) -- ^dimension
420 -> (Bool) -- ^brownian bridge
421 -> IO ((PathGenerator))
422 sobolPathGenerator a1 a2 a3 a4 a5 a6 =
423 let {a1' = fromEnumC a1} in
424 withStochasticProcess a2 $ \a2' ->
425 withTimeGrid a3 $ \a3' ->
426 let {a4' = fromIntegral a4} in
427 let {a5' = fromIntegral a5} in
428 let {a6' = C2HSImp.fromBool a6} in
429 preErrorCheck $ \a7' ->
430 sobolPathGenerator'_ a1' a2' a3' a4' a5' a6' a7' >>= \res ->
431 peekPathGenerator res >>= \res' ->
432 errorCheck a7'>>
433 return (res')
434
435
436
437 -- |The gaussian sequence generator a 'pathGenerator' drives its evolution with, exposed on its own
438 -- so a Haskell-defined SDE can be simulated with no FFI call in the inner loop -- the same
439 -- decomposition 'lsmRegress' applies to @LongstaffSchwartzPathPricer@, one level lower down.
440 --
441 -- QuantLib's @StochasticProcess@ has no Haskell-subclassable hook here by design: @MultiPathGenerator@
442 -- (which 'pathGenerator' wraps) calls @process->evolve@ once per timestep /per path/, so binding
443 -- that virtual as a callback would put an FFI crossing in the hottest loop there is. Drawing the
444 -- normals with 'nextSequence' and writing @evolve@ in Haskell instead costs one crossing per
445 -- /path/, and the result composes with 'lsmRegress' into a complete custom-SDE American Monte
446 -- Carlo. The trade-off is that the result is a set of paths, not a @StochasticProcess@ object, so
447 -- it cannot be fed to 'fdmSimpleProcess1dMesher' or to a pricing engine -- but no stock QuantLib
448 -- engine would have accepted a custom process anyway: their constructors are typed on concrete
449 -- process classes (@GeneralizedBlackScholesProcess@ and friends), not on the abstract base.
450 --
451 -- @dimension@ is the length of each drawn sequence: (normals drawn per step) * timesteps. For
452 -- 'pathGenerator' parity the per-step count is the process's @factors@; a Haskell-evolved model
453 -- may draw more normals per step than it has Brownian drivers. The construction mirrors
454 -- 'pathGenerator''s exactly (same trait, same seed, same direction integers), so a
455 -- Haskell-evolved path can be compared draw for draw against a 'pathGenerator' one on a bound
456 -- process.
457 gaussianRsg :: (RngTrait) -> (Word) -- ^dimension
458 -> (Word) -- ^seed
459 -> IO ((GaussianRsg))
460 gaussianRsg a1 a2 a3 =
461 let {a1' = fromEnumC a1} in
462 let {a2' = fromIntegral a2} in
463 let {a3' = fromIntegral a3} in
464 preErrorCheck $ \a4' ->
465 gaussianRsg'_ a1' a2' a3' a4' >>= \res ->
466 peekGaussianRsg res >>= \res' ->
467 errorCheck a4'>>
468 return (res')
469
470
471
472 -- |'gaussianRsg' driven by a low-discrepancy (Sobol) sequence with the given direction integers --
473 -- the 'sobolPathGenerator' counterpart. The maximum @dimension@ depends on the direction-integer
474 -- set and on QuantLib's build-time @PPMT_MAX_DIM@; a larger one raises an exception.
475 sobolGaussianRsg :: (SobolDirectionIntegers) -> (Word) -- ^dimension
476 -> (Word) -- ^seed
477 -> IO ((GaussianRsg))
478 sobolGaussianRsg a1 a2 a3 =
479 let {a1' = fromEnumC a1} in
480 let {a2' = fromIntegral a2} in
481 let {a3' = fromIntegral a3} in
482 preErrorCheck $ \a4' ->
483 sobolGaussianRsg'_ a1' a2' a3' a4' >>= \res ->
484 peekGaussianRsg res >>= \res' ->
485 errorCheck a4'>>
486 return (res')
487
488
489
490 -- |the length of each sequence the generator draws.
491 rsgDimension :: (GaussianRsg) -> (Word)
492 rsgDimension a1 =
493 C2HSImp.unsafePerformIO $
494 withGaussianRsg a1 $ \a1' ->
495 rsgDimension'_ a1' >>= \res ->
496 let {res' = fromIntegral res} in
497 return (res')
498
499
500
501 -- |draw the next sequence of standard normal variates, with its sample weight (1 for every trait
502 -- bound here, carried through for symmetry with 'weight').
503 nextSequence :: (GaussianRsg) -> IO ((RealVector), (Double))
504 nextSequence a1 =
505 withGaussianRsg a1 $ \a1' ->
506 preDoubleArray $ \(a2'1, a2'2) ->
507 alloca $ \a3' ->
508 preErrorCheck $ \a4' ->
509 nextSequence'_ a1' a2'1 a2'2 a3' a4' >>
510 peekRealVector a2'1 a2'2>>= \a2'' ->
511 peekDouble a3'>>= \a3'' ->
512 errorCheck a4'>>
513 return (a2'', a3'')
514
515
516
517 -- |re-read the sequence 'nextSequence' last drew, without advancing the generator.
518 lastSequence :: (GaussianRsg) -> IO ((RealVector), (Double))
519 lastSequence a1 =
520 withGaussianRsg a1 $ \a1' ->
521 preDoubleArray $ \(a2'1, a2'2) ->
522 alloca $ \a3' ->
523 preErrorCheck $ \a4' ->
524 lastSequence'_ a1' a2'1 a2'2 a3' a4' >>
525 peekRealVector a2'1 a2'2>>= \a2'' ->
526 peekDouble a3'>>= \a3'' ->
527 errorCheck a4'>>
528 return (a2'', a3'')
529
530
531
532 -- |The random sequence consumed by the last 'next', with its sample weight, without advancing
533 -- the generator. Refuses before the first draw. These are variates before process correlation;
534 -- 'antithetic' uses their negatives and leaves this original sequence unchanged.
535 pathGeneratorSequence :: (PathGenerator) -- ^generator
536 -> IO ((RealVector), (Double))
537 pathGeneratorSequence a1 =
538 withPathGenerator a1 $ \a1' ->
539 preDoubleArray $ \(a2'1, a2'2) ->
540 alloca $ \a3' ->
541 preErrorCheck $ \a4' ->
542 pathGeneratorSequence'_ a1' a2'1 a2'2 a3' a4' >>
543 peekRealVector a2'1 a2'2>>= \a2'' ->
544 peekDouble a3'>>= \a3'' ->
545 errorCheck a4'>>
546 return (a2'', a3'')
547
548
549
550 -- |draw the next weighted sample path from the generator.
551 next :: (PathGenerator) -> IO ((SamplePath))
552 next a1 =
553 withPathGenerator a1 $ \a1' ->
554 preErrorCheck $ \a2' ->
555 next'_ a1' a2' >>= \res ->
556 peekSamplePath res >>= \res' ->
557 errorCheck a2'>>
558 return (res')
559
560
561
562 -- |draw the antithetic (sign-flipped) counterpart of the last drawn sample path.
563 antithetic :: (PathGenerator) -> IO ((SamplePath))
564 antithetic a1 =
565 withPathGenerator a1 $ \a1' ->
566 preErrorCheck $ \a2' ->
567 antithetic'_ a1' a2' >>= \res ->
568 peekSamplePath res >>= \res' ->
569 errorCheck a2'>>
570 return (res')
571
572
573
574 -- |the weight associated with a sample path.
575 weight :: (SamplePath) -> (Double)
576 weight a1 =
577 C2HSImp.unsafePerformIO $
578 withSamplePath a1 $ \a1' ->
579 weight'_ a1' >>= \res ->
580 let {res' = realToFrac res} in
581 return (res')
582
583
584
585 -- |the number of correlated asset paths in a sample.
586 assetNumber :: (SamplePath) -> (Word)
587 assetNumber a1 =
588 C2HSImp.unsafePerformIO $
589 withSamplePath a1 $ \a1' ->
590 assetNumber'_ a1' >>= \res ->
591 let {res' = fromIntegral res} in
592 return (res')
593
594
595
596 -- |the number of time steps in each asset path of a sample.
597 pathSize :: (SamplePath) -> (Word)
598 pathSize a1 =
599 C2HSImp.unsafePerformIO $
600 withSamplePath a1 $ \a1' ->
601 pathSize'_ a1' >>= \res ->
602 let {res' = fromIntegral res} in
603 return (res')
604
605
606
607 -- |the value of one asset's path at a given time step.
608 assetAt :: (SamplePath) -> (Word) -- ^asset
609 -> (Word) -- ^point
610 -> IO ((Double))
611 assetAt a1 a2 a3 =
612 withSamplePath a1 $ \a1' ->
613 let {a2' = fromIntegral a2} in
614 let {a3' = fromIntegral a3} in
615 preErrorCheck $ \a4' ->
616 assetAt'_ a1' a2' a3' a4' >>= \res ->
617 let {res' = realToFrac res} in
618 errorCheck a4'>>
619 return (res')
620
621
622
623 -- |The full simulated path (values at every time step) of a single asset.
624 asset :: (SamplePath) -> (Word) -> IO ((RealVector))
625 asset a1 a2 =
626 withSamplePath a1 $ \a1' ->
627 let {a2' = fromIntegral a2} in
628 preDoubleArray $ \(a3'1, a3'2) ->
629 preErrorCheck $ \a4' ->
630 asset'_ a1' a2' a3'1 a3'2 a4' >>
631 peekRealVector a3'1 a3'2>>= \a3'' ->
632 errorCheck a4'>>
633 return (a3'')
634
635
636
637 -- |one step of Longstaff-Schwartz early-exercise regression: fit a polynomial basis of the given
638 -- order/type against the (in-the-money) fit states and their continuation targets, then evaluate the
639 -- fitted continuation value at each of the given eval states. This is the same per-exercise-date
640 -- regression @LongstaffSchwartzPathPricer@ performs internally against a bound @Payoff@, exposed so it
641 -- can be driven from a Haskell-defined payoff instead: call it once per exercise date, walking dates
642 -- strictly backward, batched across all paths rather than per path. See this module's header for the
643 -- full backward-induction pattern.
644 lsmRegress :: (PolynomialType) -> (Word) -- ^basis order
645 -> (RealVector) -- ^fit states (in-the-money paths only)
646 -> (RealVector) -- ^fit targets (continuation value at these states)
647 -> (RealVector) -- ^eval states (all paths' state at this date)
648 -> IO ((RealVector))
649 lsmRegress a1 a2 a3 a4 a5 =
650 let {a1' = (fromIntegral . fromEnum) a1} in
651 let {a2' = fromIntegral a2} in
652 withRealVector a3 $ \(a3'1, a3'2) ->
653 withRealVector a4 $ \(a4'1, a4'2) ->
654 withRealVector a5 $ \(a5'1, a5'2) ->
655 preDoubleArray $ \(a6'1, a6'2) ->
656 preErrorCheck $ \a7' ->
657 lsmRegress'_ a1' a2' a3'1 a3'2 a4'1 a4'2 a5'1 a5'2 a6'1 a6'2 a7' >>
658 peekRealVector a6'1 a6'2>>= \a6'' ->
659 errorCheck a7'>>
660 return (a6'')
661
662
663
664 -- |number of basis terms 'lsmRegressMulti' fits for a given number of underlyings and order --
665 -- @C(dim+order, order)@, the binomial coefficient @LsmBasisSystem::multiPathBasisSystem@ actually
666 -- returns (not @order+1@, which only coincides at @dim=1@ -- 'lsmRegress' uses that special case
667 -- directly rather than calling this). Use it to size the \"enough in-the-money calibration paths to
668 -- fit\" guard before calling 'lsmRegressMulti': the underlying least-squares solve requires at least
669 -- this many fit rows, and undershooting it throws rather than returning a degenerate fit.
670 lsmBasisSize :: Word -> Word -> Word
671 lsmBasisSize dim order = fromInteger $ binomial (toInteger dim + toInteger order) (toInteger order)
672 where binomial n k = product [n - k + 1 .. n] `div` product [1 .. k]
673
674 -- |multi-asset counterpart of 'lsmRegress', for a Haskell-defined basket (several correlated
675 -- underlyings) early-exercise payoff -- 'lsmRegress' itself only regresses against one state
676 -- variable. Fit\/eval states are contiguous row-major 'RealMatrix' values: one row per path, one column per underlying, and the
677 -- two matrices' column counts must agree. Regresses against
678 -- @LsmBasisSystem::multiPathBasisSystem@'s combinatorial basis; see 'lsmBasisSize' for its size and
679 -- this module's header for the surrounding backward-induction pattern (identical to the scalar case,
680 -- just with 'Matrix'-shaped states).
681 lsmRegressMulti :: PolynomialType -> Word -> RealMatrix -- ^fit states (in-the-money paths only)
682 -> RealVector -- ^fit targets (continuation value at these states)
683 -> RealMatrix -- ^eval states (all paths' state at this date)
684 -> IO RealVector -- ^continuation value estimate per eval row
685 lsmRegressMulti p order (RealMatrix fr fc fd) t (RealMatrix er ec ed) = qlLsmRegressMulti p order fr fc fd t er ec ed
686 qlLsmRegressMulti :: (PolynomialType) -> (Word) -- ^basis order
687 -> (Word) -- ^fit rows
688 -> (Word) -- ^fit columns (underlyings)
689 -> (RealVector) -- ^fit states, row-major
690 -> (RealVector) -- ^fit targets
691 -> (Word) -- ^eval rows
692 -> (Word) -- ^eval columns (underlyings)
693 -> (RealVector) -- ^eval states, row-major
694 -> IO ((RealVector))
695 qlLsmRegressMulti a1 a2 a3 a4 a5 a6 a7 a8 a9 =
696 let {a1' = (fromIntegral . fromEnum) a1} in
697 let {a2' = fromIntegral a2} in
698 let {a3' = fromIntegral a3} in
699 let {a4' = fromIntegral a4} in
700 withRealVectorRaw a5 $ \a5' ->
701 withRealVector a6 $ \(a6'1, a6'2) ->
702 let {a7' = fromIntegral a7} in
703 let {a8' = fromIntegral a8} in
704 withRealVectorRaw a9 $ \a9' ->
705 preDoubleArray $ \(a10'1, a10'2) ->
706 preErrorCheck $ \a11' ->
707 qlLsmRegressMulti'_ a1' a2' a3' a4' a5' a6'1 a6'2 a7' a8' a9' a10'1 a10'2 a11' >>
708 peekRealVector a10'1 a10'2>>= \a10'' ->
709 errorCheck a11'>>
710 return (a10'')
711
712
713
714 -- |basis coefficients of one Longstaff-Schwartz fit, the fitting half of 'lsmRegress' (one state
715 -- column) or 'lsmRegressMulti' (several): fit states are a row-major 'RealMatrix', one row per
716 -- path. There are 'lsmBasisSize' of them, in QuantLib's basis order; evaluate them with 'lsmEvaluate'.
717 lsmFit :: PolynomialType -> Word -> RealMatrix -- ^fit states (in-the-money paths only)
718 -> RealVector -- ^fit targets (continuation value at these states)
719 -> IO RealVector -- ^basis coefficients
720 lsmFit p order (RealMatrix r c d) = qlLsmFit p order r c d
721 qlLsmFit :: (PolynomialType) -> (Word) -- ^basis order
722 -> (Word) -- ^rows
723 -> (Word) -- ^columns
724 -> (RealVector) -- ^states, row-major
725 -> (RealVector) -- ^targets
726 -> IO ((RealVector))
727 qlLsmFit a1 a2 a3 a4 a5 a6 =
728 let {a1' = (fromIntegral . fromEnum) a1} in
729 let {a2' = fromIntegral a2} in
730 let {a3' = fromIntegral a3} in
731 let {a4' = fromIntegral a4} in
732 withRealVectorRaw a5 $ \a5' ->
733 withRealVector a6 $ \(a6'1, a6'2) ->
734 preDoubleArray $ \(a7'1, a7'2) ->
735 preErrorCheck $ \a8' ->
736 qlLsmFit'_ a1' a2' a3' a4' a5' a6'1 a6'2 a7'1 a7'2 a8' >>
737 peekRealVector a7'1 a7'2>>= \a7'' ->
738 errorCheck a8'>>
739 return (a7'')
740
741
742
743 -- |continuation value of 'lsmFit' coefficients at each row of the given states, which must have
744 -- the fit's column count; the polynomial type and order must be the fit's too. Throws unless there
745 -- are 'lsmBasisSize' coefficients for that column count.
746 lsmEvaluate :: PolynomialType -> Word -> RealVector -- ^coefficients
747 -> RealMatrix -- ^eval states (one row per path)
748 -> IO RealVector -- ^continuation value estimate per row
749 lsmEvaluate p order coefficients (RealMatrix r c d) = qlLsmEvaluate p order coefficients r c d
750 qlLsmEvaluate :: (PolynomialType) -> (Word) -- ^basis order
751 -> (RealVector) -- ^coefficients
752 -> (Word) -- ^rows
753 -> (Word) -- ^columns
754 -> (RealVector) -- ^states, row-major
755 -> IO ((RealVector))
756 qlLsmEvaluate a1 a2 a3 a4 a5 a6 =
757 let {a1' = (fromIntegral . fromEnum) a1} in
758 let {a2' = fromIntegral a2} in
759 withRealVector a3 $ \(a3'1, a3'2) ->
760 let {a4' = fromIntegral a4} in
761 let {a5' = fromIntegral a5} in
762 withRealVectorRaw a6 $ \a6' ->
763 preDoubleArray $ \(a7'1, a7'2) ->
764 preErrorCheck $ \a8' ->
765 qlLsmEvaluate'_ a1' a2' a3'1 a3'2 a4' a5' a6' a7'1 a7'2 a8' >>
766 peekRealVector a7'1 a7'2>>= \a7'' ->
767 errorCheck a8'>>
768 return (a7'')
769
770
771
772 -- |the build that 'lsmFit' and 'lsmEvaluate' belong to: the shim's basis revision, the QuantLib
773 -- version, the compiler and the architecture. Store it beside coefficients meant for later use.
774 lsmEvaluatorIdentity :: (String)
775 lsmEvaluatorIdentity =
776 C2HSImp.unsafePerformIO $
777 lsmEvaluatorIdentity'_ >>= \res ->
778 peekCString res >>= \res' ->
779 return (res')
780
781
782
783 -- |Drive @FdmBackwardSolver::rollback@ with a Haskell-defined 'FdmLinearOpComposite' (the
784 -- @apply@\/@apply_direction@\/@solve_splitting@ callbacks) and an optional Haskell-defined step
785 -- condition (e.g. American\/Bermudan early exercise, or a barrier), instead of a bound mesher +
786 -- @FdmInnerValueCalculator@ as every concrete FDM pricing engine in "QuantLib.PricingEngine"
787 -- uses. This coarsened callback shape is modeled on QuantLib-SWIG's
788 -- @FdmLinearOpCompositeDelegate@\/
789 -- @FdmStepConditionDelegate@ (@SWIG\/fdm.i@): each callback crosses once per outer iteration over
790 -- the whole grid array, not once per grid node.
791 -- Internally each callback receives one native argument record, avoiding a wide mixed-argument
792 -- callback ABI at the Haskell boundary; this does not affect the public callback types.
793 --
794 -- The grid is a plain @[Double]@ in and out -- no mesher, no @FdmInnerValueCalculator@, no
795 -- @FdmSolverDesc@ is bound; callers manage their own grid geometry entirely in Haskell. Boundary
796 -- conditions are always the empty @FdmBoundaryConditionSet()@ (not bound). Every callback must
797 -- return an array of its input's length; any other length throws 'QuantLib.Context.CallbackResultLength'.
798 --
799 -- /Only DouglasScheme::step's three virtuals are implemented -- 'apply', 'apply_direction' and/
800 -- /'solve_splitting'; @apply_mixed@\/@preconditioner@ are unimplemented and @QL_FAIL@ at the C++/
801 -- /level if called./ This makes 'fdmRollback' safe to drive with 'QuantLib.Internal.Common.Douglas'
802 -- or 'QuantLib.Internal.Common.CrankNicolson' in one dimension (the two schemes
803 -- @DouglasScheme::step@ itself is used for) -- anything needing mixed derivatives across more than
804 -- one PDE direction (Craig-Sneyd, Hundsdorfer, or any genuinely multi-dimensional operator) will
805 -- throw partway through 'fdmRollback' rather than silently mispricing.
806 fdmRollback :: (Int) -- ^number of PDE directions\/dimensions the operator has (e.g. 1 for a 1D Black-Scholes-in-log-spot operator) -- /not/ the grid array length, which is the length of every @[Double]@ passed to\/returned from the callbacks below
807 -> ((Double,Double) -> RealVector -> RealVector) -- ^@apply(r)@: whole-grid operator application at the current @(t1,t2)@ time pair (no direction argument -- QuantLib's own 'FdmLinearOp' base method)
808 -> (Int -> (Double,Double) -> RealVector -> RealVector) -- ^@apply_direction(direction, r)@
809 -> (Int -> Double -> (Double,Double) -> RealVector -> RealVector) -- ^@solve_splitting(direction, r, s)@ -- the implicit per-direction solve (e.g. a tridiagonal\/Thomas-algorithm solve for a 1D operator)
810 -> (Maybe (Double -> RealVector -> RealVector)) -- ^optional step condition @applyTo(a, t)@, e.g. American\/Bermudan early exercise (@max(a_i, intrinsic_i)@ at every step) or a barrier knockout
811 -> (RealVector) -- ^stopping times at which the step condition above is applied (ignored if there is no step condition); pass every rollback step's time to apply it at every step
812 -> (FdmScheme) -- ^the finite-difference scheme (see the haddock above for which schemes are actually safe to use here)
813 -> (RealVector) -- ^initial grid values, at time \'from\'
814 -> (Double) -- ^from (start time of the rollback, e.g. option maturity)
815 -> (Double) -- ^to (end time of the rollback, e.g. 0)
816 -> (Int) -- ^steps
817 -> (Int) -- ^dampingSteps
818 -> IO ((RealVector))
819 fdmRollback a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 =
820 let {a1' = fromIntegral a1} in
821 withFdmApply a2 $ \a2' ->
822 withFdmApplyDirection a3 $ \a3' ->
823 withFdmSolveSplitting a4 $ \a4' ->
824 withMaybeFdmStepCondition a5 $ \a5' ->
825 withRealVector a6 $ \(a6'1, a6'2) ->
826 withFdmSchemeDesc a7 $ \a7' ->
827 withRealVector a8 $ \(a8'1, a8'2) ->
828 let {a9' = realToFrac a9} in
829 let {a10' = realToFrac a10} in
830 let {a11' = fromIntegral a11} in
831 let {a12' = fromIntegral a12} in
832 preDoubleArray $ \(a13'1, a13'2) ->
833 preErrorCheck $ \a14' ->
834 fdmRollback'_ a1' a2' a3' a4' a5' a6'1 a6'2 a7' a8'1 a8'2 a9' a10' a11' a12' a13'1 a13'2 a14' >>
835 peekRealVector a13'1 a13'2>>= \a13'' ->
836 errorCheck a14'>>
837 return (a13'')
838
839
840
841 -- |'Predefined1dMesher(points)' -- an 'Fdm1dMesher' over an explicit, caller-supplied set of grid points.
842 predefined1dMesher :: (RealVector) -- ^points
843 -> IO ((Fdm1dMesher))
844 predefined1dMesher a1 =
845 withRealVector a1 $ \(a1'1, a1'2) ->
846 preErrorCheck $ \a2' ->
847 predefined1dMesher'_ a1'1 a1'2 a2' >>= \res ->
848 peekFdm1dMesher res >>= \res' ->
849 errorCheck a2'>>
850 return (res')
851
852
853
854 -- |'Uniform1dMesher(start, end, size)' -- an evenly spaced 'Fdm1dMesher'.
855 uniform1dMesher :: (Double) -- ^start
856 -> (Double) -- ^end
857 -> (Word) -- ^size
858 -> IO ((Fdm1dMesher))
859 uniform1dMesher a1 a2 a3 =
860 let {a1' = realToFrac a1} in
861 let {a2' = realToFrac a2} in
862 let {a3' = fromIntegral a3} in
863 preErrorCheck $ \a4' ->
864 uniform1dMesher'_ a1' a2' a3' a4' >>= \res ->
865 peekFdm1dMesher res >>= \res' ->
866 errorCheck a4'>>
867 return (res')
868
869
870
871 -- |'Concentrating1dMesher(start, end, size, cPoint, requireCPoint)' -- an 'Fdm1dMesher' with grid
872 -- points concentrated near @cPoint@ (e.g. a strike or barrier), or plain uniform spacing when
873 -- @cPoint@ is 'Nothing' for both coordinates.
874 concentrating1dMesher :: (Double) -- ^start
875 -> (Double) -- ^end
876 -> (Word) -- ^size
877 -> (Maybe Double) -- ^concentration point location
878 -> (Maybe Double) -- ^concentration point density
879 -> (Bool) -- ^requireCPoint: force the concentration point itself onto the grid
880 -> IO ((Fdm1dMesher))
881 concentrating1dMesher a1 a2 a3 a4 a5 a6 =
882 let {a1' = realToFrac a1} in
883 let {a2' = realToFrac a2} in
884 let {a3' = fromIntegral a3} in
885 let {a4' = fromMaybeDouble a4} in
886 let {a5' = fromMaybeDouble a5} in
887 let {a6' = C2HSImp.fromBool a6} in
888 preErrorCheck $ \a7' ->
889 concentrating1dMesher'_ a1' a2' a3' a4' a5' a6' a7' >>= \res ->
890 peekFdm1dMesher res >>= \res' ->
891 errorCheck a7'>>
892 return (res')
893
894
895
896 -- |Multi-concentration-point overload of 'concentrating1dMesher'
897 -- (@Concentrating1dMesher(start, end, size, cPoints, tol)@) -- a distinct upstream constructor,
898 -- not a defaulted-arg variant of the single-point one.
899 concentrating1dMesherMulti :: Double -> Double -> Word
900 -> [(Double, Double, Bool)] -- ^concentration points: (location, density, requireCPoint)
901 -> Double -- ^tol
902 -> IO Fdm1dMesher
903 concentrating1dMesherMulti start end sz cPoints tol =
904 let (locs, densities, reqs) = unzip3 cPoints
905 in qlConcentrating1dMesherMulti start end sz (fromIntegral (length cPoints)) locs densities reqs tol
906 qlConcentrating1dMesherMulti :: (Double) -> (Double) -> (Word) -> (Word) -- ^number of concentration points
907 -> ([Double]) -- ^locations
908 -> ([Double]) -- ^densities
909 -> ([Bool]) -- ^requireCPoint per point
910 -> (Double) -- ^tol
911 -> IO ((Fdm1dMesher))
912 qlConcentrating1dMesherMulti a1 a2 a3 a4 a5 a6 a7 a8 =
913 let {a1' = realToFrac a1} in
914 let {a2' = realToFrac a2} in
915 let {a3' = fromIntegral a3} in
916 let {a4' = fromIntegral a4} in
917 withDoubleArrayRaw a5 $ \a5' ->
918 withDoubleArrayRaw a6 $ \a6' ->
919 withBoolArrayRaw a7 $ \a7' ->
920 let {a8' = realToFrac a8} in
921 preErrorCheck $ \a9' ->
922 qlConcentrating1dMesherMulti'_ a1' a2' a3' a4' a5' a6' a7' a8' a9' >>= \res ->
923 peekFdm1dMesher res >>= \res' ->
924 errorCheck a9'>>
925 return (res')
926
927
928
929 -- |'Glued1dMesher(leftMesher, rightMesher)' -- splices two 'Fdm1dMesher's into one, deduplicating
930 -- their shared boundary point if @leftMesher@'s rightmost location and @rightMesher@'s leftmost
931 -- location coincide (within QuantLib's usual @close@ tolerance). Throws if @leftMesher@'s rightmost
932 -- point is strictly greater than @rightMesher@'s leftmost point -- the two ranges may touch or be
933 -- disjoint-but-ordered, never overlap or reverse.
934 gluedMesher :: (Fdm1dMesher) -- ^leftMesher
935 -> (Fdm1dMesher) -- ^rightMesher
936 -> IO ((Fdm1dMesher))
937 gluedMesher a1 a2 =
938 withFdm1dMesher a1 $ \a1' ->
939 withFdm1dMesher a2 $ \a2' ->
940 preErrorCheck $ \a3' ->
941 gluedMesher'_ a1' a2' a3' >>= \res ->
942 peekFdm1dMesher res >>= \res' ->
943 errorCheck a3'>>
944 return (res')
945
946
947
948 -- |'FdmBlackScholesMesher(size, process, maturity, strike, ...)' -- the standard log-spot mesher
949 -- for a Black-Scholes-family process, reusing the same 'GeneralizedBlackScholesProcess'\/
950 -- 'Dividend'\/'FdmQuantoHelper' plumbing "QuantLib.PricingEngine"'s @fd*@ engines already use.
951 fdmBlackScholesMesher :: (Word) -- ^size
952 -> (GenGeneralizedBlackScholesProcess gbs) -> (Double) -- ^maturity
953 -> (Double) -- ^strike
954 -> (Maybe Double) -- ^xMinConstraint
955 -> (Maybe Double) -- ^xMaxConstraint
956 -> (Double) -- ^eps
957 -> (Double) -- ^scaleFactor
958 -> (Maybe Double) -- ^concentration point location
959 -> (Maybe Double) -- ^concentration point density
960 -> ([Dividend]) -> (Maybe FdmQuantoHelper) -> (Double) -- ^spotAdjustment
961 -> IO ((Fdm1dMesher))
962 fdmBlackScholesMesher a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 =
963 let {a1' = fromIntegral a1} in
964 withGeneralizedBlackScholesProcess a2 $ \a2' ->
965 let {a3' = realToFrac a3} in
966 let {a4' = realToFrac a4} in
967 let {a5' = fromMaybeDouble a5} in
968 let {a6' = fromMaybeDouble a6} in
969 let {a7' = realToFrac a7} in
970 let {a8' = realToFrac a8} in
971 let {a9' = fromMaybeDouble a9} in
972 let {a10' = fromMaybeDouble a10} in
973 withDividendArray a11 $ \(a11'1, a11'2) ->
974 withMaybeFdmQuantoHelper a12 $ \a12' ->
975 let {a13' = realToFrac a13} in
976 preErrorCheck $ \a14' ->
977 fdmBlackScholesMesher'_ a1' a2' a3' a4' a5' a6' a7' a8' a9' a10' a11'1 a11'2 a12' a13' a14' >>= \res ->
978 peekFdm1dMesher res >>= \res' ->
979 errorCheck a14'>>
980 return (res')
981
982
983
984 -- |'FdmCEV1dMesher(size, f0, alpha, beta, maturity, eps, scaleFactor, cPoint)' -- the standard
985 -- mesher for a CEV process.
986 fdmCev1dMesher :: (Word) -- ^size
987 -> (Double) -- ^f0
988 -> (Double) -- ^alpha
989 -> (Double) -- ^beta
990 -> (Double) -- ^maturity
991 -> (Double) -- ^eps
992 -> (Double) -- ^scaleFactor
993 -> (Maybe Double) -- ^concentration point location
994 -> (Maybe Double) -- ^concentration point density
995 -> IO ((Fdm1dMesher))
996 fdmCev1dMesher a1 a2 a3 a4 a5 a6 a7 a8 a9 =
997 let {a1' = fromIntegral a1} in
998 let {a2' = realToFrac a2} in
999 let {a3' = realToFrac a3} in
1000 let {a4' = realToFrac a4} in
1001 let {a5' = realToFrac a5} in
1002 let {a6' = realToFrac a6} in
1003 let {a7' = realToFrac a7} in
1004 let {a8' = fromMaybeDouble a8} in
1005 let {a9' = fromMaybeDouble a9} in
1006 preErrorCheck $ \a10' ->
1007 fdmCev1dMesher'_ a1' a2' a3' a4' a5' a6' a7' a8' a9' a10' >>= \res ->
1008 peekFdm1dMesher res >>= \res' ->
1009 errorCheck a10'>>
1010 return (res')
1011
1012
1013
1014 -- |'ExponentialJump1dMesher(steps, beta, jumpIntensity, eta, eps)' -- mesher for the jump-diffusion
1015 -- component of a jump-diffusion process.
1016 exponentialJump1dMesher :: (Word) -- ^steps
1017 -> (Double) -- ^beta
1018 -> (Double) -- ^jumpIntensity
1019 -> (Double) -- ^eta
1020 -> (Double) -- ^eps
1021 -> IO ((Fdm1dMesher))
1022 exponentialJump1dMesher a1 a2 a3 a4 a5 =
1023 let {a1' = fromIntegral a1} in
1024 let {a2' = realToFrac a2} in
1025 let {a3' = realToFrac a3} in
1026 let {a4' = realToFrac a4} in
1027 let {a5' = realToFrac a5} in
1028 preErrorCheck $ \a6' ->
1029 exponentialJump1dMesher'_ a1' a2' a3' a4' a5' a6' >>= \res ->
1030 peekFdm1dMesher res >>= \res' ->
1031 errorCheck a6'>>
1032 return (res')
1033
1034
1035
1036 -- |'FdmSimpleProcess1dMesher(size, process, maturity, tAvgSteps, epsilon, mandatoryPoint)' --
1037 -- generic mesher for any bound one-dimensional 'StochasticProcess1D'.
1038 fdmSimpleProcess1dMesher :: (Word) -- ^size
1039 -> (GenStochasticProcess1D p1d) -> (Double) -- ^maturity
1040 -> (Word) -- ^tAvgSteps
1041 -> (Double) -- ^epsilon
1042 -> (Maybe Double) -- ^mandatoryPoint
1043 -> IO ((Fdm1dMesher))
1044 fdmSimpleProcess1dMesher a1 a2 a3 a4 a5 a6 =
1045 let {a1' = fromIntegral a1} in
1046 withStochasticProcess1D a2 $ \a2' ->
1047 let {a3' = realToFrac a3} in
1048 let {a4' = fromIntegral a4} in
1049 let {a5' = realToFrac a5} in
1050 let {a6' = fromMaybeDouble a6} in
1051 preErrorCheck $ \a7' ->
1052 fdmSimpleProcess1dMesher'_ a1' a2' a3' a4' a5' a6' a7' >>= \res ->
1053 peekFdm1dMesher res >>= \res' ->
1054 errorCheck a7'>>
1055 return (res')
1056
1057
1058
1059 -- |'FdmHestonVarianceMesher(size, process, maturity, tAvgSteps, epsilon, mixingFactor)' -- variance
1060 -- mesher for a Heston-family process.
1061 fdmHestonVarianceMesher :: (Word) -- ^size
1062 -> (GenHestonProcess hp) -> (Double) -- ^maturity
1063 -> (Word) -- ^tAvgSteps
1064 -> (Double) -- ^epsilon
1065 -> (Double) -- ^mixingFactor
1066 -> IO ((Fdm1dMesher))
1067 fdmHestonVarianceMesher a1 a2 a3 a4 a5 a6 =
1068 let {a1' = fromIntegral a1} in
1069 withHestonProcess a2 $ \a2' ->
1070 let {a3' = realToFrac a3} in
1071 let {a4' = fromIntegral a4} in
1072 let {a5' = realToFrac a5} in
1073 let {a6' = realToFrac a6} in
1074 preErrorCheck $ \a7' ->
1075 fdmHestonVarianceMesher'_ a1' a2' a3' a4' a5' a6' a7' >>= \res ->
1076 peekFdm1dMesher res >>= \res' ->
1077 errorCheck a7'>>
1078 return (res')
1079
1080
1081
1082 -- |'FdmHestonLocalVolatilityVarianceMesher(size, process, leverageFct, maturity, tAvgSteps, epsilon, mixingFactor)'
1083 -- -- Heston variance mesher accounting for a local-volatility leverage function.
1084 fdmHestonLocalVolatilityVarianceMesher :: (Word) -- ^size
1085 -> (GenHestonProcess hp) -> (GenLocalVolTermStructure lv) -- ^leverageFct
1086 -> (Double) -- ^maturity
1087 -> (Word) -- ^tAvgSteps
1088 -> (Double) -- ^epsilon
1089 -> (Double) -- ^mixingFactor
1090 -> IO ((Fdm1dMesher))
1091 fdmHestonLocalVolatilityVarianceMesher a1 a2 a3 a4 a5 a6 a7 =
1092 let {a1' = fromIntegral a1} in
1093 withHestonProcess a2 $ \a2' ->
1094 withGenLocalVolTermStructure a3 $ \a3' ->
1095 let {a4' = realToFrac a4} in
1096 let {a5' = fromIntegral a5} in
1097 let {a6' = realToFrac a6} in
1098 let {a7' = realToFrac a7} in
1099 preErrorCheck $ \a8' ->
1100 fdmHestonLocalVolatilityVarianceMesher'_ a1' a2' a3' a4' a5' a6' a7' a8' >>= \res ->
1101 peekFdm1dMesher res >>= \res' ->
1102 errorCheck a8'>>
1103 return (res')
1104
1105
1106
1107 -- |'FdmMesherComposite' -- combine one or more 'Fdm1dMesher's into the multi-dimensional
1108 -- 'FdmMesher' the operator\/step-condition callbacks and 'fdmSolve' operate over; the sole
1109 -- concrete 'FdmMesher' upstream.
1110 fdmMesherComposite :: ([Fdm1dMesher]) -> IO ((FdmMesher))
1111 fdmMesherComposite a1 =
1112 withFdm1dMesherArray a1 $ \(a1'1, a1'2) ->
1113 preErrorCheck $ \a2' ->
1114 fdmMesherComposite'_ a1'1 a1'2 a2' >>= \res ->
1115 peekFdmMesher res >>= \res' ->
1116 errorCheck a2'>>
1117 return (res')
1118
1119
1120
1121 -- |Real-valued node locations along one dimension of a mesher, e.g. to map 'fdmSolve''s flat
1122 -- result array back to coordinates (mirrors how @Fdm1DimSolver@\/@FdmNdimSolver@ build their own
1123 -- @x_@ arrays from this same call upstream).
1124 fdmMesherLocations :: (FdmMesher) -> (Int) -- ^direction
1125 -> IO ((RealVector))
1126 fdmMesherLocations a1 a2 =
1127 withFdmMesher a1 $ \a1' ->
1128 let {a2' = fromIntegral a2} in
1129 preDoubleArray $ \(a3'1, a3'2) ->
1130 preErrorCheck $ \a4' ->
1131 fdmMesherLocations'_ a1' a2' a3'1 a3'2 a4' >>
1132 peekRealVector a3'1 a3'2>>= \a3'' ->
1133 errorCheck a4'>>
1134 return (a3'')
1135
1136
1137
1138 qlFdmInnerValueCalculatorFromFunctions :: (FdmMesher) -> (Callback) -> (Callback) -> IO ((FdmInnerValueCalculator))
1139 qlFdmInnerValueCalculatorFromFunctions a1 a2 a3 =
1140 withFdmMesher a1 $ \a1' ->
1141 withCallbackPtr a2 $ \a2' ->
1142 withCallbackPtr a3 $ \a3' ->
1143 preErrorCheck $ \a4' ->
1144 qlFdmInnerValueCalculatorFromFunctions'_ a1' a2' a3' a4' >>= \res ->
1145 peekFdmInnerValueCalculator res >>= \res' ->
1146 errorCheck a4'>>
1147 return (res')
1148
1149
1150
1151 -- |Wraps a Haskell @t -> location -> value@ pair of @innerValue@\/@avgInnerValue@ functions as a
1152 -- real 'FdmInnerValueCalculator' that retains both callbacks after the continuation returns.
1153 -- Callback exceptions are rethrown by the enclosing Haskell call. Unlike every callback
1154 -- 'fdmRollback' takes, this crosses the language boundary once /per grid node/, not once per outer
1155 -- iteration over the whole grid -- there is no batched \"whole-grid inner value\" shape anywhere
1156 -- in QuantLib or QuantLib-SWIG. The per-call FFI cost across
1157 -- every node (and, if a step condition also calls the calculator, every node at every exercise
1158 -- date) is accepted -- matching QuantLib-SWIG's own accepted-cost precedent,
1159 -- @FdmInnerValueCalculatorDelegate@ (@SWIG\/fdm.i@).
1160 withCustomFdmInnerValueCalculator :: FdmMesher
1161 -> (Double -> [Double] -> Double) -- ^innerValue(t, location)
1162 -> (Double -> [Double] -> Double) -- ^avgInnerValue(t, location)
1163 -> (FdmInnerValueCalculator -> IO b) -> IO b
1164 withCustomFdmInnerValueCalculator mesher iv aiv k =
1165 withFdmInnerValue iv $ \inner ->
1166 withFdmInnerValue aiv $ \average ->
1167 qlFdmInnerValueCalculatorFromFunctions mesher inner average >>= k
1168
1169 -- |'FdmZeroInnerValue' -- an 'FdmInnerValueCalculator' whose @innerValue@\/@avgInnerValue@ are
1170 -- always 0.
1171 fdmZeroInnerValue :: IO ((FdmInnerValueCalculator))
1172 fdmZeroInnerValue =
1173 preErrorCheck $ \a1' ->
1174 fdmZeroInnerValue'_ a1' >>= \res ->
1175 peekFdmInnerValueCalculator res >>= \res' ->
1176 errorCheck a1'>>
1177 return (res')
1178
1179
1180
1181 -- |'FdmCellAveragingInnerValue(payoff, mesher, direction)' -- cell-averages @payoff@ over each
1182 -- grid cell along @direction@ (Simpson-integrating across the cell straddling a kink, e.g. a
1183 -- strike, rather than just evaluating at the cell center), with the identity value mapping. See
1184 -- 'withCustomCellAveragingInnerValue' for the @gridMapping@-taking overload (e.g. to reproduce
1185 -- 'fdmLogInnerValue' by hand), and 'fdmLogInnerValue' for the common log-mapped case QuantLib
1186 -- itself gives its own dedicated subclass.
1187 fdmCellAveragingInnerValue :: (Payoff) -> (FdmMesher) -> (Int) -- ^direction
1188 -> IO ((FdmInnerValueCalculator))
1189 fdmCellAveragingInnerValue a1 a2 a3 =
1190 withPayoff a1 $ \a1' ->
1191 withFdmMesher a2 $ \a2' ->
1192 let {a3' = fromIntegral a3} in
1193 preErrorCheck $ \a4' ->
1194 fdmCellAveragingInnerValue'_ a1' a2' a3' a4' >>= \res ->
1195 peekFdmInnerValueCalculator res >>= \res' ->
1196 errorCheck a4'>>
1197 return (res')
1198
1199
1200
1201 qlFdmCellAveragingInnerValueMapped :: (Payoff) -> (FdmMesher) -> (Int) -> (Callback) -> IO ((FdmInnerValueCalculator))
1202 qlFdmCellAveragingInnerValueMapped a1 a2 a3 a4 =
1203 withPayoff a1 $ \a1' ->
1204 withFdmMesher a2 $ \a2' ->
1205 let {a3' = fromIntegral a3} in
1206 withCallbackPtr a4 $ \a4' ->
1207 preErrorCheck $ \a5' ->
1208 qlFdmCellAveragingInnerValueMapped'_ a1' a2' a3' a4' a5' >>= \res ->
1209 peekFdmInnerValueCalculator res >>= \res' ->
1210 errorCheck a5'>>
1211 return (res')
1212
1213
1214
1215 -- |As 'fdmCellAveragingInnerValue', but with an explicit @gridMapping :: Double -> Double@ applied
1216 -- to each node's location before the payoff sees it (e.g. @exp@ on a log-spot grid, reproducing
1217 -- 'fdmLogInnerValue' by hand) -- a genuine per-node Haskell callback; see
1218 -- 'withCustomFdmInnerValueCalculator'. The calculator retains the callback after the continuation.
1219 withCustomCellAveragingInnerValue :: Payoff -> FdmMesher -> Int -> (Double -> Double)
1220 -> (FdmInnerValueCalculator -> IO b) -> IO b
1221 withCustomCellAveragingInnerValue payoff mesher direction mapping k =
1222 withFdmGridMapping mapping $ \callback ->
1223 qlFdmCellAveragingInnerValueMapped payoff mesher direction callback >>= k
1224
1225 -- |'FdmLogInnerValue(payoff, mesher, direction)' -- 'fdmCellAveragingInnerValue' with the
1226 -- @gridMapping = exp@ QuantLib itself gives its own dedicated subclass (the standard shape for a
1227 -- log-spot grid, e.g. 'fdmBlackScholesMesher''s own grid).
1228 fdmLogInnerValue :: (Payoff) -> (FdmMesher) -> (Int) -- ^direction
1229 -> IO ((FdmInnerValueCalculator))
1230 fdmLogInnerValue a1 a2 a3 =
1231 withPayoff a1 $ \a1' ->
1232 withFdmMesher a2 $ \a2' ->
1233 let {a3' = fromIntegral a3} in
1234 preErrorCheck $ \a4' ->
1235 fdmLogInnerValue'_ a1' a2' a3' a4' >>= \res ->
1236 peekFdmInnerValueCalculator res >>= \res' ->
1237 errorCheck a4'>>
1238 return (res')
1239
1240
1241
1242 -- |'FdmLogBasketInnerValue(payoff, mesher)' -- the multi-asset counterpart to 'fdmLogInnerValue':
1243 -- evaluates a 'BasketPayoff' with each dimension's location exponentiated first (@exp@ on every
1244 -- mesher direction, i.e. a log-spot grid per underlying), no cell averaging.
1245 fdmLogBasketInnerValue :: (BasketPayoff) -> (FdmMesher) -> IO ((FdmInnerValueCalculator))
1246 fdmLogBasketInnerValue a1 a2 =
1247 withBasketPayoff a1 $ \a1' ->
1248 withFdmMesher a2 $ \a2' ->
1249 preErrorCheck $ \a3' ->
1250 fdmLogBasketInnerValue'_ a1' a2' a3' >>= \res ->
1251 peekFdmInnerValueCalculator res >>= \res' ->
1252 errorCheck a3'>>
1253 return (res')
1254
1255
1256
1257 -- |'FdmAffineModelSwapInnerValue\<G2\>(disModel, fwdModel, swap, exerciseDates, mesher, direction)'
1258 -- -- the swap-NPV-under-the-model 'FdmInnerValueCalculator' used internally by
1259 -- 'QuantLib.PricingEngine.fdG2SwaptionEngine'. @exerciseDates@ pairs each exercise time (the same
1260 -- @Time@-as-@Double@ year-fraction convention used throughout, not a dedicated type) with the
1261 -- 'Data.Time.Calendar.Day' it corresponds to (upstream's @std::map\<Time, Date\>@).
1262 fdmAffineG2ModelSwapInnerValue :: G2 -> G2 -> GenFixedVsFloatingSwap f -> [(Double, Day)] -> FdmMesher -> Int -> IO FdmInnerValueCalculator
1263 fdmAffineG2ModelSwapInnerValue disModel fwdModel swap exerciseDates =
1264 let (times, dates) = unzip exerciseDates
1265 in qlFdmAffineG2ModelSwapInnerValue disModel fwdModel swap (length exerciseDates) times dates
1266 qlFdmAffineG2ModelSwapInnerValue :: (G2) -> (G2) -> (GenFixedVsFloatingSwap f) -> (Int) -- ^number of exercise dates
1267 -> ([Double]) -- ^exercise times
1268 -> ([Day]) -- ^exercise dates
1269 -> (FdmMesher) -> (Int) -- ^direction
1270 -> IO ((FdmInnerValueCalculator))
1271 qlFdmAffineG2ModelSwapInnerValue a1 a2 a3 a4 a5 a6 a7 a8 =
1272 withG2 a1 $ \a1' ->
1273 withG2 a2 $ \a2' ->
1274 withFixedVsFloatingSwap a3 $ \a3' ->
1275 let {a4' = fromIntegral a4} in
1276 withDoubleArrayRaw a5 $ \a5' ->
1277 withDayPtr a6 $ \a6' ->
1278 withFdmMesher a7 $ \a7' ->
1279 let {a8' = fromIntegral a8} in
1280 preErrorCheck $ \a9' ->
1281 qlFdmAffineG2ModelSwapInnerValue'_ a1' a2' a3' a4' a5' a6' a7' a8' a9' >>= \res ->
1282 peekFdmInnerValueCalculator res >>= \res' ->
1283 errorCheck a9'>>
1284 return (res')
1285
1286
1287
1288 -- |As 'fdmAffineG2ModelSwapInnerValue', but for 'HullWhite' -- used internally by
1289 -- 'QuantLib.PricingEngine.fdHullWhiteSwaptionEngine'.
1290 fdmAffineHullWhiteModelSwapInnerValue :: HullWhite -> HullWhite -> GenFixedVsFloatingSwap f -> [(Double, Day)] -> FdmMesher -> Int -> IO FdmInnerValueCalculator
1291 fdmAffineHullWhiteModelSwapInnerValue disModel fwdModel swap exerciseDates =
1292 let (times, dates) = unzip exerciseDates
1293 in qlFdmAffineHullWhiteModelSwapInnerValue disModel fwdModel swap (length exerciseDates) times dates
1294 qlFdmAffineHullWhiteModelSwapInnerValue :: (HullWhite) -> (HullWhite) -> (GenFixedVsFloatingSwap f) -> (Int) -- ^number of exercise dates
1295 -> ([Double]) -- ^exercise times
1296 -> ([Day]) -- ^exercise dates
1297 -> (FdmMesher) -> (Int) -- ^direction
1298 -> IO ((FdmInnerValueCalculator))
1299 qlFdmAffineHullWhiteModelSwapInnerValue a1 a2 a3 a4 a5 a6 a7 a8 =
1300 withHullWhite a1 $ \a1' ->
1301 withHullWhite a2 $ \a2' ->
1302 withFixedVsFloatingSwap a3 $ \a3' ->
1303 let {a4' = fromIntegral a4} in
1304 withDoubleArrayRaw a5 $ \a5' ->
1305 withDayPtr a6 $ \a6' ->
1306 withFdmMesher a7 $ \a7' ->
1307 let {a8' = fromIntegral a8} in
1308 preErrorCheck $ \a9' ->
1309 qlFdmAffineHullWhiteModelSwapInnerValue'_ a1' a2' a3' a4' a5' a6' a7' a8' a9' >>= \res ->
1310 peekFdmInnerValueCalculator res >>= \res' ->
1311 errorCheck a9'>>
1312 return (res')
1313
1314
1315
1316 -- |Evaluate an 'FdmInnerValueCalculator''s @innerValue@ at the mesher node given by its
1317 -- coordinates (one index per PDE dimension), at time @t@ -- lets any bound calculator (native or
1318 -- built via 'withCustomFdmInnerValueCalculator') be inspected directly without assembling a whole
1319 -- 'fdmSolve'.
1320 fdmInnerValue :: (FdmInnerValueCalculator) -> (FdmMesher) -> ([Int]) -- ^node coordinates
1321 -> (Double) -- ^t
1322 -> IO ((Double))
1323 fdmInnerValue a1 a2 a3 a4 =
1324 withFdmInnerValueCalculator a1 $ \a1' ->
1325 withFdmMesher a2 $ \a2' ->
1326 withIntArray a3 $ \(a3'1, a3'2) ->
1327 let {a4' = realToFrac a4} in
1328 preErrorCheck $ \a5' ->
1329 fdmInnerValue'_ a1' a2' a3'1 a3'2 a4' a5' >>= \res ->
1330 let {res' = realToFrac res} in
1331 errorCheck a5'>>
1332 return (res')
1333
1334
1335
1336 -- |As 'fdmInnerValue', but for @avgInnerValue@.
1337 fdmAvgInnerValue :: (FdmInnerValueCalculator) -> (FdmMesher) -> ([Int]) -- ^node coordinates
1338 -> (Double) -- ^t
1339 -> IO ((Double))
1340 fdmAvgInnerValue a1 a2 a3 a4 =
1341 withFdmInnerValueCalculator a1 $ \a1' ->
1342 withFdmMesher a2 $ \a2' ->
1343 withIntArray a3 $ \(a3'1, a3'2) ->
1344 let {a4' = realToFrac a4} in
1345 preErrorCheck $ \a5' ->
1346 fdmAvgInnerValue'_ a1' a2' a3'1 a3'2 a4' a5' >>= \res ->
1347 let {res' = realToFrac res} in
1348 errorCheck a5'>>
1349 return (res')
1350
1351
1352
1353 -- |Sibling of 'fdmRollback' that derives its own initial grid from a mesher and an
1354 -- 'FdmInnerValueCalculator' (@avgInnerValue(t, location)@ per node, called once per mesher node at
1355 -- @t = maturity@ -- mirroring @Fdm1DimSolver@\/@FdmNdimSolver@'s own constructor loop) instead of
1356 -- taking a precomputed grid array. Everything else (operator\/step-condition\/scheme\/rollback) is
1357 -- identical to 'fdmRollback', reusing the same callback machinery. The calculator can be either
1358 -- fully custom ('fdmInnerValueCalculator') or one of QuantLib's own native subclasses.
1359 --
1360 -- @Fdm1DimSolver@\/@FdmNdimSolver@ themselves (their own @LazyObject@ caching and cubic-spline
1361 -- interpolation) are /not/ bound; combine this function's result with 'fdmMesherLocations' for
1362 -- interpolation.
1363 fdmSolve :: (FdmMesher) -> (FdmInnerValueCalculator) -> (Int) -- ^number of PDE directions\/dimensions the operator has
1364 -> ((Double,Double) -> RealVector -> RealVector) -- ^@apply(r)@
1365 -> (Int -> (Double,Double) -> RealVector -> RealVector) -- ^@apply_direction(direction, r)@
1366 -> (Int -> Double -> (Double,Double) -> RealVector -> RealVector) -- ^@solve_splitting(direction, r, s)@
1367 -> (Maybe (Double -> RealVector -> RealVector)) -- ^optional step condition
1368 -> (RealVector) -- ^stopping times at which the step condition above is applied
1369 -> (FdmScheme) -- ^the finite-difference scheme
1370 -> (Double) -- ^maturity (start time of the rollback, and the time at which avgInnerValue builds the initial grid)
1371 -> (Double) -- ^to (end time of the rollback, e.g. 0)
1372 -> (Int) -- ^steps
1373 -> (Int) -- ^dampingSteps
1374 -> IO ((RealVector))
1375 fdmSolve a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 =
1376 withFdmMesher a1 $ \a1' ->
1377 withFdmInnerValueCalculator a2 $ \a2' ->
1378 let {a3' = fromIntegral a3} in
1379 withFdmApply a4 $ \a4' ->
1380 withFdmApplyDirection a5 $ \a5' ->
1381 withFdmSolveSplitting a6 $ \a6' ->
1382 withMaybeFdmStepCondition a7 $ \a7' ->
1383 withRealVector a8 $ \(a8'1, a8'2) ->
1384 withFdmSchemeDesc a9 $ \a9' ->
1385 let {a10' = realToFrac a10} in
1386 let {a11' = realToFrac a11} in
1387 let {a12' = fromIntegral a12} in
1388 let {a13' = fromIntegral a13} in
1389 preDoubleArray $ \(a14'1, a14'2) ->
1390 preErrorCheck $ \a15' ->
1391 fdmSolve'_ a1' a2' a3' a4' a5' a6' a7' a8'1 a8'2 a9' a10' a11' a12' a13' a14'1 a14'2 a15' >>
1392 peekRealVector a14'1 a14'2>>= \a14'' ->
1393 errorCheck a15'>>
1394 return (a14'')
1395
1396
1397
1398 -- vim: set ff=unix ts=8 sts=2 sw=2 et:
1399
1400 foreign import ccall safe "QuantLib/Method.chs.h qlPathGenerator"
1401 pathGenerator'_ :: (C2HSImp.CInt -> ((C2HSImp.Ptr (CStochasticProcess')) -> ((C2HSImp.Ptr (CTimeGrid)) -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> (C2HSImp.CInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CPathGenerator))))))))))
1402
1403 foreign import ccall safe "QuantLib/Method.chs.h qlSobolPathGenerator"
1404 sobolPathGenerator'_ :: (C2HSImp.CInt -> ((C2HSImp.Ptr (CStochasticProcess')) -> ((C2HSImp.Ptr (CTimeGrid)) -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> (C2HSImp.CInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CPathGenerator))))))))))
1405
1406 foreign import ccall safe "QuantLib/Method.chs.h qlGaussianRsg"
1407 gaussianRsg'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CGaussianRsg)))))))
1408
1409 foreign import ccall safe "QuantLib/Method.chs.h qlSobolGaussianRsg"
1410 sobolGaussianRsg'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CGaussianRsg)))))))
1411
1412 foreign import ccall safe "QuantLib/Method.chs.h qlGaussianRsgDimension"
1413 rsgDimension'_ :: ((C2HSImp.Ptr (CGaussianRsg)) -> (IO C2HSImp.CUInt))
1414
1415 foreign import ccall safe "QuantLib/Method.chs.h qlGaussianRsgNextSequence"
1416 nextSequence'_ :: ((C2HSImp.Ptr (CGaussianRsg)) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))
1417
1418 foreign import ccall safe "QuantLib/Method.chs.h qlGaussianRsgLastSequence"
1419 lastSequence'_ :: ((C2HSImp.Ptr (CGaussianRsg)) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))
1420
1421 foreign import ccall safe "QuantLib/Method.chs.h qlPathGeneratorSequence"
1422 pathGeneratorSequence'_ :: ((C2HSImp.Ptr (CPathGenerator)) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))
1423
1424 foreign import ccall safe "QuantLib/Method.chs.h qlPathGeneratorNext"
1425 next'_ :: ((C2HSImp.Ptr (CPathGenerator)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CSamplePath)))))
1426
1427 foreign import ccall safe "QuantLib/Method.chs.h qlPathGeneratorAntithetic"
1428 antithetic'_ :: ((C2HSImp.Ptr (CPathGenerator)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CSamplePath)))))
1429
1430 foreign import ccall safe "QuantLib/Method.chs.h qlSamplePathWeight"
1431 weight'_ :: ((C2HSImp.Ptr (CSamplePath)) -> (IO C2HSImp.CDouble))
1432
1433 foreign import ccall safe "QuantLib/Method.chs.h qlSamplePathAssetNumber"
1434 assetNumber'_ :: ((C2HSImp.Ptr (CSamplePath)) -> (IO C2HSImp.CUInt))
1435
1436 foreign import ccall safe "QuantLib/Method.chs.h qlSamplePathSize"
1437 pathSize'_ :: ((C2HSImp.Ptr (CSamplePath)) -> (IO C2HSImp.CUInt))
1438
1439 foreign import ccall safe "QuantLib/Method.chs.h qlSamplePathAt"
1440 assetAt'_ :: ((C2HSImp.Ptr (CSamplePath)) -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO C2HSImp.CDouble)))))
1441
1442 foreign import ccall safe "QuantLib/Method.chs.h qlSamplePathAssetPath"
1443 asset'_ :: ((C2HSImp.Ptr (CSamplePath)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))
1444
1445 foreign import ccall safe "QuantLib/Method.chs.h qlLsmRegress"
1446 lsmRegress'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))))))))
1447
1448 foreign import ccall safe "QuantLib/Method.chs.h qlLsmRegressMulti"
1449 qlLsmRegressMulti'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))))))))))
1450
1451 foreign import ccall safe "QuantLib/Method.chs.h qlLsmFit"
1452 qlLsmFit'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ())))))))))))
1453
1454 foreign import ccall safe "QuantLib/Method.chs.h qlLsmEvaluate"
1455 qlLsmEvaluate'_ :: (C2HSImp.CInt -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ())))))))))))
1456
1457 foreign import ccall safe "QuantLib/Method.chs.h qlLsmEvaluatorIdentity"
1458 lsmEvaluatorIdentity'_ :: (IO (C2HSImp.Ptr C2HSImp.CChar))
1459
1460 foreign import ccall safe "QuantLib/Method.chs.h qlFdmRollback"
1461 fdmRollback'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (CFdmSchemeDesc)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))))))))))))))
1462
1463 foreign import ccall safe "QuantLib/Method.chs.h qlPredefined1dMesher"
1464 predefined1dMesher'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))
1465
1466 foreign import ccall safe "QuantLib/Method.chs.h qlUniform1dMesher"
1467 uniform1dMesher'_ :: (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher)))))))
1468
1469 foreign import ccall safe "QuantLib/Method.chs.h qlConcentrating1dMesher"
1470 concentrating1dMesher'_ :: (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))))))
1471
1472 foreign import ccall safe "QuantLib/Method.chs.h qlConcentrating1dMesherMulti"
1473 qlConcentrating1dMesherMulti'_ :: (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CInt) -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))))))))
1474
1475 foreign import ccall safe "QuantLib/Method.chs.h qlGluedMesher"
1476 gluedMesher'_ :: ((C2HSImp.Ptr (CFdm1dMesher)) -> ((C2HSImp.Ptr (CFdm1dMesher)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))
1477
1478 foreign import ccall safe "QuantLib/Method.chs.h qlFdmBlackScholesMesher"
1479 fdmBlackScholesMesher'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr (CGeneralizedBlackScholesProcess')) -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr (CDividend))) -> ((C2HSImp.Ptr (CFdmQuantoHelper)) -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))))))))))))))
1480
1481 foreign import ccall safe "QuantLib/Method.chs.h qlFdmCev1dMesher"
1482 fdmCev1dMesher'_ :: (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher)))))))))))))
1483
1484 foreign import ccall safe "QuantLib/Method.chs.h qlExponentialJump1dMesher"
1485 exponentialJump1dMesher'_ :: (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher)))))))))
1486
1487 foreign import ccall safe "QuantLib/Method.chs.h qlFdmSimpleProcess1dMesher"
1488 fdmSimpleProcess1dMesher'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr (CStochasticProcess1D')) -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))))))
1489
1490 foreign import ccall safe "QuantLib/Method.chs.h qlFdmHestonVarianceMesher"
1491 fdmHestonVarianceMesher'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr (CHestonProcess')) -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher))))))))))
1492
1493 foreign import ccall safe "QuantLib/Method.chs.h qlFdmHestonLocalVolatilityVarianceMesher"
1494 fdmHestonLocalVolatilityVarianceMesher'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr (CHestonProcess')) -> ((C2HSImp.Ptr (CLocalVolTermStructure')) -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdm1dMesher)))))))))))
1495
1496 foreign import ccall safe "QuantLib/Method.chs.h qlFdmMesherComposite"
1497 fdmMesherComposite'_ :: (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr (CFdm1dMesher))) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmMesher))))))
1498
1499 foreign import ccall safe "QuantLib/Method.chs.h qlFdmMesherLocations"
1500 fdmMesherLocations'_ :: ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))
1501
1502 foreign import ccall safe "QuantLib/Method.chs.h qlFdmInnerValueCalculatorFromFunctions"
1503 qlFdmInnerValueCalculatorFromFunctions'_ :: ((C2HSImp.Ptr (CFdmMesher)) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator)))))))
1504
1505 foreign import ccall safe "QuantLib/Method.chs.h qlFdmZeroInnerValue"
1506 fdmZeroInnerValue'_ :: ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator))))
1507
1508 foreign import ccall safe "QuantLib/Method.chs.h qlFdmCellAveragingInnerValue"
1509 fdmCellAveragingInnerValue'_ :: ((QlPayoff) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator)))))))
1510
1511 foreign import ccall safe "QuantLib/Method.chs.h qlFdmCellAveragingInnerValueMapped"
1512 qlFdmCellAveragingInnerValueMapped'_ :: ((QlPayoff) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator))))))))
1513
1514 foreign import ccall safe "QuantLib/Method.chs.h qlFdmLogInnerValue"
1515 fdmLogInnerValue'_ :: ((QlPayoff) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator)))))))
1516
1517 foreign import ccall safe "QuantLib/Method.chs.h qlFdmLogBasketInnerValue"
1518 fdmLogBasketInnerValue'_ :: ((QlBasketPayoff) -> ((C2HSImp.Ptr (CFdmMesher)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator))))))
1519
1520 foreign import ccall safe "QuantLib/Method.chs.h qlFdmAffineG2ModelSwapInnerValue"
1521 qlFdmAffineG2ModelSwapInnerValue'_ :: ((C2HSImp.Ptr (CG2')) -> ((C2HSImp.Ptr (CG2')) -> ((C2HSImp.Ptr (CFixedVsFloatingSwap')) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CInt) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator))))))))))))
1522
1523 foreign import ccall safe "QuantLib/Method.chs.h qlFdmAffineHullWhiteModelSwapInnerValue"
1524 qlFdmAffineHullWhiteModelSwapInnerValue'_ :: ((C2HSImp.Ptr (CHullWhite')) -> ((C2HSImp.Ptr (CHullWhite')) -> ((C2HSImp.Ptr (CFixedVsFloatingSwap')) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr C2HSImp.CInt) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO (C2HSImp.Ptr (CFdmInnerValueCalculator))))))))))))
1525
1526 foreign import ccall safe "QuantLib/Method.chs.h qlFdmInnerValueCalculatorEval"
1527 fdmInnerValue'_ :: ((C2HSImp.Ptr (CFdmInnerValueCalculator)) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO C2HSImp.CDouble)))))))
1528
1529 foreign import ccall safe "QuantLib/Method.chs.h qlFdmInnerValueCalculatorAvgEval"
1530 fdmAvgInnerValue'_ :: ((C2HSImp.Ptr (CFdmInnerValueCalculator)) -> ((C2HSImp.Ptr (CFdmMesher)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> (C2HSImp.CDouble -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO C2HSImp.CDouble)))))))
1531
1532 foreign import ccall safe "QuantLib/Method.chs.h qlFdmSolve"
1533 fdmSolve'_ :: ((C2HSImp.Ptr (CFdmMesher)) -> ((C2HSImp.Ptr (CFdmInnerValueCalculator)) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> ((C2HSImp.Ptr ()) -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CDouble) -> ((C2HSImp.Ptr (CFdmSchemeDesc)) -> (C2HSImp.CDouble -> (C2HSImp.CDouble -> (C2HSImp.CUInt -> (C2HSImp.CUInt -> ((C2HSImp.Ptr C2HSImp.CUInt) -> ((C2HSImp.Ptr (C2HSImp.Ptr C2HSImp.CDouble)) -> ((C2HSImp.Ptr (C2HSImp.Ptr ())) -> (IO ()))))))))))))))))))