Coverage Report

Created: 2026-10-31 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/experimental/barrieroption/perturbativebarrieroptionengine.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2008 Lorella Fatone
5
 Copyright (C) 2008 Maria Cristina Recchioni
6
 Copyright (C) 2008 Francesco Zirilli
7
 Copyright (C) 2008 StatPro Italia srl
8
9
 This file is part of QuantLib, a free-software/open-source library
10
 for financial quantitative analysts and developers - http://quantlib.org/
11
12
 QuantLib is free software: you can redistribute it and/or modify it
13
 under the terms of the QuantLib license.  You should have received a
14
 copy of the license along with this program; if not, please email
15
 <quantlib-dev@lists.sf.net>. The license is also available online at
16
 <https://www.quantlib.org/license.shtml>.
17
18
 This program is distributed in the hope that it will be useful, but WITHOUT
19
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 FOR A PARTICULAR PURPOSE.  See the license for more details.
21
*/
22
23
#include <ql/errors.hpp>
24
#include <ql/exercise.hpp>
25
#include <ql/experimental/barrieroption/perturbativebarrieroptionengine.hpp>
26
#include <ql/types.hpp>
27
#include <functional>
28
#include <algorithm>
29
#include <cmath>
30
#include <utility>
31
32
using namespace std;
33
34
namespace {
35
36
    inline QuantLib::Real SIGN(const QuantLib::Real& a, const QuantLib::Real& b) 
37
0
    {
38
0
        if (b > 0.0) 
39
0
            return std::fabs(a);
40
0
        else
41
0
            return -std::fabs(a);
42
0
    }
43
44
}
45
46
namespace QuantLib {
47
48
    namespace {
49
50
    constexpr double PI = 3.14159265358979324;
51
    constexpr double halfPi = PI / 2.0;
52
    constexpr double twoPi = 2.0 * PI;
53
    constexpr double sqrtTwo = 1.4142135623730950488;
54
    constexpr double sqrtPi = 1.7724538509055160273;
55
    constexpr double sqrtTwoPi = sqrtTwo * sqrtPi;
56
57
    // TODO: review these local distribution helpers against the existing
58
    // QuantLib implementations before consolidating them.
59
    Real ND2(Real a, Real b, Real rho);
60
    // standard normal cumulative distribution function
61
    Real PHID(Real Z);
62
63
    // Functions used to compute the first order approximation
64
    Real ff(Real p,Real tt,Real a, Real b, Real gm);
65
    Real v(Real p, Real tt,Real a,Real b,Real gm);
66
    Real llold(Real p,Real tt, Real a, Real b,
67
                 Real c, Real gm);
68
69
    // Functions used to compute the second order approximation
70
    Real derivn3(const Real limit[4], const Real sigmarho[4], const Real sigma[4], int idx);
71
    Real ddvv(Real s, Real p, Real tt, Real a,
72
                Real b, Real gm);
73
    Real ddff(Real s, Real p,Real tt,Real a,Real b,Real gm);
74
    Real dll(Real s,Real p,Real tt,Real a,Real b,
75
               Real c,Real gm);
76
    Real ddll(Real s,Real p,Real tt, Real ax, Real bx,
77
                Real c, Real gm);
78
    Real dvv(Real s,Real p,Real tt,Real a,Real b,Real gm);
79
    Real dff(Real s, Real p,Real tt,Real a,Real b,Real gm);
80
    Real tvtl(int jj, const Real limit[4], const Real sigmarho[4], Real epsi);
81
82
    template <class Integr, class IntegralAlpha, class IntegralVariance,
83
              class Alpha, class SigmaQ>
84
    Real BarrierUPD(Real kprice,
85
                    Real stock,
86
                    Real hbarr,
87
                    Real taumin,
88
                    Real taumax,
89
                    int iord,
90
                    int igm,
91
                    Size npoint,
92
                    Size npoint2,
93
                    const Integr& integr,
94
                    const IntegralAlpha& integalpha,
95
                    const IntegralVariance& integs,
96
                    const Alpha& alpha,
97
0
                    const SigmaQ& sigmaq) {
98
0
        Real v0=0.0, v1=0.0, v1p=0.0, v2p=0.0, v2pp=0.0, gm=0.0;
99
0
        Size i=0,j=0;
100
0
        Real tmp=0.0, e1=0.0, e2=0.0, e3=0.0, e4=0.0;
101
0
        Real xstar=0.0, s0=0.0;
102
0
        Real sigmat=0.0, disc=0.0, d1=0.0,d2=0.0,d3=0.0,d4=0.0;
103
0
        Real et=0.0,tt=0.0, dt=0.0,p=0.0;
104
0
        Real dsqpi;
105
0
        Real caux=0.0,ccaux=0.0;
106
0
        Real auxnew=0.0;
107
0
        Real x=0.0,b=0.0,c=0.0;
108
109
0
        if(igm==0) {
110
0
            gm=0.0;
111
0
        } else if(igm==1) {
112
0
            gm=integalpha(taumin,taumax)/(0.5*integs(taumin,taumax));
113
0
        } else {
114
0
            gm=0.0;
115
0
        }
116
117
        /*
118
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
119
          !!                                 !!
120
          !! xstar=min(0,log(kprice/hbarr))  !!
121
          !!                                 !!
122
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
123
        */
124
125
0
        xstar=log(kprice/hbarr);
126
127
0
        if(xstar>0.0) xstar=0.0;
128
0
        sigmat=integs(taumin,taumax);
129
0
        disc=-integr(taumin,taumax);
130
0
        const Real oneMinusGamma = 1.0-gm;
131
0
        const Real onePlusGamma = 1.0+gm;
132
0
        const Real barrierFactor = hbarr*exp(0.5*onePlusGamma*xstar)
133
0
                     - kprice*exp(-0.5*oneMinusGamma*xstar);
134
135
        /*
136
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
137
          !!    Change of variable            !!
138
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
139
        */
140
0
        s0=stock/hbarr;
141
142
        /*
143
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
144
          !!                                       !!
145
          !! Compute the zero-th order term P_0    !!
146
          !!                                       !!
147
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
148
        */
149
0
        x=log(s0);
150
0
        const Real invSqrtSigmat = 1.0 / std::sqrt(sigmat);
151
0
        const Real halfSigmat = 0.5 * sigmat;
152
0
        const Real minusGammaNumerator = xstar + oneMinusGamma * halfSigmat;
153
0
        const Real plusGammaNumerator = xstar - onePlusGamma * halfSigmat;
154
0
        const Real scaledLogS0 = x * invSqrtSigmat;
155
0
        const Real scaledMinusGammaNumerator = minusGammaNumerator * invSqrtSigmat;
156
0
        const Real scaledPlusGammaNumerator = plusGammaNumerator * invSqrtSigmat;
157
0
        d1=scaledMinusGammaNumerator-scaledLogS0;
158
0
        d2=scaledMinusGammaNumerator+scaledLogS0;
159
0
        d3=scaledPlusGammaNumerator-scaledLogS0;
160
0
        d4=scaledPlusGammaNumerator+scaledLogS0;
161
162
0
        e1=PHID(d1);
163
0
        e2=PHID(d2);
164
0
        e3=PHID(d3);
165
0
        e4=PHID(d4);
166
167
0
        v0=kprice*e1-kprice*exp(oneMinusGamma*x)*e2;
168
0
        v0=v0+exp(gm*halfSigmat)*(-hbarr*s0*e3+hbarr*exp(-gm*x)*e4);
169
0
        v0=v0*exp(disc);
170
171
0
        if(iord==0) return v0;
172
173
        /*
174
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
175
          !!                                           !!
176
          !! Compute the first order term  P_1         !!
177
          !!                                           !!
178
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
179
        */
180
181
0
        dt=(taumax-taumin)/double(npoint);
182
183
0
        tt=0.5*integs(taumin,taumax);
184
185
0
        et=exp(0.5*(1.0-gm)*x);
186
187
0
        dsqpi=sqrtPi;
188
189
0
        v1=0.0;
190
0
        for( i=1;i<=npoint;i++) {
191
0
            v1p=0.0;
192
0
            tmp=taumin+dt*double(2*i-1)*0.5;
193
0
            p=0.5*integs(tmp,taumax);
194
0
            const Real expGammaP = exp(gm*p);
195
            /*
196
              !!
197
              !! Function E(p,tt,a,b,gm)
198
              !!
199
            */
200
0
            ccaux=v(p,tt,x,xstar,gm)+v(p,tt,x,-xstar,gm)-v(p,tt,-x,xstar,gm)-v(p,tt,-x,-xstar,gm);
201
0
            auxnew=ccaux*(-kprice*exp(-xstar*0.5*(1.0-gm))+hbarr*exp(xstar*0.5*(1.0+gm)));
202
0
            v1p=v1p+auxnew;
203
            /*
204
              !!
205
              !! Function L(p,tt,a,b,c,gm)
206
              !!
207
            */
208
0
            b=gm-1.0;
209
0
            c=-xstar;
210
0
            ccaux=llold(p,tt,x,b,c,gm)-llold(p,tt,-x,b,c,gm);
211
0
            auxnew=kprice*(1.0-gm)*ccaux;
212
0
            v1p=v1p+auxnew;
213
214
0
            b=-(gm+1.0);
215
0
            c=xstar;
216
0
            ccaux=llold(p,tt,x,b,c,gm)-llold(p,tt,-x,b,c,gm);
217
0
            auxnew=-expGammaP*hbarr*ccaux;
218
0
            v1p=v1p+auxnew;
219
220
0
            b=(gm+1.0);
221
0
            c=-xstar;
222
0
            ccaux=llold(p,tt,x,b,c,gm)-llold(p,tt,-x,b,c,gm);
223
0
            auxnew=expGammaP*hbarr*gm*ccaux;
224
0
            v1p=v1p+auxnew;
225
            /*
226
              !!
227
              !! Function F(p,tt,a,b,c,gm)
228
              !!
229
            */
230
0
            b=gm-1.0;
231
0
            auxnew=-kprice*(1.0-gm)*(ff(p,tt,x,b,gm)-ff(p,tt,-x,b,gm));
232
0
            v1p=v1p+auxnew;
233
234
0
            b=gm+1.0;
235
0
            auxnew=-expGammaP*gm*hbarr*(ff(p,tt,x,b,gm)-ff(p,tt,-x,b,gm));
236
0
            v1p=v1p+auxnew;
237
238
0
            v1=v1+(alpha(tmp)-gm*0.5*sigmaq(tmp))*v1p;
239
0
        }
240
241
0
        v1=exp(disc)*et*v1*dt/(dsqpi*2.0);
242
243
0
        if(iord==1) return v0+v1;
244
245
        /*
246
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
247
          !!                                          !!
248
          !! Compute the second order term P_2        !!
249
          !!                                          !!
250
          !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
251
        */
252
253
0
        Real v2,dtp, tmp1,s;
254
0
        v2=0.0;
255
256
0
        for(i=1;i<=npoint;i++) {
257
0
            v2p=0.0;
258
0
            tmp=taumin+dt*(double)(2*i-1)*0.5;
259
0
            p=0.5*integs(tmp,taumax);
260
261
0
            dtp=(taumax-tmp)/(double)(npoint2);
262
0
            const Real outerPerturbation = alpha(tmp)-gm*0.5*sigmaq(tmp);
263
264
0
            for(j=1;j<=npoint2; j++) {
265
0
                tmp1=tmp+dtp*(double)(2*j-1)*0.50;
266
0
                s=0.50*integs(tmp1,taumax);
267
0
                const Real expGammaS = exp(gm*s);
268
0
                const Real innerPerturbation = alpha(tmp1)-gm*0.5*sigmaq(tmp1);
269
270
0
                caux=dll(s,p,tt,-x,-1.0+gm,-xstar,gm)-dll(s,p,tt,x,-1.0+gm,-xstar,gm);
271
0
                v2pp=caux*kprice*(1.0-gm);
272
273
0
                caux=dll(s,p,tt,-x,-1.0-gm,xstar,gm)-dll(s,p,tt,x,-1.0-gm,xstar,gm);
274
0
                v2pp=v2pp-expGammaS*hbarr*caux;
275
276
0
                caux=dll(s,p,tt,-x,1.0+gm,-xstar,gm)-dll(s,p,tt,x,1.0+gm,-xstar,gm);
277
0
                v2pp=v2pp+expGammaS*gm*hbarr*caux;
278
279
0
                caux=+dvv(s,p,tt,-x,xstar,gm)-dvv(s,p,tt,x,xstar,gm);
280
0
                caux=caux+(dvv(s,p,tt,-x,-xstar,gm)-dvv(s,p,tt,x,-xstar,gm));
281
0
                v2pp=v2pp+barrierFactor*caux;
282
283
0
                caux=dff(s,p,tt,-x,-1.0+gm,gm)-dff(s,p,tt,x,-1.0+gm,gm);
284
0
                v2pp=v2pp-(1.0-gm)*kprice*caux;
285
286
0
                caux=dff(s,p,tt,-x,1.0+gm,gm)-dff(s,p,tt,x,1.0+gm,gm);
287
0
                v2pp=v2pp-expGammaS*gm*hbarr*caux;
288
289
0
                v2pp=v2pp*0.5*(1.0-gm);
290
291
0
                caux=-ddll(s,p,tt,-x,-1.0+gm,-xstar,gm)+ddll(s,p,tt,x,-1.0+gm,-xstar,gm);
292
0
                v2pp=v2pp+caux*kprice*(1.0-gm);
293
294
0
                caux=-ddll(s,p,tt,-x,-1.0-gm,xstar,gm)+ddll(s,p,tt,x,-1.0-gm,xstar,gm);
295
0
                v2pp=v2pp-expGammaS*hbarr*caux;
296
297
0
                caux=-ddll(s,p,tt,-x,1.0+gm,-xstar,gm)+ddll(s,p,tt,x,1.0+gm,-xstar,gm);
298
0
                v2pp=v2pp+expGammaS*gm*hbarr*caux;
299
300
0
                caux=-ddvv(s,p,tt,-x,xstar,gm)+ddvv(s,p,tt,x,xstar,gm);
301
0
                caux=caux+(-dvv(s,p,tt,-x,-xstar,gm)+dvv(s,p,tt,x,-xstar,gm));
302
303
0
                v2pp=v2pp+barrierFactor*caux;
304
305
0
                caux=-ddff(s,p,tt,-x,-1+gm,gm)+ddff(s,p,tt,x,-1+gm,gm);
306
0
                v2pp=v2pp-(1.0-gm)*kprice*caux;
307
308
0
                caux=-ddff(s,p,tt,-x,1.0+gm,gm)+ddff(s,p,tt,x,1.0+gm,gm);
309
0
                v2pp=v2pp-expGammaS*gm*hbarr*caux;
310
311
0
                v2p=v2p+innerPerturbation*v2pp;
312
0
            }
313
314
0
            v2=v2+v2p*outerPerturbation*dtp;
315
0
        }
316
317
0
        v2=exp(disc)*et*v2*dt;
318
319
0
        return v0+v1+v2;
320
0
    }
321
322
323
0
    Real PHID(Real Z){
324
        /*
325
         *     Normal distribution probabilities accurate to 1D-15.
326
         *     Z = number of standard deviations from the mean.
327
         *
328
         *     The software that computes the normal distribution
329
         *     probabilities has been developed by M.C. Recchioni
330
         *     based upon algorithm 5666 (Programmer Alan Miller)
331
         *     for the error function, taken from:
332
         *     Hart, J.F. et al, 'Computer Approximations', Wiley, 1968
333
         *
334
         */
335
0
        Real P0, P1, P2, P3, P4, P5, P6;
336
0
        Real Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7;
337
0
        Real P, EXPNTL, CUTOFF, ZABS;
338
339
0
        P0 = 220.2068679123761;
340
0
        P1 = 221.2135961699311;
341
0
        P2 = 112.0792914978709;
342
0
        P3 = 33.91286607838300;
343
0
        P4 = 6.373962203531650;
344
0
        P5 = 0.7003830644436881;
345
0
        P6 = 0.03526249659989109;
346
347
0
        Q0 = 440.4137358247522;
348
0
        Q1 = 793.8265125199484;
349
0
        Q2 = 637.3336333788311;
350
0
        Q3 = 296.5642487796737;
351
0
        Q4 = 86.78073220294608;
352
0
        Q5 = 16.064177579206950;
353
0
        Q6 = 1.7556671631826420;
354
0
        Q7 = 0.088388347648318440;
355
0
        CUTOFF = 7.071067811865475;
356
357
0
        ZABS = fabs(Z);
358
        /*
359
          |Z| > 37
360
        */
361
0
        if (ZABS > 37)
362
0
            P = 0;
363
0
        else
364
0
        {
365
            /*
366
              |Z| <= 37
367
            */
368
0
            EXPNTL =exp(-ZABS*ZABS/2);
369
            /*
370
              |Z| < CUTOFF = 10/SQRT(2)
371
            */
372
0
            if ( ZABS < CUTOFF )
373
0
                P = EXPNTL*((((((P6*ZABS + P5)*ZABS + P4)*ZABS + P3)*ZABS+ P2)*ZABS + P1)*ZABS + P0)/(((((((Q7*ZABS + Q6)*ZABS + Q5)*ZABS + Q4)*ZABS + Q3)*ZABS + Q2)*ZABS + Q1)*ZABS + Q0);
374
            /*
375
              |Z| >= CUTOFF.
376
            */
377
0
            else
378
0
                P = EXPNTL/(ZABS + 1/(ZABS + 2/(ZABS + 3/(ZABS + 4/(ZABS + 0.65)))))/sqrtTwoPi;
379
380
0
        }
381
0
        if ( Z > 0 ) P = 1 - P;
382
383
0
        return(P);
384
0
    }
385
386
387
    /*
388
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
389
      !!                                                              !!
390
      !! Functions needed to compute the  first order term  P_1       !!
391
      !!                                                              !!
392
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
393
    */
394
395
    /*
396
      !!
397
      !! Function F(p,tt,a,b,gm)
398
      !!
399
    */
400
0
    Real ff(Real p,Real tt,Real a, Real b, Real gm) {
401
0
        Real phid;
402
0
        Real aa, caux;
403
404
0
        aa=-(b*p-b*tt+a)/std::sqrt(2.0*(tt-p));
405
406
0
        caux=2.0*sqrtPi*PHID(aa);
407
0
        aa=b*b-(1.0-gm)*(1.0-gm);
408
0
        aa=aa/4.0;
409
0
        phid=exp(-0.5*a*b)*exp(aa*(tt-p))*caux;
410
411
0
        return phid;
412
0
    }
413
414
    /*
415
      !!
416
      !! Function  E(p,tt,a,b,gm)
417
      !!
418
    */
419
    Real v(Real p, Real tt,Real a,Real b,Real gm)
420
0
    {
421
0
        Real result;
422
0
        Real aa,caux;
423
424
0
        aa=-(p*(a-b)+b*tt)/std::sqrt(2.0*p*tt*(tt-p));
425
0
        caux=PHID(aa);
426
427
0
        aa=exp((a-b)*(a-b)/(4.0*tt))*exp((1.0-gm)*(1.0-gm)*tt/4.0)*std::sqrt(tt);
428
0
        result=caux/aa;
429
430
0
        return(result);
431
0
    }
432
433
    /*
434
      !!
435
      !! Fuction L(p,tt,a,b,c,gm)
436
      !!
437
    */
438
0
    Real llold(Real p,Real tt, Real a, Real b,Real c, Real gm){
439
0
        Real bvnd;
440
0
        Real xx,yy,rho,caux;
441
0
        Real aa;
442
443
0
        xx=(-a+b*(tt-p))/std::sqrt(2.0*(tt-p));
444
0
        yy=(-a+b*tt+c)/std::sqrt(2.0*tt);
445
0
        rho=std::sqrt((tt-p)/tt);
446
0
        aa=b*b-(1.0-gm)*(1.0-gm);
447
0
        aa=aa/4.0;
448
0
        caux=ND2(-xx,-yy,rho);
449
450
0
        bvnd=2.0*sqrtPi*exp(-a*b*0.5)*exp(aa*(tt-p))*caux;
451
0
        return(bvnd);
452
0
    }
453
454
    /*
455
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
456
      !!                                                              !!
457
      !! Functions needed to compute the  second order term  P_2      !!
458
      !!                                                              !!
459
      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
460
    */
461
462
    /*
463
      !!
464
      !! Function  D_E(s,p,tt,a,b,gm)
465
      !!
466
    */
467
    Real dvv(Real s,Real p,Real tt,Real a,Real b,Real gm)
468
0
    {
469
0
        Real result;
470
0
        Real aa,caux,caux1,caux2;
471
0
        Real xx,yy,rho;
472
473
0
        aa=(a*p+b*(tt-p))/std::sqrt(2.0*p*tt*(tt-p));
474
0
        caux=PHID(aa);
475
476
0
        aa=exp((a-b)*(a-b)/(4.0*tt))*exp((1.0-gm)*(1.0-gm)*tt/4.0)*std::sqrt(tt);
477
0
        caux=-caux/aa;
478
479
0
        xx=(a*p+b*(tt-p))/std::sqrt(2.0*tt*p*(tt-p));
480
0
        yy=(a*s+b*(tt-s))/std::sqrt(2.0*tt*s*(tt-s));
481
0
        rho=std::sqrt((s*(tt-p))/(p*(tt-s)));
482
0
        caux1=ND2(-xx,-yy,rho);
483
0
        caux1=caux1/aa;
484
485
486
0
        aa=exp((a+b)*(a+b)/(4.0*tt))*exp((1.0-gm)*(1.0-gm)*tt/4.0)*std::sqrt(tt);
487
488
0
        xx=(a*p-b*(tt-p))/std::sqrt(2.0*tt*p*(tt-p));
489
0
        yy=(a*s-b*(tt-s))/std::sqrt(2.0*tt*s*(tt-s));
490
0
        rho=std::sqrt((s*(tt-p))/(p*(tt-s)));
491
0
        caux2=ND2(-xx,-yy,rho);
492
0
        caux2=caux2/aa;
493
0
        result=(caux+caux1+caux2)/(2.0*sqrtPi);
494
0
        return(result);
495
0
    }
496
497
    /*
498
      !!
499
      !! Function D_F(s,p,tt,a,b,gm)
500
      !!
501
    */
502
    Real dff(Real s, Real p,Real tt,Real a,Real b,Real gm)
503
0
    {
504
0
        Real result;
505
0
        Real aa,caux,caux1,caux2;
506
0
        Real xx,yy,rho;
507
508
0
        xx=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
509
0
        caux=-PHID(xx)*exp(-0.5*a*b);
510
511
0
        xx=(a+b*(tt-p))/std::sqrt(2.0*(tt-p));
512
0
        yy=(a+b*(tt-s))/std::sqrt(2.0*(tt-s));
513
0
        rho=std::sqrt((tt-p)/(tt-s));
514
0
        caux1=ND2(-xx,-yy,rho);
515
0
        caux1=exp(0.5*a*b)*caux1;
516
517
0
        xx=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
518
0
        yy=(a-b*(tt-s))/std::sqrt(2.0*(tt-s));
519
0
        rho=std::sqrt((tt-p)/(tt-s));
520
0
        caux2=ND2(-xx,-yy,rho);
521
0
        caux2=exp(-0.5*a*b)*caux2;
522
523
0
        aa=exp((b*b-(1.0-gm)*(1.0-gm))*(tt-s)/4.0);
524
525
0
        result=(caux+caux1+caux2)*aa;
526
0
        return(result);
527
0
    }
528
529
530
    /*
531
      !!
532
      !! Function D_L(s,p,a,b,c,gm)
533
      !!
534
    */
535
    Real dll(Real s,Real p,Real tt,Real a,Real b,Real c,Real gm)
536
0
    {
537
0
        Real result;
538
0
        Real aa,caux,caux1;
539
0
        Real sigmarho[4],limit[4],epsi;
540
541
0
        epsi=1.e-12;
542
0
        limit[1]=(a+b*(tt-p))/std::sqrt(2.0*(tt-p));
543
0
        limit[2]=(a+b*(tt-s))/std::sqrt(2.0*(tt-s));
544
0
        limit[3]=(a+b*tt+c)/std::sqrt(2.0*tt);
545
0
        sigmarho[1]=std::sqrt((tt-p)/(tt-s));
546
0
        sigmarho[2]=std::sqrt((tt-p)/tt);
547
0
        sigmarho[3]=std::sqrt((tt-s)/tt);
548
549
0
        caux=exp(0.5*a*b)*tvtl(0,limit,sigmarho,epsi);
550
551
0
        limit[1]=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
552
0
        limit[2]=(-a+b*(tt-s))/std::sqrt(2.0*(tt-s));
553
0
        limit[3]=(-a+b*tt+c)/std::sqrt(2.0*tt);
554
0
        sigmarho[1]=-std::sqrt((tt-p)/(tt-s));
555
0
        sigmarho[2]=-std::sqrt((tt-p)/tt);
556
0
        sigmarho[3]=std::sqrt((tt-s)/tt);
557
558
0
        caux1=-exp(-0.5*a*b)*tvtl(0,limit,sigmarho,epsi);
559
560
0
        aa=exp((b*b-(1.0-gm)*(1.0-gm))*(tt-s)/4.0);
561
562
563
0
        result=(caux+caux1)*aa;
564
565
0
        return(result);
566
0
    }
567
568
    /*
569
      !!
570
      !! Derivative with respect to a of the function D_F(s,p,tt,a,b,gm)
571
      !!
572
    */
573
    Real ddff(Real s, Real p,Real tt,Real a,Real b,Real gm)
574
0
    {
575
0
        Real aa,caux,caux1,caux2,caux3,caux4;
576
0
        Real xx,yy,rho;
577
0
        Real result;
578
579
0
        xx=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
580
0
        caux=PHID(xx)*exp(-0.5*a*b);
581
582
0
        xx=(a+b*(tt-p))/std::sqrt(2.0*(tt-p));
583
0
        yy=(a+b*(tt-s))/std::sqrt(2.0*(tt-s));
584
0
        rho=std::sqrt((tt-p)/(tt-s));
585
0
        caux1=ND2(-xx,-yy,rho);
586
0
        caux1=exp(0.5*a*b)*caux1;
587
588
0
        xx=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
589
0
        yy=(a-b*(tt-s))/std::sqrt(2.0*(tt-s));
590
0
        rho=std::sqrt((tt-p)/(tt-s));
591
0
        caux2=ND2(-xx,-yy,rho);
592
0
        caux2=-exp(-0.5*a*b)*caux2;
593
594
0
        caux=0.5*b*(caux+caux1+caux2);
595
596
0
        xx=(a+b*(tt-p))/std::sqrt(2.0*(tt-p));
597
0
        yy=b*std::sqrt(p-s)/sqrtTwo;
598
0
        caux1=exp(-0.5*xx*xx)*exp(0.5*a*b)*PHID(yy)/(2.0*std::sqrt(PI*(tt-p)));
599
600
601
0
        xx=(a+b*(tt-s))/std::sqrt(2.0*(tt-s));
602
0
        yy=a*std::sqrt(p-s)/std::sqrt(2.0*(tt-p)*(tt-s));
603
0
        caux2=exp(-0.5*xx*xx)*exp(0.5*a*b)*PHID(yy)/(2.0*std::sqrt(PI*(tt-s)));
604
605
0
        xx=(a-b*(tt-p))/std::sqrt(2.0*(tt-p));
606
0
        yy=b*std::sqrt(p-s)/sqrtTwo;
607
0
        caux3=-exp(-0.5*xx*xx)*exp(-0.5*a*b)*PHID(yy)/(2.0*std::sqrt(PI*(tt-p)));
608
609
610
0
        xx=(a-b*(tt-s))/std::sqrt(2.0*(tt-s));
611
0
        yy=a*std::sqrt(p-s)/std::sqrt(2.0*(tt-p)*(tt-s));
612
0
        caux4=exp(-0.5*xx*xx)*exp(-0.5*a*b)*PHID(yy)/(2.0*std::sqrt(PI*(tt-s)));
613
614
615
616
0
        aa=exp((b*b-(1.0-gm)*(1.0-gm))*(tt-p)/4.0);
617
618
619
0
        result=(caux+caux1+caux2+caux3+caux4)*aa;
620
0
        return(result);
621
0
    }
622
623
    /*
624
      !!
625
      !! Derivative with respect to a of the function D_L(s,p,tt,a,b,c,gm)
626
      !!
627
    */
628
    Real ddll(Real s,Real p,Real tt, Real ax, Real bx,Real c, Real gm)
629
0
    {
630
0
        Real result;
631
0
        Real aa,caux,caux1;
632
0
        Real sigmarho[4],sigma[4],limit[4];
633
0
        int idx;
634
0
        Real epsi;
635
636
0
        epsi=1.e-12;
637
0
        limit[1]=(ax+bx*(tt-p))/std::sqrt(2.0*(tt-p));
638
0
        limit[2]=(ax+bx*(tt-s))/std::sqrt(2.0*(tt-s));
639
0
        limit[3]=(ax+bx*tt+c)/std::sqrt(2.0*tt);
640
0
        sigmarho[1]=std::sqrt((tt-p)/(tt-s));
641
0
        sigmarho[2]=std::sqrt((tt-p)/tt);
642
0
        sigmarho[3]=std::sqrt((tt-s)/tt);
643
0
        sigma[1]=std::sqrt(1.0-sigmarho[1]*sigmarho[1]);
644
0
        sigma[2]=std::sqrt(1.0-sigmarho[2]*sigmarho[2]);
645
0
        sigma[3]=std::sqrt(1.0-sigmarho[3]*sigmarho[3]);
646
647
0
        caux=0.5*bx*tvtl(0,limit,sigmarho,epsi);
648
649
650
0
        idx=1;
651
0
        caux=caux+derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*(tt-p));
652
653
0
        idx=2;
654
0
        caux=caux+derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*(tt-s));
655
656
0
        idx=3;
657
0
        caux=caux+derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*tt);
