Added cdfnorm2d and prbnorm2d + tests

master
Per.Andreas.Brodtkorb 15 years ago
parent d70f75a3cf
commit e1ed205bd2

@ -1,12 +1,14 @@
import warnings
from numpy import r_, minimum, maximum, atleast_1d, atleast_2d, mod, ones, floor, \
random, eye, nonzero, where, repeat, sqrt, exp, inf, diag, zeros, sin, arcsin, nan #@UnresolvedImport
from numpy import triu #@UnresolvedImport
from scipy.special import ndtr as cdfnorm, ndtri as invnorm
from wafo import mvn
import numpy as np
from numpy import (r_, minimum, maximum, atleast_1d, atleast_2d, mod, zeros, #@UnresolvedImport
ones, floor, random, eye, nonzero, repeat, sqrt, exp, inf, diag, triu) #@UnresolvedImport
from scipy.special import ndtri as invnorm
from scipy.special import ndtr as cdfnorm
import wafo.rindmod as rindmod
import wafo.mvnprdmod as mvnprdmod
from wafo import mvn
import wafo.rindmod as rindmod
import warnings
from wafo.misc import common_shape
from scipy.stats.stats import erfc
class Rind(object):
'''
@ -22,7 +24,7 @@ class Rind(object):
Lower and upper barriers used to compute the integration limits, Hlo and Hup, respectively.
indI : array-like, length Ni
vector of indices to the different barriers in the indicator function.
(NB! restriction indI(1)=0, indI(NI)=Nt+Nd, Ni = Nb+1)
(NB! restriction indI(1)=-1, indI(NI)=Nt+Nd, Ni = Nb+1)
(default indI = 0:Nt+Nd)
xc : values to condition on (default xc = zeros(0,1)), size Nc x Nx
Nt : size of Xt (default Nt = Ntdc - Nc)
@ -628,19 +630,30 @@ def prbnormnd(correl,a,b,abseps=1e-4,releps=1e-3,maxpts=None,method=0):
decrease ERROR;
if INFORM = 2, N > NMAX or N < 1. where NMAX depends on the
integration method
Example:% Compute the probability that X1<0,X2<0,X3<0,X4<0,X5<0,
% Xi are zero-mean Gaussian variables with variances one
% and correlations Cov(X(i),X(j))=0.3:
% indI=[0 5], and barriers B_lo=[-inf 0], B_lo=[0 inf]
% gives H_lo = [-inf -inf -inf -inf -inf] H_lo = [0 0 0 0 0]
N = 5; rho=0.3; NIT=3; Nt=N; indI=[0 N];
B_lo=-10; B_up=0; m=1.2*ones(N,1);
Sc=(ones(N)-eye(N))*rho+eye(N);
E = rind(Sc,m,B_lo,B_up,indI,[],Nt) % exact prob. 0.00195
A = [-inf -inf -inf -inf -inf],
B = [0 0 0 0 0]-m'
[val,err,inform] = prbnormnd(Sc,A,B);
Example
-------
Compute the probability that X1<0,X2<0,X3<0,X4<0,X5<0,
Xi are zero-mean Gaussian variables with variances one
and correlations Cov(X(i),X(j))=0.3:
indI=[0 5], and barriers B_lo=[-inf 0], B_lo=[0 inf]
gives H_lo = [-inf -inf -inf -inf -inf] H_lo = [0 0 0 0 0]
>>> Et = 0.001946 # # exact prob.
>>> n = 5; nt = n
>>> Blo =-np.inf; Bup=0; indI=[-1, n-1] # Barriers
>>> m = 1.2*np.ones(n); rho = 0.3;
>>> Sc =(np.ones((n,n))-np.eye(n))*rho+np.eye(n)
>>> rind = Rind()
>>> E0, err0, terr0 = rind(Sc,m,Blo,Bup,indI, nt=nt)
>>> A = np.repeat(Blo,n)
>>> B = np.repeat(Bup,n)-m
>>> [val,err,inform] = prbnormnd(Sc,A,B);val;err;inform
>>> np.abs(val-Et)< err0+terr0
array([ True], dtype=bool)
>>> 'val = %2.6f' % val
'val = 0.001945'
See also
--------
@ -668,13 +681,18 @@ def prbnormnd(correl,a,b,abseps=1e-4,releps=1e-3,maxpts=None,method=0):
if (any(D != 1)):
raise ValueError('This is not a correlation matrix')
# Make sure integration limits are finite
A = np.clip(a, -100, 100)
B = np.clip(b, -100, 100)
ix = np.where(np.triu(np.ones((m, m)), 1) != 0)
L = correl[ix].ravel() #% return only off diagonal elements
#L = correl((triu(ones(m),1)~=0)); % return only off diagonal elements
return mvn.mvnun(A,B, correl,maxpts, abseps, releps)
infinity = 37
infin = np.repeat(2, n) - (B > infinity) - 2 * (A < -infinity)
err, val, inform = mvn.mvndst(A, B, infin, L, maxpts, abseps, releps)
return val, err, inform
#CALL the mexroutine
# t0 = clock;
@ -688,7 +706,253 @@ def prbnormnd(correl,a,b,abseps=1e-4,releps=1e-3,maxpts=None,method=0):
# [value, err,inform] = mexGenzMvnPrb(L,A,B,abseps,releps,maxpts,method);
# end
# exTime = etime(clock,t0);
# '
#% gauss legendre points and weights, n = 6
_W6 = [ 0.1713244923791705e+00, 0.3607615730481384e+00, 0.4679139345726904e+00]
_X6 = [-0.9324695142031522e+00, -0.6612093864662647e+00, -0.2386191860831970e+00]
#% gauss legendre points and weights, n = 12
_W12 = [ 0.4717533638651177e-01, 0.1069393259953183e+00, 0.1600783285433464e+00,
0.2031674267230659e+00, 0.2334925365383547e+00, 0.2491470458134029e+00]
_X12 = [ -0.9815606342467191e+00, -0.9041172563704750e+00, -0.7699026741943050e+00,
- 0.5873179542866171e+00, -0.3678314989981802e+00, -0.1252334085114692e+00]
#% gauss legendre points and weights, n = 20
_W20 = [ 0.1761400713915212e-01, 0.4060142980038694e-01,
0.6267204833410906e-01, 0.8327674157670475e-01,
0.1019301198172404e+00, 0.1181945319615184e+00,
0.1316886384491766e+00, 0.1420961093183821e+00,
0.1491729864726037e+00, 0.1527533871307259e+00]
_X20 = [ -0.9931285991850949e+00, -0.9639719272779138e+00,
- 0.9122344282513259e+00, -0.8391169718222188e+00,
- 0.7463319064601508e+00, -0.6360536807265150e+00,
- 0.5108670019508271e+00, -0.3737060887154196e+00,
- 0.2277858511416451e+00, -0.7652652113349733e-01]
def cdfnorm2d(b1, b2, r):
'''
Returnc Bivariate Normal cumulative distribution function
Parameters
----------
b1, b2 : array-like
upper integration limits
r : real scalar
correlation coefficient (-1 <= r <= 1).
Returns
-------
bvn : ndarray
distribution function evaluated at b1, b2.
Notes
-----
CDFNORM2D computes bivariate normal probabilities, i.e., the probability
Prob(X1 <= B1 and X2 <= B2) with an absolute error less than 1e-15.
This function is based on the method described by Drezner, z and
G.O. Wesolowsky, (1989), with major modifications for double precision,
and for |r| close to 1.
Example
-------
>>> x = np.linspace(-5,5,20)
>>> [B1,B2] = np.meshgrid(x, x)
>>> r = 0.3;
>>> F = cdfnorm2d(B1,B2,r);
surf(x,x,F)
See also
cdfnorm
Reference
---------
Drezner, z and g.o. Wesolowsky, (1989),
"On the computation of the bivariate normal integral",
Journal of statist. comput. simul. 35, pp. 101-107,
'''
# Translated into Python
# Per A. Brodtkorb
#
# Original code
# by alan genz
# department of mathematics
# washington state university
# pullman, wa 99164-3113
# email : alangenz@wsu.edu
cshape = common_shape(b1, b2, r, shape=[1, ])
one = ones(cshape)
h, k, r = (-b1 * one).ravel(), (-b2 * one).ravel(), (r * one).ravel()
bvn = where(abs(r) > 1, nan, 0.0)
two = 2.e0;
twopi = 6.283185307179586e0;
hk = h * k
k0, = nonzero(abs(r) < 0.925e0)
if len(k0) > 0:
hs = (h[k0] ** 2 + k[k0] ** 2) / two
asr = arcsin(r[k0])
k1, = nonzero(r[k0] >= 0.75)
if len(k1) > 0:
k01 = k0[k1]
for i in range(10):
for sign in - 1, 1:
sn = sin(asr[k1] * (sign * _X20[i] + 1) / 2)
bvn[k01] = bvn[k01] + _W20[i] * exp((sn * hk[k01] - hs[k1]) / (1 - sn * sn));
k1, = nonzero((0.3 <= r[k0]) & (r[k0] < 0.75))
if len(k1) > 0:
k01 = k0[k1];
for i in range(6):
for sign in - 1, 1:
sn = sin(asr[k1] * (sign * _X12[i] + 1) / 2);
bvn[k01] = bvn[k01] + _W12[i] * exp((sn * hk[k01] - hs[k1]) / (1 - sn * sn));
k1, = nonzero(r[k0] < 0.3);
if len(k1) > 0:
k01 = k0[k1]
for i in range(3):
for sign in - 1, 1:
sn = sin(asr[k1] * (sign * _X6[i] + 1) / 2)
bvn[k01] = bvn[k01] + _W6[i] * exp((sn * hk[k01] - hs[k1]) / (1 - sn * sn))
bvn[k0] *= asr / (two * twopi)
bvn[k0] += fi(-h[k0]) * fi(-k[k0])
k1, = nonzero((0.925 <= abs(r)) & (abs(r) <= 1));
if len(k1) > 0:
k2, = nonzero(r[k1] < 0);
if len(k2) > 0:
k12 = k1[k2];
k[k12] = -k[k12];
hk[k12] = -hk[k12];
k3, = nonzero(abs(r[k1]) < 1);
if len(k3) > 0:
k13 = k1[k3];
a2 = (1 - r[k13]) * (1 + r[k13]);
a = sqrt(a2)
b = abs(h[k13] - k[k13]);
bs = b * b;
c = (4.e0 - hk[k13]) / 8.e0;
d = (12.e0 - hk[k13]) / 16.e0;
asr = -(bs / a2 + hk[k13]) / 2.e0;
k4, = nonzero(asr > -100.e0);
if len(k4) > 0:
bvn[k13[k4]] = a[k4] * exp(asr[k4]) * (1 - c[k4] *
(bs[k4] - a2[k4]) * (1 - d[k4] * bs[k4] / 5) / 3
+ c[k4] * d[k4] * a2[k4] ** 2 / 5);
k5, = nonzero(hk[k13] < 100.e0);
if len(k5) > 0:
#% b = sqrt(bs);
k135 = k13[k5];
bvn[k135] = bvn[k135] - exp(-hk[k135] / 2) * sqrt(twopi) * fi(-b[k5] / a[k5]) * b[k5] * (1 - c[k5] * bs[k5] * (1 - d[k5] * bs[k5] / 5) / 3)
a /= two
for i in range(10):
for sign in - 1, 1:
xs = (a * (sign * _X20[i] + 1)) ** 2;
rs = sqrt(1 - xs);
asr = -(bs / xs + hk[k13]) / 2;
k6, = nonzero(asr > -100.e0) ;
if len(k6) > 0:
k136 = k13[k6]
bvn[k136] += (a[k6] * _W20[i] * exp(asr[k6]) *
(exp(-hk[k136] * (1 - rs[k6]) / (2 * (1 + rs[k6]))) / rs[k6] -
(1 + c[k6] * xs[k6] * (1 + d[k6] * xs[k6]))))
bvn[k3] = -bvn[k3] / twopi;
k7, = nonzero(r[k1] > 0);
if len(k7):
k17 = k1[k7]
bvn[k17] += fi(-np.maximum(h[k17], k[k17]));
k8, = nonzero(r[k1] < 0);
if len(k8) > 0:
k18 = k1[k8];
bvn[k18] = -bvn[k18] + np.maximum(0, fi(-h[k18]) - fi(-k[k18]));
bvn.shape = cshape
return bvn
def fi(x):
return 0.5 * (erfc((-x) / sqrt(2)))
def prbnorm2d(a, b, r):
'''
Returns Bivariate Normal probability
Parameters
---------
a, b : array-like, size==2
vector with lower and upper integration limits, respectively.
r : real scalar
correlation coefficient
Returns
-------
prb : real scalar
computed probability Prob(A[0] <= X1 <= B[0] and A[1] <= X2 <= B[1])
with an absolute error less than 1e-15.
Example
-------
>>> a = [-1, -2]
>>> b = [1, 1]
>>> r = 0.3
>>> prbnorm2d(a,b,r)
See also
--------
cdfnorm2d,
cdfnorm,
prbnormndpc
'''
infinity = 37
lower = np.asarray(a)
upper = np.asarray(b)
if np.all((lower <= -infinity) & (infinity<=upper)):
return 1.0
if (lower >= upper).any():
return 0.0
correl = r
infin = np.repeat(2, 2) - (upper > infinity) - 2 * (lower < -infinity)
if np.all(infin == 2):
return (bvd(lower[0], lower[1], correl)
- bvd(upper[0], lower[1], correl)
- bvd(lower[0], upper[1], correl)
+ bvd(upper[0], upper[1], correl))
elif (infin[0] == 2 and infin[1] == 1):
return bvd(lower[0], lower[1], correl) - bvd(upper[0], lower[1], correl)
elif (infin[0] == 1 and infin[1] == 2) :
return bvd(lower[0], lower[1], correl) - bvd(lower[0], upper[1], correl)
elif (infin[0] == 2 and infin[1] == 0) :
return bvd(-upper[0], -upper[1], correl) - bvd(-lower[0], -upper[1], correl)
elif (infin[0] == 0 and infin[1] == 2):
return bvd(-upper[0], -upper[1], correl) - bvd(-upper[0], -lower[1], correl)
elif (infin[0] == 1 and infin[1] == 0) :
return bvd(lower[0], -upper[1], -correl)
elif (infin[0] == 0 and infin[1] == 1) :
return bvd(-upper[0], lower[1], -correl)
elif (infin[0] == 1 and infin[1] == 1):
return bvd(lower[0], lower[1], correl)
elif (infin[0] == 0 and infin[1] == 0) :
return bvd(-upper[0], -upper[1], correl)
return 1
def bvd(lo, up, r):
return cdfnorm2d(-lo, -up, r)
if __name__ == '__main__':
if False: #True: #

@ -5,7 +5,7 @@ Created on 17. juli 2010
'''
import numpy as np
from numpy import pi, inf
from wafo.gaussian import Rind, prbnormtndpc, prbnormndpc
from wafo.gaussian import Rind, prbnormtndpc, prbnormndpc, prbnormnd, cdfnorm2d, prbnorm2d
def test_rind():
'''
@ -83,7 +83,7 @@ def test_prbnormtndpc():
>>> [val3,err3, ift3] = prbnormtndpc(rho3,a3,b3)
>>> g3 = lambda x : 0.5-sum(np.sort(np.arccos([x[0]*x[1],x[0]*x[2],x[1]*x[2]])))/(4*pi)
>>> E3 = g3(rho3) # Exact value
>>> np.abs(E3-val3)<err2
>>> np.abs(E3-val3)<err3
True
'''
def test_prbnormndpc():
@ -106,6 +106,47 @@ def test_prbnormndpc():
>>> np.abs(E3-val3)<err2
True
'''
def test_prbnormnd():
'''
>>> Et = 0.001946 # # exact prob.
>>> n = 5; nt = n
>>> Blo =-np.inf; Bup=0; indI=[-1, n-1] # Barriers
>>> m = 1.2*np.ones(n); rho = 0.3;
>>> Sc =(np.ones((n,n))-np.eye(n))*rho+np.eye(n)
>>> rind = Rind()
>>> E0, err0, terr0 = rind(Sc,m,Blo,Bup,indI, nt=nt)
>>> A = np.repeat(Blo,n)
>>> B = np.repeat(Bup,n)-m
>>> [val,err,inform] = prbnormnd(Sc,A,B);val;err;inform
0.0019456719705212067
1.0059406844578488e-05
0
>>> np.abs(val-Et)< err0+terr0
array([ True], dtype=bool)
>>> 'val = %2.6f' % val
'val = 0.001945'
'''
def test_cdfnorm2d():
'''
>>> x = np.linspace(-3,3,3)
>>> [b1,b2] = np.meshgrid(x,x)
>>> r = 0.3
>>> cdfnorm2d(b1,b2,r)
array([[ 2.38515157e-05, 1.14504149e-03, 1.34987703e-03],
[ 1.14504149e-03, 2.98493342e-01, 4.99795143e-01],
[ 1.34987703e-03, 4.99795143e-01, 9.97324055e-01]])
'''
def test_prbnorm2d():
'''
>>> a = [-1, -2]
>>> b = [1, 1]
>>> r = 0.3
>>> prbnorm2d(a,b,r)
array([ 0.56659121])
'''
if __name__ == '__main__':
import doctest
doctest.testmod()
Loading…
Cancel
Save