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