658
659
0
        caux=exp(0.5*ax*bx)*caux;
660
661
0
        limit[1]=(ax-bx*(tt-p))/std::sqrt(2.0*(tt-p));
662
0
        limit[2]=(-ax+bx*(tt-s))/std::sqrt(2.0*(tt-s));
663
0
        limit[3]=(-ax+bx*tt+c)/std::sqrt(2.0*tt);
664
0
        sigmarho[1]=-std::sqrt((tt-p)/(tt-s));
665
0
        sigmarho[2]=-std::sqrt((tt-p)/tt);
666
0
        sigmarho[3]=std::sqrt((tt-s)/tt);
667
0
        sigma[1]=std::sqrt(1.0-sigmarho[1]*sigmarho[1]);
668
0
        sigma[2]=std::sqrt(1.0-sigmarho[2]*sigmarho[2]);
669
0
        sigma[3]=std::sqrt(1.0-sigmarho[3]*sigmarho[3]);
670
671
0
        caux1=0.5*bx*tvtl(0,limit,sigmarho,epsi);
672
673
0
        idx=1;
674
0
        caux1=caux1-derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*(tt-p));
675
676
0
        idx=2;
677
0
        caux1=caux1+derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*(tt-s));
678
679
680
0
        idx=3;
681
0
        caux1=caux1+derivn3(limit,sigmarho,sigma,idx)/std::sqrt(2.0*tt);
