/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 | | |