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 ()))))))))))))))))))