682
683
0
        caux1=exp(-0.5*ax*bx)*caux1;
684
685
686
0
        aa=exp((bx*bx-(1.0-gm)*(1.0-gm))*(tt-s)/4.0);
687
688
0
        result=(caux+caux1)*aa;
689
0
        return(result);
690
0
    }
691
692
    /*
693
      !!
694
      !!   Derivative with respect to a of the function D_E(s,p,tt,a,b,gm)
695
      !!
696
    */
697
    Real ddvv(Real s, Real p, Real tt, Real a, Real b, Real gm)
698
0
    {
699
0
        Real result;
700
0
        Real aa,caux,caux1,caux2,caux6;
701
0
        Real caux3,caux4,caux5,aux;
702
0
        Real xx,yy,rho;
703
704
0
        aa=(a*p+b*(tt-p))/std::sqrt(2.0*p*tt*(tt-p));
705
0
        caux=PHID(aa);
706
707
0
        aa=exp(-(a-b)*(a-b)/(4.0*tt))/tt;
708
709
0
        caux=0.5*aa*caux*(a-b);
710
711
0
        xx=(a*p+b*(tt-p))/std::sqrt(2.0*tt*p*(tt-p));
712
0
        yy=(a*s+b*(tt-s))/std::sqrt(2.0*tt*s*(tt-s));
713
0
        rho=std::sqrt((s*(tt-p))/(p*(tt-s)));
714
0
        caux1=ND2(-xx,-yy,rho);
715
0
        caux1=-0.5*aa*caux1*(a-b);
716
717
718
0
        aa=exp(-(a+b)*(a+b)/(4.0*tt))/tt;
719
720
0
        xx=(a*p-b*(tt-p))/std::sqrt(2.0*tt*p*(tt-p));
721
0
        yy=(a*s-b*(tt-s))/std::sqrt(2.0*tt*s*(tt-s));
722
0
        rho=std::sqrt((s*(tt-p))/(p*(tt-s)));
723
0
        caux2=ND2(-xx,-yy,rho);
724
0
        caux2=-0.5*aa*caux2*(a+b);
725
726
0
        aa=-b*std::sqrt((p-s)/std::sqrt(2.0*p*s));
727
0
        aux=std::sqrt(p/(PI*tt*(tt-p)))*PHID(aa);
728
729
0
        xx=(a+b)*(a+b)/(4.0*tt);
730
0
        yy=(a*p-b*(tt-p))*(a*p-b*(tt-p))/(4.0*p*tt*(tt-p));
731
0
        caux3=aux*exp(-xx)*exp(-yy)/2.0;
732
733
734
0
        xx=(a-b)*(a-b)/(4.0*tt);
735
0
        yy=(a*p+b*(tt-p))*(a*p+b*(tt-p))/(4.0*p*tt*(tt-p));
736
0
        caux4=aux*exp(-xx)*exp(-yy)/2.0;
737
738
0
        aa=a*std::sqrt((p-s)/std::sqrt(2.0*(tt-p)*(tt-s)));
739
0
        aux=std::sqrt(s/(PI*tt*(tt-s)))*PHID(aa);
740
741
0
        xx=(a+b)*(a+b)/(4.0*tt);
742
0
        yy=(a*s-b*(tt-s))*(a*s-b*(tt-s))/(4.0*s*tt*(tt-s));
743
0
        caux5=aux*exp(-xx)*exp(-yy)/2.0;
744
745
0
        xx=(a-b)*(a-b)/(4.0*tt);
746
0
        yy=(a*s+b*(tt-s))*(a*s+b*(tt-s))/(4.0*s*tt*(tt-s));
747
0
        caux6=aux*exp(-xx)*exp(-yy)/2.0;
748
749
0
        aux=exp((1.0-gm)*(1.0-gm)*tt/4.0)*std::sqrt(tt);
750
751
0
        result=(caux+caux1+caux2+caux3+caux4+caux5+caux6)/(aux*2.0*sqrtPi);
752
0
        return(result);
753
0
    }
754
755
    /*
756
      !!
757
      !! Derivn3 computes the derivatives of the trivariate cumulative normal
758
      !! distribution with respect to one of the integration limits
759
      !!
760
    */
761
    Real derivn3(const Real limit[4], const Real sigmarho[4], const Real sigma[4], int idx)
762
0
    {
763
0
        Real aa;
764
0
        Real xx,yy,rho,sc;
765
0
        Real deriv;
766
0
        sc=sqrtTwoPi;
767
768
0
        if(idx==1)
769
0
            {
770
0
                aa=exp(-0.5*limit[1]*limit[1]);
771
0
                xx=(limit[3]-sigmarho[2]*limit[1])/sigma[2];
772
0
                yy=(limit[2]-sigmarho[1]*limit[1])/sigma[1];
773
0
                rho=(sigmarho[3]-sigmarho[1]*sigmarho[2])/(sigma[1]*sigma[2]);
774
0
                deriv=aa*ND2(-xx,-yy,rho)/sc;
775
0
            }
776
0
        else
777
0
            {
778
0
                if(idx==2)
779
0
                    {
780
0
                        aa=exp(-0.5*limit[2]*limit[2]);
781
0
                        xx=(limit[1]-sigmarho[1]*limit[2])/sigma[1];
782
0
                        yy=(limit[3]-sigmarho[3]*limit[2])/sigma[3];
783
0
                        rho=(sigmarho[2]-sigmarho[1]*sigmarho[3])/(sigma[1]*sigma[3]);
784
0
                        deriv=aa*ND2(-xx,-yy,rho)/sc;
785
0
                    }
786
0
                else
787
0
                    {
788
                        //!!! idx=3
789
0
                        aa=exp(-0.5*limit[3]*limit[3]);
790
791
0
                        xx=(limit[1]-sigmarho[2]*limit[3])/sigma[2];
792
0
                        yy=(limit[2]-sigmarho[3]*limit[3])/sigma[3];
793
0
                        rho=(sigmarho[1]-sigmarho[2]*sigmarho[3])/(sigma[2]*sigma[3]);
794
0
                        deriv=aa*ND2(-xx,-yy,rho)/sc;
795
0
                    }
796
797
0
            }
798
0
        return(deriv);
799
0
    }
800
801
802
    Real BVTL(int NU, Real DH, Real DK, Real RRR );
803
    Real TVTMFN(Real X, Real H1, Real H2, Real H3,
804
                  Real R23, Real RUA, Real RUB, Real AR,
805
                  Real RUC, int NUC);
806
    template <class Integrand>
807
    Real KRNRDT(Real A, Real B, const Integrand& integrand, Real& error);
808
809
    template <class Integrand>
810
    Real ADONET(Real A, Real B, Real TOL, const Integrand& integrand);
811
812
0
    Real tvtl(int NU, const Real limit[4], const Real sigmarho[4], Real epsi) {
813
        /*
814
          A function for computing trivariate normal and t-probabilities.
815
816
          This function uses algorithms developed from the ideas
817
          described in the papers:
818
          R.L. Plackett, Biometrika 41(1954), pp. 351-360.
819
          Z. Drezner, Math. Comp. 62(1994), pp. 289-294.
820
          and uses adaptive integration.
821
822
          The software given here is based on algorithms described in
823
          the paper A. Genz: "Numerical Computation of Rectangular
824
          Bivariate and Trivariate Normal and t Probabilities",
825
          Statistics and Computing 14 (2004) 251-260.
826
827
          This software has been developed by M.C. Recchioni based on
828
          previous software developed by
829
          Alan Genz
830
          Department of Mathematics
831
          Washington State University
832
          Pullman, WA 99164-3113
833
          Email : alangenz@wsu.edu
834
          The software developed by A. Genz is available free of
835
          charge in the website:
836
          www.math.wsu.edu/faculty/genz/software/software.html
837
838
          The software calculates the probability that
839
          X(I) < H(I), for I = 1,2,3
840
841
          NU        INTEGER degrees of freedom; use NU = 0 for normal cases.
842
          LIMIT     REAL array of uppoer limits for probability distribution
843
          SIGMARHO  REAL array of three correlation coefficients, should
844
          contain the lower left portion of the correlation matrix.
845
          SIGMARHO should contains the values r21, r31, r23 in that order.
846
          EPSI      REAL required absolute accuracy; maximum accuracy for most
847
          computations is approximately 1D-14
848
849
        */
850
851
0
        Real result;
852
0
        const Real ONE=1.0, ZRO=0.0;
853
0
        Real EPS, TVT;
854
0
        Real PT, H1, H2, H3, R12, R13, R23, RUA, RUB, AR, RUC;
855
0
        EPS = max( 1.e-14, epsi );
856
0
        PT=halfPi;
857
858
0
        H1 = limit[1];
859
0
        H2 = limit[2];
860
0
        H3 = limit[3];
861
0
        R12 = sigmarho[1];
862
0
        R13 = sigmarho[2];
863
0
        R23 = sigmarho[3];
864
        /*
865
         *     Sort R's and check for special cases
866
         */
867
0
        if ( fabs(R12) > fabs(R13) ) {
868
0
            H2 = H3;
869
0
            H3 = limit[2];
870
0
            R12 = R13;
871
0
            R13 = sigmarho[1];
872
0
        }
873
874
0
        if ( fabs(R13) > fabs(R23) ) {
875
0
            H1 = H2;
876
0
            H2 = limit[1];
877
0
            R23 = R13;
878
0
            R13 = sigmarho[3];
879
0
        }
880
881
0
        TVT = 0.0;
882
0
        if ( (fabs(H1) + fabs(H2) + fabs(H3)) < EPS ) TVT = ( 1 + ( asin(R12) + asin(R13) + asin(R23) )/PT )/8.0;
883
884
0
        else  if ( (NU < 1) && ( (fabs(R12) + fabs(R13)) < EPS) )  TVT = PHID(H1)*BVTL( NU, H2, H3, R23 );
885
886
0
        else  if ( (NU < 1) && ((fabs(R13) + fabs(R23))< EPS) ) TVT = PHID(H3)*BVTL( NU, H1, H2, R12 );
887
888
0
        else if( (NU < 1) && ((fabs(R12) + fabs(R23))< EPS) ) TVT = PHID(H2)*BVTL( NU, H1, H3, R13 );
889
890
0
        else if ( (1.0 - R23)< EPS ) TVT = BVTL( NU, H1, min( H2, H3 ), R12 );
891
892
0
        else  if ( (R23 + 1.0) <EPS ) {
893
0
            if  ( H2 > -H3 ) TVT = BVTL( NU, H1, H2, R12 ) - BVTL( NU, H1, -H3, R12 );}
894
0
        else
895
0
            {
896
                /*
897
                 *        Compute singular TVT value
898
                 */
899
0
                if ( NU < 1 ) TVT = BVTL( NU, H2, H3, R23 )*PHID(H1);
900
901
0
                else if ( R23 > 0 ) TVT = BVTL( NU, H1, min( H2, H3 ), ZRO );
902
903
0
                else if ( H2 > -H3 ) TVT = BVTL( NU, H1, H2, ZRO ) - BVTL( NU, H1, -H3, ZRO );
904
905
                /*
906
                 *        Use numerical integration to compute probability
907
                 *
908
                 */
909
0
                RUA = asin( R12 );
910
0
                RUB = asin( R13 );
911
0
                AR = asin( R23);
912
0
                RUC = SIGN( PT, AR ) - AR;
913
0
                const auto integrand = [&](Real X) {
914
0
                    return TVTMFN(X, H1, H2, H3, R23, RUA, RUB, AR, RUC, NU);
915
0
                };
916
0
                TVT = TVT + ADONET(ZRO, ONE, EPS, integrand) / (4.0 * PT);
917
0
            }
918
0
        result = max( ZRO, min( TVT, ONE ) );
919
920
0
        return(result);
921
0
    }
922
923
    void SINCS(Real v1,Real& v2, Real& v3);
924
    Real PNTGND(int , Real ,Real ,Real ,
925
                  Real ,Real ,Real ,Real );
926
927
    Real TVTMFN(Real X, Real H1, Real H2, Real H3, Real R23,
928
0
                  Real RUA, Real RUB, Real AR,Real RUC, int NUC ){
929
        /*
930
          Computes Plackett formula integrands
931
        */
932
933
0
        Real R12=0.0, RR2=0, R13=0.0, RR3=0.0, R=0.0, RR=0.0;
934
0
        const Real ZRO = 0.0;
935
0
        Real result = 0.0;
936
937
0
        SINCS( RUA*X, R12, RR2 );
938
0
        SINCS( RUB*X, R13, RR3 );
939
940
0
        if ( fabs(RUA)> 0 )  result += RUA*PNTGND( NUC, H1,H2,H3, R13,R23,R12,RR2);
941
0
        if( fabs(RUB)>0 ) result += RUB*PNTGND( NUC, H1,H3,H2, R12,R23,R13,RR3 ) ;
942
0
        if ( NUC > 0 )
943
0
            {
944
0
                SINCS( AR + RUC*X, R, RR );
945
0
                result -= RUC*PNTGND( NUC, H2, H3, H1, ZRO, ZRO, R, RR );
946
0
            }
947
0
        return(result);
948
0
    }
949
    //
950
951
952
    void SINCS(Real X, Real& SX, Real& CS )
953
0
    {
954
        /*
955
          Computes SIN(X), COS(X)^2, with series approx. for |X| near PI/2
956
        */
957
0
        constexpr double PT = 1.57079632679489661923132169163975;
958
0
        Real EE;
959
0
        EE = (PT - fabs(X))*(PT - fabs(X));
960
961
0
        if ( EE < 5e-5 )
962
0
            {
963
0
                SX = SIGN( 1 - EE*( 1 - EE/12 )/2, X );
964
0
                CS = EE*( 1 - EE*( 1 - 2*EE/15 )/3 );
965
0
            }
966
0
        else
967
0
            {
968
0
                SX = sin(X);
969
0
                CS = 1 - SX*SX;
970
0
            }
971
0
    }
972
    //
973
974
    template <class Integrand>
975
0
    Real ADONET(Real A, Real B, Real TOL, const Integrand& integrand) {
976
        //
977
        //     One Dimensional Globally Adaptive Integration Function
978
        //
979
0
        const Size NL=100;
980
0
        Size I, IM, IP;
981
0
        Real EI[101], AI[101], BI[101], FI[101], FIN=0.0;
982
0
        Real result,ERR;
983
984
985
0
        AI[1] = A;
986
0
        BI[1] = B;
987
0
        ERR = 1;
988
0
        IP = 1;
989
0
        IM = 1;
990
0
        while ( ((4*ERR)> TOL) && (IM< NL) )
991
0
            {
992
0
                IM = IM + 1;
993
0
                BI[IM] = BI[IP];
994
0
                AI[IM] = (AI[IP] + BI[IP] )/2.0;
995
0
                BI[IP] = AI[IM];
996
0
                FI[IP] = KRNRDT(AI[IP], BI[IP], integrand, EI[IP]);
997
0
                FI[IM] = KRNRDT(AI[IM], BI[IM], integrand, EI[IM]);
998
999
0
                ERR = 0.0;
1000
0
                FIN = 0.0;
1001
0
                for(I = 1; I<=IM; I++)
1002
0
                    {
1003
0
                        if( EI[I] > EI[IP]) IP = I;
1004
0
                        FIN = FIN + FI[I];
1005
0
                        ERR = ERR + EI[I]*EI[I];
1006
0
                    }
1007
0
                ERR = std::sqrt(ERR);
1008
0
            }
1009
0
        result=FIN;
1010
        //   ADONET = FIN
1011
0
        return(result);
1012
0
    }
1013
    //
1014
1015
    template <class Integrand>
1016
0
    Real KRNRDT(Real A, Real B, const Integrand& integrand, Real& ERR) {
1017
1018
        //
1019
        //     Kronrod Rule
1020
        //
1021
0
        Real T, CEN, FC, WID, RESG, RESK;
1022
1023
0
        Real result;
1024
        //
1025
        //        The abscissae and weights are given for the interval (-1,1);
1026
        //        only positive abscissae and corresponding weights are given.
1027
        //
1028
        //        XGK    - abscissae of the 2N+1-point Kronrod rule:
1029
        //                 XGK(2), XGK(4), ...  N-point Gauss rule abscissae;
1030
        //                 XGK(1), XGK(3), ...  optimally added abscissae.
1031
        //        WGK    - weights of the 2N+1-point Kronrod rule.
1032
        //        WG     - weights of the N-point Gauss rule.
1033
        //
1034
0
        int J, N=11;
1035
1036
0
        static const Real WG[7] = {
1037
0
            0.0, 0.2729250867779007, 0.05566856711617449,
1038
0
            0.1255803694649048, 0.1862902109277352,
1039
0
            0.2331937645919914, 0.2628045445102478
1040
0
        };
1041
0
        static const Real XGK[13] = {
1042
0
            0.0, 0.0000000000000000, 0.9963696138895427,
1043
0
            0.9782286581460570, 0.9416771085780681,
1044
0
            0.8870625997680953, 0.8160574566562211,
1045
0
            0.7301520055740492, 0.6305995201619651,
1046
0
            0.5190961292068118, 0.3979441409523776,
1047
0
            0.2695431559523450, 0.1361130007993617
1048
0
        };
1049
0
        static const Real WGK[13] = {
1050
0
            0.0, 0.1365777947111183, 0.00976544104596129,
1051
0
            0.02715655468210443, 0.04582937856442671,
1052
0
            0.06309742475037484, 0.07866457193222764,
1053
0
            0.09295309859690074, 0.1058720744813894,
1054
0
            0.1167395024610472, 0.1251587991003195,
1055
0
            0.1312806842298057, 0.1351935727998845
1056
0
        };
1057
        /*
1058
          Major variables
1059
1060
          CEN  - mid point of the interval
1061
          WID  - half-length of the interval
1062
          RESG - result of the N-point Gauss formula
1063
          RESK - result of the 2N+1-point Kronrod formula
1064
          Compute the 2N+1-point Kronrod approximation to
1065
          the integral, and estimate the absolute error.
1066
        */
1067
0
        WID = ( B - A )/2.0;
1068
0
        CEN = ( B + A )/2.0;
1069
1070
0
        FC = integrand(CEN);
1071
1072
0
        RESG = FC*WG[0+1];
1073
0
        RESK = FC*WGK[0+1];
1074
1075
0
        for (J = 1; J<= N; J++)
1076
0
            {
1077
0
                T = WID*XGK[J+1];
1078
0
                FC = integrand(CEN-T) + integrand(CEN+T);
1079
0
                RESK = RESK + WGK[J+1]*FC;
1080
0
                if((J-2*int(J/2)) == 0 ) RESG = RESG + WG[1+J/2]*FC;
1081
0
            }
1082
0
        result = WID*RESK;
1083
0
        ERR = fabs( WID*( RESK - RESG ) );
1084
0
        return(result);
1085
0
    }
1086
1087
    //
1088
    Real  STUDNT(int NU, Real T )
1089
0
    {
1090
        /*
1091
          Student t Distribution Function
1092
        */
1093
0
        const Real ZRO=0.0, ONE=1.0;
1094
0
        Real CSSTHE, SNTHE, POLYN, TT, TS, RN;
1095
0
        Real result;
1096
1097
1098
0
        if ( NU < 1 ) result= PHID( T );
1099
0
        else if ( NU == 1 ) result = ( 1 + 2.0*atan(T)/PI )/2.0;
1100
0
        else if ( NU == 2 ) result = ( 1 + T/std::sqrt(2.0 + T*T))/2.0;
1101
0
        else
1102
0
            {
1103
0
                TT = T*T;
1104
0
                CSSTHE = 1/( 1 + TT/double(NU) );
1105
0
                POLYN = 1;
1106
0
                for (int J = NU-2; J >= 2; J -= 2)
1107
0
                    {
1108
0
                        POLYN = 1.0 + ( J - 1.0 )*CSSTHE*POLYN/(double)J;
1109
0
                    }
1110
0
                if ((NU-2*int(NU/2) ) == 1 )
1111
0
                    {
1112
0
                        RN = NU;
1113
0
                        TS = T/std::sqrt(RN);
1114
0
                        result = ( 1.0 + 2.0*( atan(TS) + TS*CSSTHE*POLYN )/PI )/2.0;
1115
0
                    }
1116
0
                else
1117
0
                    {
1118
0
                        SNTHE = T/std::sqrt(NU+TT);
1119
0
                        result = ( 1 + SNTHE*POLYN )/2.0;
1120
0
                    }
1121
0
                result = max( ZRO, min( result, ONE ) );
1122
0
            }
1123
0
        return(result);
1124
0
    }
1125
1126
    //
1127
    Real BVTL(int NU, Real DH, Real DK, Real R )
1128
0
    {
1129
        /*
1130
          A function for computing bivariate t probabilities.
1131
          This function is based on the method described by
1132
          Dunnett, C.W. and M. Sobel, (1954),
1133
          A bivariate generalization of Student's t-distribution
1134
          with tables for certain special cases,
1135
          Biometrika 41, pp. 153-169.
1136
          The software given here has been developed by M.C. Recchioni based on previous
1137
          software developed by
1138
          Alan Genz
1139
          Department of Mathematics
1140
          Washington State University
1141
          Pullman, WA 99164-3113
1142
          Email : alangenz@wsu.edu
1143
          The software developed by A. Genz is available free of charge in
1144
          the website: www.math.wsu.edu/faculty/genz/software/software.html
1145
          ***
1146
1147
          BVTL - calculate the probability that X < DH and Y < DK.
1148
1149
          parameters
1150
1151
          NU number of degrees of freedom
1152
          DH 1st lower integration limit
1153
          DK 2nd lower integration limit
1154
          R   correlation coefficient
1155
        */
1156
0
        Real TPI, ORS, HRK, KRH, BVT, SNU;
1157
0
        Real GMPH, GMPK, XNKH, XNHK, QHRK, HKN, HPK, HKRN;
1158
0
        Real BTNCKH, BTNCHK, BTPDKH, BTPDHK, ONE, EPS;
1159
0
        Real result;
1160
0
        ONE = 1;
1161
0
        EPS = 1e-15;
1162
0
        if ( NU <1 ) result = ND2( -DH, -DK, R );
1163
1164
0
        else if ( (1 - R)<= EPS ) result = STUDNT( NU, min( DH, DK ) );
1165
1166
0
        else  if( (R + 1)<=EPS )
1167
0
            {
1168
0
                if( DH > -DK ) result = STUDNT( NU, DH ) - STUDNT( NU, -DK );
1169
0
                else
1170
0
                    result = 0.0;
1171
0
            }
1172
0
        else
1173
0
            {
1174
0
                const int HS = static_cast<int>(SIGN(ONE, DH - R*DK));
1175
0
                const int KS = static_cast<int>(SIGN(ONE, DK - R*DH));
1176
0
                TPI = twoPi;
1177
0
                SNU = (double)NU;
1178
0
                SNU = std::sqrt(SNU);
1179
0
                ORS = 1.0 - R*R;
1180
0
                HRK = DH - R*DK;
1181
0
                KRH = DK - R*DH;
1182
0
                if((fabs(HRK) + ORS)> 0 )
1183
0
                    {
1184
0
                        XNHK = HRK*HRK/( HRK*HRK + ORS*( NU + DK*DK ) );
1185
0
                        XNKH = KRH*KRH/( KRH*KRH+ ORS*( NU + DH*DH ) );
1186
0
                    }
1187
0
                else
1188
0
                    {
1189
0
                        XNHK = 0.0;
1190
0
                        XNKH = 0.0;
1191
0
                    }
1192
1193
0
                if((NU-2*(int)(NU/2))==0 )
1194
0
                    {
1195
0
                        BVT = atan2( std::sqrt(ORS), -R )/TPI;
1196
0
                        GMPH = DH/std::sqrt(16*( NU + DH*DH ));
1197
0
                        GMPK = DK/std::sqrt(16*( NU + DK*DK));
1198
0
                        BTNCKH = 2*atan2( std::sqrt(XNKH), std::sqrt(1-XNKH) )/PI;
1199
0
                        BTPDKH = 2*std::sqrt(XNKH*(1-XNKH))/PI;
1200
0
                        BTNCHK = 2*atan2( std::sqrt(XNHK), std::sqrt(1-XNHK) )/PI;
1201
0
                        BTPDHK = 2*std::sqrt(XNHK*(1-XNHK))/PI;
1202
0
                        for (int J = 1; J <= NU/2; ++J)
1203
0
                            {
1204
0
                                BVT = BVT + GMPH*( 1 + KS*BTNCKH );
1205
0
                                BVT = BVT + GMPK*( 1 + HS*BTNCHK );
1206
0
                                BTNCKH = BTNCKH + BTPDKH;
1207
0
                                BTPDKH = 2*J*BTPDKH*( 1 - XNKH )/( 2*J + 1 );
1208
0
                                BTNCHK = BTNCHK + BTPDHK;
1209
0
                                BTPDHK = 2*J*BTPDHK*( 1 - XNHK )/( 2*J + 1 );
1210
0
                                GMPH = GMPH*( 2*J - 1 )/( 2*J*( 1 + DH*DH/NU ) );
1211
0
                                GMPK = GMPK*( 2*J - 1 )/( 2*J*( 1 + DK*DK/NU ) );
1212
0
                            }
1213
0
                    }
1214
0
                else
1215
0
                    {
1216
0
                        QHRK = std::sqrt(DH*DH + DK*DK - 2*R*DH*DK + NU*ORS) ;
1217
0
                        HKRN = DH*DK + R*NU ;
1218
0
                        HKN = DH*DK - NU;
1219
0
                        HPK = DH + DK;
1220
0
                        BVT = atan2( -SNU*( HKN*QHRK + HPK*HKRN ),HKN*HKRN-NU*HPK*QHRK )/TPI;
1221
0
                        if ( BVT < -EPS ) BVT = BVT + 1;
1222
0
                        GMPH = DH/( TPI*SNU*( 1 + DH*DH/NU ) );
1223
0
                        GMPK = DK/( TPI*SNU*( 1 + DK*DK/NU ) );
1224
0
                        BTNCKH = std::sqrt(XNKH);
1225
0
                        BTPDKH = BTNCKH;
1226
0
                        BTNCHK = std::sqrt(XNHK);
1227
0
                        BTPDHK = BTNCHK;
1228
0
                        for (int J = 1; J <= (NU - 1)/2; ++J)
1229
0
                            {
1230
0
                                BVT = BVT + GMPH*( 1 + KS*BTNCKH );
1231
0
                                BVT = BVT + GMPK*( 1 + HS*BTNCHK );
1232
0
                                BTPDKH = ( 2*J - 1 )*BTPDKH*( 1 - XNKH )/( 2*J );
1233
0
                                BTNCKH = BTNCKH + BTPDKH;
1234
0
                                BTPDHK = ( 2*J - 1 )*BTPDHK*( 1 - XNHK )/( 2*J );
1235
0
                                BTNCHK = BTNCHK + BTPDHK;
1236
0
                                GMPH = 2*J*GMPH/( ( 2*J + 1 )*( 1 + DH*DH/NU ) );
1237
0
                                GMPK = 2*J*GMPK/( ( 2*J + 1 )*( 1 + DK*DK/NU ) );
1238
0
                            }
1239
0
                    }
1240
0
                result = BVT;
1241
0
            }
1242
1243
0
        return(result);
1244
1245
0
    }
1246
1247
1248
1249
1250
0
      Real PNTGND(int NUC, Real BA, Real BB, Real BC, Real RA, Real RB, Real R, Real RR) {
1251
          /*
1252
            Computes Plackett formula integrand
1253
          */
1254
0
          Real DT, FT, BT,result;
1255
1256
0
          result = 0.0;
1257
0
          DT = RR*( RR - (RA-RB)*(RA-RB) - 2*RA*RB*( 1 - R ) );
1258
0
          if( DT > 0 ) {
1259
0
              BT = ( BC*RR + BA*( R*RB - RA ) + BB*( R*RA -RB ) )/std::sqrt(DT);
1260
0
              FT = (BA - R*BB)*(BA - R*BB)/RR + BB*BB;
1261
0
              if( NUC<1 ) {
1262
0
                  if ( (BT > -10) && (FT <100) ) {
1263
0
                      result = exp( -FT/2 );
1264
0
                      if ( BT <10 ) result= result*PHID(BT);
1265
0
                  } else {
1266
0
                      FT = std::sqrt(1 + FT/NUC);
1267
0
                      result = STUDNT( NUC, BT/FT )/std::pow(FT,NUC);
1268
0
                  }
1269
0
              }
1270
0
          }
1271
0
          return(result);
1272
0
      }
1273
1274
1275
1276
    //***********************************************************
1277
0
    Real ND2(Real a, Real b, Real rho ){
1278
        /*
1279
         *     A function for computing bivariate normal probabilities.
1280
         *     This function is based on the method described by
1281
         *     Z. Drezner and G.O. Wesolowsky, (1989),
1282
         *     On the computation of the bivariate normal integral,
1283
         *     Journal of Statist. Comput. Simul. 35, pp. 101-107,
1284
         *     with major modifications for double precision, and for |R| close to 1.
1285
         *     The software given here has been developed by M.C. Recchioni based on previous
1286
         *     software developed by:
1287
         *     Alan Genz
1288
         *     Department of Mathematics
1289
         *     Washington State University
1290
         *     Pullman, WA 99164-3113
1291
         *     Email : alangenz@wsu.edu
1292
         *     The software developed by A. Genz is available free of charge in the website:
1293
         *     www.math.wsu.edu/faculty/genz/software/software.html
1294
         *
1295
         *
1296
         *      ND2 calculates the probability that X > DH and Y > DK.
1297
         *      Note: Prob( X < DH, Y < DK ) = ND2( -DH, -DK, R ).
1298
         *
1299
         * Parameters
1300
         *
1301
         *   DH  DOUBLE PRECISION, integration limit
1302
         *   DK  DOUBLE PRECISION, integration limit
1303
         *   R   DOUBLE PRECISION, correlation coefficient
1304
         */
1305
0
        Real result, DK, DH, R;
1306
0
        int I, IS, LG, NG;
1307
1308
0
        static const Real XL[11][4] = {
1309
0
            { 0.0, 0.0, 0.0, 0.0 },
1310
0
            { 0.0, -0.9324695142031522, -0.9815606342467191, -0.9931285991850949 },
1311
0
            { 0.0, -0.6612093864662647, -0.9041172563704750, -0.9639719272779138 },
1312
0
            { 0.0, -0.2386191860831970, -0.7699026741943050, -0.9122344282513259 },
1313
0
            { 0.0, 0.0, -0.5873179542866171, -0.8391169718222188 },
1314
0
            { 0.0, 0.0, -0.3678314989981802, -0.7463319064601508 },
1315
0
            { 0.0, 0.0, -0.1252334085114692, -0.6360536807265150 },
1316
0
            { 0.0, 0.0, 0.0, -0.5108670019508271 },
1317
0
            { 0.0, 0.0, 0.0, -0.3737060887154196 },
1318
0
            { 0.0, 0.0, 0.0, -0.2277858511416451 },
1319
0
            { 0.0, 0.0, 0.0, -0.07652652113349733 }
1320
0
        };
1321
0
        static const Real WL[11][4] = {
1322
0
            { 0.0, 0.0, 0.0, 0.0 },
1323
0
            { 0.0, 0.1713244923791705, 0.0471753363865111, 0.01761400713915212 },
1324
0
            { 0.0, 0.3607615730481384, 0.1069393259953183, 0.04060142980038694 },
1325
0
            { 0.0, 0.4679139345726904, 0.1600783285433464, 0.06267204833410906 },
1326
0
            { 0.0, 0.0, 0.2031674267230659, 0.08327674157670475 },
1327
0
            { 0.0, 0.0, 0.2334925365383547, 0.1019301198172404 },
1328
0
            { 0.0, 0.0, 0.2491470458134029, 0.1181945319615184 },
1329
0
            { 0.0, 0.0, 0.0, 0.1316886384491766 },
1330
0
            { 0.0, 0.0, 0.0, 0.1420961093183821 },
1331
0
            { 0.0, 0.0, 0.0, 0.1491729864726037 },
1332
0
            { 0.0, 0.0, 0.0, 0.1527533871307259 }
1333
0
        };
1334
0
        Real AS, AA, BB, C, D, RS, XS, BVN;
1335
0
        Real SN, ASR, H, K, BS, HS, HK;
1336
1337
0
        R=rho;
1338
0
        DH=a;
1339
0
        DK=b;
1340
1341
0
        if( fabs(R) < 0.3 ) {
1342
0
            NG = 1;
1343
0
            LG = 3; }
1344
0
        else if ( fabs(R) < 0.75 ) {
1345
0
            NG = 2;
1346
0
            LG = 6;}
1347
0
        else{
1348
0
            NG = 3;
1349
0
            LG = 10;
1350
0
        }
1351
0
        H = DH;
1352
0
        K = DK;
1353
0
        HK = H*K;
1354
1355
0
        BVN = 0.0 ;
1356
0
        if( fabs(R) < 0.925 ) {
1357
0
            if( fabs(R) > 0 ) {
1358
0
                HS = ( H*H + K*K )/2;
1359
0
                ASR = asin(R);
1360
0
                for (I = 1;I<= LG; I++){
1361
0
                    for( IS = -1; IS<= 1; IS=IS+2){
1362
0
                        SN = sin( ASR*(  IS*XL[I][NG] + 1 )/2 );
1363
0
                        BVN = BVN + WL[I][NG]*exp( ( SN*HK-HS )/( 1.0-SN*SN ) );
1364
1365
0
                    }
1366
0
                }
1367
0
                BVN = BVN*ASR/( 2*twoPi );
1368
1369
0
            }
1370
1371
0
            BVN = BVN + PHID(-H)*PHID(-K);
1372
1373
0
        }
1374
0
        else
1375
0
            {
1376
0
                if ( R < 0 ) {
1377
0
                    K = -K;
1378
0
                    HK = -HK;
1379
0
                }
1380
1381
0
                if( fabs(R) <1 ) {
1382
0
                    AS = ( 1 - R )*( 1 + R );
1383
0
                    AA = std::sqrt(AS);
1384
1385
0
                    BS = (H-K)*(H-K);
1386
0
                    C = ( 4 - HK )/8 ;
1387
0
                    D = ( 12 - HK )/16;
1388
0
                    ASR = -( BS/AS + HK )/2;
1389
0
                    if( ASR > -100 ) BVN = AA*exp(ASR)*( 1 - C*( BS - AS )*( 1 - D*BS/5 )/3 + C*D*AS*AS/5 );
1390
0
                    if( -HK<100 ){
1391
0
                        BB = std::sqrt(BS);
1392
0
                        BVN = BVN - exp( -HK/2 )*sqrtTwoPi*PHID(-BB/AA)*BB*( 1 - C*BS*( 1 - D*BS/5 )/3 );
1393
0
                    }
1394
0
                    AA = AA/2   ;
1395
0
                    for (I = 1; I<= LG;I++){
1396
0
                        for( IS = -1; IS<=1; IS=IS+2){
1397
0
                            XS =(AA*(IS*XL[I][NG]+1))*(AA*(IS*XL[I][NG]+1));
1398
0
                            RS = std::pow( (1 - XS),2 );
1399
0
                            ASR = -( BS/XS + HK )/2;
1400
0
                            if ( ASR > -100 ) {
1401
1402
0
                                BVN = BVN + AA*WL[I][NG]*exp( ASR )*(exp( -HK*( 1 - RS )/( 2*( 1 + RS ) ) )/RS- ( 1 + C*XS*( 1 + D*XS ) ) );
1403
1404
1405
0
                            }
1406
0
                        }
1407
0
                    }
1408
0
                    BVN = -BVN/twoPi;
1409
0
                }
1410
0
                if ( R > 0 )  {
1411
1412
0
                    BVN =  BVN + PHID( -max( H, K ) );
1413
1414
0
                }
1415
0
                else
1416
0
                    {
1417
0
                        BVN = -BVN;
1418
0
                        if( K > H ) BVN = BVN + PHID(K) - PHID(H);
1419
0
                    }
1420
0
            }
1421
1422
1423
0
        result=BVN;
1424
1425
0
        return(result);
1426
1427
0
    }
1428
1429
        struct integr_adapter {
1430
            ext::shared_ptr<YieldTermStructure> r;
1431
            explicit integr_adapter(const ext::shared_ptr<GeneralizedBlackScholesProcess>& process)
1432
0
            : r(*(process->riskFreeRate())) {}
1433
0
            Real operator()(Real t1,Real t2) const {
1434
0
                return r->forwardRate(t1,t2,Continuous) * (t2-t1);
1435
0
            }
1436
        };
1437
1438
        struct integalpha_adapter {
1439
            ext::shared_ptr<YieldTermStructure> r;
1440
            ext::shared_ptr<YieldTermStructure> q;
1441
            explicit integalpha_adapter(
1442
                const ext::shared_ptr<GeneralizedBlackScholesProcess>& process)
1443
0
            : r(*(process->riskFreeRate())), q(*(process->dividendYield())) {}
1444
0
            Real operator()(Real t1,Real t2) const {
1445
0
                Real alpha = r->forwardRate(t1,t2,Continuous).rate()
1446
0
                           - q->forwardRate(t1,t2,Continuous).rate();
1447
0
                return alpha * (t2-t1);
1448
0
            }
1449
        };
1450
1451
        struct alpha_adapter {
1452
            ext::shared_ptr<YieldTermStructure> r;
1453
            ext::shared_ptr<YieldTermStructure> q;
1454
            explicit alpha_adapter(const ext::shared_ptr<GeneralizedBlackScholesProcess>& process)
1455
0
            : r(*(process->riskFreeRate())), q(*(process->dividendYield())) {}
1456
0
            Real operator()(Real t) const {
1457
0
                return r->forwardRate(t,t,Continuous).rate()
1458
0
                     - q->forwardRate(t,t,Continuous).rate();
1459
0
            }
1460
        };
1461
1462
        struct sigmaq_adapter {
1463
            ext::shared_ptr<BlackVolTermStructure> v;
1464
            Real s;
1465
            explicit sigmaq_adapter(const ext::shared_ptr<GeneralizedBlackScholesProcess>& process)
1466
0
            : v(*(process->blackVolatility())), s(process->x0()) {}
1467
0
            Real operator()(Real t) const {
1468
0
                Real sigma = v->blackForwardVol(t,t,s,true);
1469
0
                return sigma*sigma;
1470
0
            }
1471
        };
1472
1473
        struct integs_adapter {
1474
            ext::shared_ptr<BlackVolTermStructure> v;
1475
            Real s;
1476
            explicit integs_adapter(const ext::shared_ptr<GeneralizedBlackScholesProcess>& process)
1477
0
            : v(*(process->blackVolatility())), s(process->x0()) {}
1478
0
            Real operator()(Real t1,Real t2) const {
1479
0
                return v->blackForwardVariance(t1,t2,s,true);
1480
0
            }
1481
        };
1482
1483
    }
1484
1485
1486
    PerturbativeBarrierOptionEngine::PerturbativeBarrierOptionEngine(
1487
                ext::shared_ptr<GeneralizedBlackScholesProcess> process, Natural order,
1488
                bool zeroGamma, Size npoint, Size npoint2)
1489
0
        : process_(std::move(process)), order_(order), zeroGamma_(zeroGamma),
1490
0
            npoint_(npoint), npoint2_(npoint2) {
1491
0
        registerWith(process_);
1492
0
    }
1493
1494
0
    void PerturbativeBarrierOptionEngine::calculate() const {
1495
1496
0
        QL_REQUIRE(arguments_.barrierType == Barrier::UpOut,
1497
0
                   "this engine only manages up-and-out options");
1498
1499
0
        QL_REQUIRE(arguments_.rebate == 0.0,
1500
0
                   "this engine does not manage non-null rebates");
1501
1502
0
        ext::shared_ptr<PlainVanillaPayoff> payoff =
1503
0
            ext::dynamic_pointer_cast<PlainVanillaPayoff>(arguments_.payoff);
1504
0
        QL_REQUIRE(payoff && payoff->optionType() == Option::Put,
1505
0
                   "this engine only manages put options");
1506
1507
0
        Real stock = process_->x0();
1508
0
        Real kprice = payoff->strike();
1509
0
        Real hbarr = arguments_.barrier;
1510
1511
0
        Time tauMin = 0.0;
1512
0
        Time tauMax = process_->time(arguments_.exercise->lastDate());
1513
1514
0
        QL_REQUIRE(order_ <= 2, "order must be <= 2");
1515
0
        QL_REQUIRE(npoint_ > 0 && npoint2_ > 0,
1516
0
               "integration point counts must be positive");
1517
1518
0
        int igm = zeroGamma_ ? 0 : 1;
1519
        
1520
0
        results_.value = BarrierUPD(kprice, stock, hbarr,
1521
0
                                    tauMin, tauMax, order_, igm, npoint_, npoint2_,
1522
0
                                    integr_adapter(process_),
1523
0
                                    integalpha_adapter(process_),
1524
0
                                    integs_adapter(process_),
1525
0
                                    alpha_adapter(process_),
1526
0
                                    sigmaq_adapter(process_));
1527
0
    }
1528
1529
}
1530