distribution 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +23 -0
- data/History.txt +3 -0
- data/Manifest.txt +39 -0
- data/README.txt +71 -0
- data/Rakefile +19 -0
- data/bin/distribution +3 -0
- data/lib/distribution.rb +148 -0
- data/lib/distribution/bivariatenormal.rb +25 -0
- data/lib/distribution/bivariatenormal/gsl.rb +11 -0
- data/lib/distribution/bivariatenormal/ruby.rb +281 -0
- data/lib/distribution/bivariatenormal/statistics2.rb +0 -0
- data/lib/distribution/chisquare.rb +29 -0
- data/lib/distribution/chisquare/gsl.rb +27 -0
- data/lib/distribution/chisquare/ruby.rb +85 -0
- data/lib/distribution/chisquare/statistics2.rb +21 -0
- data/lib/distribution/f.rb +28 -0
- data/lib/distribution/f/gsl.rb +28 -0
- data/lib/distribution/f/ruby.rb +117 -0
- data/lib/distribution/f/statistics2.rb +26 -0
- data/lib/distribution/math_extension.rb +72 -0
- data/lib/distribution/normal.rb +36 -0
- data/lib/distribution/normal/gsl.rb +24 -0
- data/lib/distribution/normal/ruby.rb +99 -0
- data/lib/distribution/normal/statistics2.rb +14 -0
- data/lib/distribution/normalmultivariate.rb +73 -0
- data/lib/distribution/t.rb +27 -0
- data/lib/distribution/t/gsl.rb +29 -0
- data/lib/distribution/t/ruby.rb +105 -0
- data/lib/distribution/t/statistics2.rb +28 -0
- data/spec/bivariatenormal_spec.rb +63 -0
- data/spec/chisquare_spec.rb +89 -0
- data/spec/distribution_spec.rb +19 -0
- data/spec/f_spec.rb +107 -0
- data/spec/normal_spec.rb +105 -0
- data/spec/shorthand_function.rb +6 -0
- data/spec/shorthand_spec.rb +14 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/t_spec.rb +98 -0
- metadata +160 -0
- metadata.gz.sig +1 -0
data.tar.gz.sig
ADDED
Binary file
|
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/distribution
|
7
|
+
lib/distribution.rb
|
8
|
+
lib/distribution/bivariatenormal.rb
|
9
|
+
lib/distribution/bivariatenormal/gsl.rb
|
10
|
+
lib/distribution/bivariatenormal/ruby.rb
|
11
|
+
lib/distribution/bivariatenormal/statistics2.rb
|
12
|
+
lib/distribution/chisquare.rb
|
13
|
+
lib/distribution/chisquare/gsl.rb
|
14
|
+
lib/distribution/chisquare/ruby.rb
|
15
|
+
lib/distribution/chisquare/statistics2.rb
|
16
|
+
lib/distribution/f.rb
|
17
|
+
lib/distribution/f/gsl.rb
|
18
|
+
lib/distribution/f/ruby.rb
|
19
|
+
lib/distribution/f/statistics2.rb
|
20
|
+
lib/distribution/math_extension.rb
|
21
|
+
lib/distribution/normal.rb
|
22
|
+
lib/distribution/normal/gsl.rb
|
23
|
+
lib/distribution/normal/ruby.rb
|
24
|
+
lib/distribution/normal/statistics2.rb
|
25
|
+
lib/distribution/normalmultivariate.rb
|
26
|
+
lib/distribution/t.rb
|
27
|
+
lib/distribution/t/gsl.rb
|
28
|
+
lib/distribution/t/ruby.rb
|
29
|
+
lib/distribution/t/statistics2.rb
|
30
|
+
spec/bivariatenormal_spec.rb
|
31
|
+
spec/chisquare_spec.rb
|
32
|
+
spec/distribution_spec.rb
|
33
|
+
spec/f_spec.rb
|
34
|
+
spec/normal_spec.rb
|
35
|
+
spec/shorthand_function.rb
|
36
|
+
spec/shorthand_spec.rb
|
37
|
+
spec/spec.opts
|
38
|
+
spec/spec_helper.rb
|
39
|
+
spec/t_spec.rb
|
data/README.txt
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
= distribution
|
2
|
+
|
3
|
+
* https://github.com/clbustos/distribution
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Statistical Distributions multi library wrapper.
|
8
|
+
Uses Ruby by default and C (statistics2/GSL) or Java extensions where available.
|
9
|
+
|
10
|
+
Includes code from statistics2
|
11
|
+
|
12
|
+
== FEATURES/PROBLEMS:
|
13
|
+
|
14
|
+
* Base API
|
15
|
+
* Shorthand for easy use
|
16
|
+
|
17
|
+
== API structure
|
18
|
+
|
19
|
+
Distribution::<name>.(cdf|pdf|p_value|rng)
|
20
|
+
|
21
|
+
module Distribution::Shorthand provides (you guess?) shortands method to call all methods
|
22
|
+
|
23
|
+
<Distribution shortname>_(cdf|pdf|p|r)
|
24
|
+
|
25
|
+
Shortnames are:
|
26
|
+
|
27
|
+
* Normal: norm
|
28
|
+
* Bivariate Normal: bnor
|
29
|
+
* T: t
|
30
|
+
* F: f
|
31
|
+
* Chi Square: chisq
|
32
|
+
|
33
|
+
For example
|
34
|
+
|
35
|
+
Distribution::T.rng
|
36
|
+
|
37
|
+
could be called after including Distribution::Shorthand
|
38
|
+
|
39
|
+
t_r
|
40
|
+
|
41
|
+
== SYNOPSIS:
|
42
|
+
# Returns Gaussian PDF for x
|
43
|
+
pdf=Distribution::Normal.pdf(x)
|
44
|
+
# Returns Gaussian CDF for x
|
45
|
+
cdf=Distribution::Normal.cdf(x)
|
46
|
+
# Returns inverse CDF (or p-value) for x
|
47
|
+
pv =Distribution::Normal.p_value(x)
|
48
|
+
|
49
|
+
== REQUIREMENTS:
|
50
|
+
|
51
|
+
I try to provide a Ruby version for each method. But to increase (notably!) the speed, please install
|
52
|
+
|
53
|
+
* Ruby 1.8-1.9: gsl or statistics2
|
54
|
+
* Java: Apache Math
|
55
|
+
|
56
|
+
== INSTALL:
|
57
|
+
|
58
|
+
gem install distribution
|
59
|
+
|
60
|
+
== DEVELOPERS:
|
61
|
+
|
62
|
+
After checking out the source, run:
|
63
|
+
|
64
|
+
$ rake newb
|
65
|
+
|
66
|
+
This task will install any missing dependencies, run the tests/specs,
|
67
|
+
and generate the RDoc.
|
68
|
+
|
69
|
+
== LICENSE:
|
70
|
+
|
71
|
+
GPL V2
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)+"/lib/"))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'distribution'
|
6
|
+
require 'rubyforge'
|
7
|
+
# Hoe.plugin :compiler
|
8
|
+
# Hoe.plugin :gem_prelude_sucks
|
9
|
+
Hoe.plugin :git
|
10
|
+
# Hoe.plugin :inline
|
11
|
+
# Hoe.plugin :racc
|
12
|
+
Hoe.plugin :rubyforge
|
13
|
+
|
14
|
+
Hoe.spec 'distribution' do
|
15
|
+
self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
|
16
|
+
self.version=Distribution::VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: syntax=ruby
|
data/bin/distribution
ADDED
data/lib/distribution.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# = distribution.rb -
|
2
|
+
# Distribution - Statistical Distributions package for Ruby
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011 Claudio Bustos
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU General Public License
|
8
|
+
# as published by the Free Software Foundation; either version 2
|
9
|
+
# of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
19
|
+
#
|
20
|
+
# == Other Sources
|
21
|
+
#
|
22
|
+
# * Code of Ruby engines came from statistics2.rb,
|
23
|
+
# created by Shin-ichiro HARA(sinara@blade.nagaokaut.ac.jp).
|
24
|
+
# Retrieve from http://blade.nagaokaut.ac.jp/~sinara/ruby/math/statistics2/
|
25
|
+
#
|
26
|
+
# Specific notices will be placed where there are appropiate
|
27
|
+
#
|
28
|
+
if !respond_to? :define_singleton_method
|
29
|
+
class Module
|
30
|
+
public :define_method
|
31
|
+
end
|
32
|
+
|
33
|
+
class Object
|
34
|
+
def define_singleton_method(name,&block)
|
35
|
+
sc=class <<self;self;end
|
36
|
+
sc.define_method(name,&block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
require 'distribution/math_extension'
|
41
|
+
|
42
|
+
# Several distributions modules to calculate pdf, cdf, inverse cdf and generate
|
43
|
+
# pseudo-random numbers for several statistical distributions
|
44
|
+
#
|
45
|
+
# == Usage:
|
46
|
+
# Distribution::Normal.cdf(1.96)
|
47
|
+
# => 0.97500210485178
|
48
|
+
# Distribution::Normal.p_value(0.95)
|
49
|
+
# => 1.64485364660836
|
50
|
+
module Distribution
|
51
|
+
VERSION="0.1.0"
|
52
|
+
|
53
|
+
module Shorthand
|
54
|
+
EQUIVALENCES={:p_value=>:p, :cdf=>:cdf, :pdf=>:pdf, :rng=>:r}
|
55
|
+
def self.add_shortcut(sh,m,&block)
|
56
|
+
if EQUIVALENCES.include? m.to_sym
|
57
|
+
sh_name=sh+"_#{m}"
|
58
|
+
define_method(sh_name,&block)
|
59
|
+
sh_name=sh+"_#{EQUIVALENCES[m]}"
|
60
|
+
define_method(sh_name,&block)
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
SQ2PI = Math.sqrt(2 * Math::PI)
|
68
|
+
|
69
|
+
# Create a method 'has_<library>' on Module
|
70
|
+
# which require a library and return true or false
|
71
|
+
# according to success of failure
|
72
|
+
def self.create_has_library(library) #:nodoc:
|
73
|
+
define_singleton_method("has_#{library}?") do
|
74
|
+
cv="@@#{library}"
|
75
|
+
if !class_variable_defined? cv
|
76
|
+
begin
|
77
|
+
require library.to_s
|
78
|
+
class_variable_set(cv, true)
|
79
|
+
rescue LoadError
|
80
|
+
class_variable_set(cv, false)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
class_variable_get(cv)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
# Retrieves the libraries used to calculate
|
87
|
+
# distributions
|
88
|
+
def self.libraries_order
|
89
|
+
order=[:Ruby_]
|
90
|
+
order.unshift(:Statistics2_) if has_statistics2?
|
91
|
+
order.unshift(:GSL_) if has_gsl?
|
92
|
+
order.unshift(:Java_) if has_java?
|
93
|
+
order
|
94
|
+
end
|
95
|
+
create_has_library :gsl
|
96
|
+
create_has_library :statistics2
|
97
|
+
create_has_library :java
|
98
|
+
|
99
|
+
# Magic module
|
100
|
+
module Distributable #:nodoc:
|
101
|
+
# Create methods for each module and add methods to
|
102
|
+
# Distribution::Shorthand.
|
103
|
+
#
|
104
|
+
# Traverse Distribution.libraries_order adding
|
105
|
+
# methods availables for each engine module on
|
106
|
+
# the current library
|
107
|
+
#
|
108
|
+
# Kids: Metaprogramming trickery! Don't do at work.
|
109
|
+
# This section was created between a very long reunion
|
110
|
+
# and a travel of 456 Km.
|
111
|
+
def create_distribution_methods()
|
112
|
+
Distribution.libraries_order.each do |l_name|
|
113
|
+
if const_defined? l_name
|
114
|
+
l =const_get(l_name)
|
115
|
+
# Add methods from engine to base base, if not yet included
|
116
|
+
l.singleton_methods.each do |m|
|
117
|
+
if !singleton_methods.include? m
|
118
|
+
define_method(m) do |*args|
|
119
|
+
l.send(m,*args)
|
120
|
+
end
|
121
|
+
# Add method to Distribution::Shorthand
|
122
|
+
sh=const_get(:SHORTHAND)
|
123
|
+
|
124
|
+
Distribution::Shorthand.add_shortcut(sh,m) do |*args|
|
125
|
+
l.send(m,*args)
|
126
|
+
end
|
127
|
+
|
128
|
+
module_function m
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
# create alias for common methods
|
135
|
+
alias_method :inverse_cdf,:p_value if singleton_methods.include? :p_value
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
autoload(:Normal, 'distribution/normal')
|
141
|
+
autoload(:ChiSquare, 'distribution/chisquare')
|
142
|
+
autoload(:T, 'distribution/t')
|
143
|
+
autoload(:F, 'distribution/f')
|
144
|
+
autoload(:BivariateNormal, 'distribution/bivariatenormal')
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'distribution/bivariatenormal/ruby'
|
2
|
+
require 'distribution/bivariatenormal/gsl'
|
3
|
+
module Distribution
|
4
|
+
# Calculate pdf and cdf for bivariate normal distribution.
|
5
|
+
#
|
6
|
+
# Pdf if easy to calculate, but CDF is not trivial. Several papers
|
7
|
+
# describe methods to calculate the integral.
|
8
|
+
module BivariateNormal
|
9
|
+
SHORTHAND='bnor'
|
10
|
+
|
11
|
+
extend Distributable
|
12
|
+
create_distribution_methods
|
13
|
+
|
14
|
+
##
|
15
|
+
# :singleton-method: pdf(x,y, rho, s1=1.0, s2=1.0)
|
16
|
+
# Probability density function for a given x, y and rho value.
|
17
|
+
#
|
18
|
+
|
19
|
+
##
|
20
|
+
# :singleton-method: cdf(x,y,rho)
|
21
|
+
# CDF for a given x, y and rho value.
|
22
|
+
#
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
module Distribution
|
2
|
+
#
|
3
|
+
# Ruby version implements three methods on this module:
|
4
|
+
# * Genz:: Used by default, with improvement to calculate p on rho > 0.95
|
5
|
+
# * Hull:: Port from a C++ code
|
6
|
+
# * Jantaravareerat:: Iterative (slow and buggy)
|
7
|
+
#
|
8
|
+
|
9
|
+
module BivariateNormal
|
10
|
+
module Ruby_
|
11
|
+
class << self
|
12
|
+
SIDE=0.1 # :nodoc:
|
13
|
+
LIMIT=5 # :nodoc:
|
14
|
+
# Return the partial derivative of cdf over x, with y and rho constant
|
15
|
+
# Reference:
|
16
|
+
# * Tallis, 1962, p.346, cited by Olsson, 1979
|
17
|
+
def partial_derivative_cdf_x(x,y,rho)
|
18
|
+
Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y-rho*x).quo( Math::sqrt( 1 - rho**2 )))
|
19
|
+
end
|
20
|
+
alias :pd_cdf_x :partial_derivative_cdf_x
|
21
|
+
# Probability density function for a given x, y and rho value.
|
22
|
+
#
|
23
|
+
# Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution
|
24
|
+
def pdf(x,y, rho, s1=1.0, s2=1.0)
|
25
|
+
1.quo(2 * Math::PI * s1 * s2 * Math::sqrt( 1 - rho**2 )) * (Math::exp(-(1.quo(2*(1-rho**2))) *
|
26
|
+
((x**2.quo(s1)) + (y**2.quo(s2)) - (2*rho*x*y).quo(s1*s2))))
|
27
|
+
end
|
28
|
+
|
29
|
+
def f(x,y,aprime,bprime,rho)
|
30
|
+
r=aprime*(2*x-aprime)+bprime*(2*y-bprime)+2*rho*(x-aprime)*(y-bprime)
|
31
|
+
Math::exp(r)
|
32
|
+
end
|
33
|
+
|
34
|
+
# CDF for a given x, y and rho value.
|
35
|
+
# Uses Genz algorithm (cdf_genz method).
|
36
|
+
#
|
37
|
+
def cdf(a,b,rho)
|
38
|
+
cdf_genz(a,b,rho)
|
39
|
+
end
|
40
|
+
|
41
|
+
def sgn(x)
|
42
|
+
if(x>=0)
|
43
|
+
1
|
44
|
+
else
|
45
|
+
-1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Normal cumulative distribution function (cdf) for a given x, y and rho.
|
50
|
+
# Based on Hull (1993, cited by Arne, 2003)
|
51
|
+
#
|
52
|
+
# References:
|
53
|
+
# * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html
|
54
|
+
def cdf_hull(a,b,rho)
|
55
|
+
#puts "a:#{a} - b:#{b} - rho:#{rho}"
|
56
|
+
if (a<=0 and b<=0 and rho<=0)
|
57
|
+
# puts "ruta 1"
|
58
|
+
aprime=a.quo(Math::sqrt(2.0*(1.0-rho**2)))
|
59
|
+
bprime=b.quo(Math::sqrt(2.0*(1.0-rho**2)))
|
60
|
+
aa=[0.3253030, 0.4211071, 0.1334425, 0.006374323]
|
61
|
+
bb=[0.1337764, 0.6243247, 1.3425378, 2.2626645]
|
62
|
+
sum=0
|
63
|
+
4.times do |i|
|
64
|
+
4.times do |j|
|
65
|
+
sum+=aa[i]*aa[j] * f(bb[i], bb[j], aprime, bprime,rho)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
sum=sum*(Math::sqrt(1.0-rho**2).quo(Math::PI))
|
69
|
+
return sum
|
70
|
+
elsif(a*b*rho<=0.0)
|
71
|
+
|
72
|
+
#puts "ruta 2"
|
73
|
+
if(a<=0 and b>=0 and rho>=0)
|
74
|
+
return Distribution::Normal.cdf(a) - cdf(a,-b,-rho)
|
75
|
+
elsif (a>=0.0 and b<=0.0 and rho>=0)
|
76
|
+
return Distribution::Normal.cdf(b) - cdf(-a,b,-rho)
|
77
|
+
elsif (a>=0.0 and b>=0.0 and rho<=0)
|
78
|
+
return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a,-b,rho)
|
79
|
+
end
|
80
|
+
elsif (a*b*rho>=0.0)
|
81
|
+
#puts "ruta 3"
|
82
|
+
denum=Math::sqrt(a**2 - 2*rho*a*b + b**2)
|
83
|
+
rho1=((rho*a-b)*sgn(a)).quo(denum)
|
84
|
+
rho2=((rho*b-a)*sgn(b)).quo(denum)
|
85
|
+
delta=(1.0-sgn(a)*sgn(b)).quo(4)
|
86
|
+
#puts "#{rho1} - #{rho2}"
|
87
|
+
return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta
|
88
|
+
end
|
89
|
+
raise "Should'nt be here! #{a} - #{b} #{rho}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# CDF. Iterative method by Jantaravareerat (n/d)
|
93
|
+
#
|
94
|
+
# Reference:
|
95
|
+
# * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution
|
96
|
+
|
97
|
+
def cdf_jantaravareerat(x,y,rho,s1=1,s2=1)
|
98
|
+
# Special cases
|
99
|
+
return 1 if x>LIMIT and y>LIMIT
|
100
|
+
return 0 if x<-LIMIT or y<-LIMIT
|
101
|
+
return Distribution::Normal.cdf(y) if x>LIMIT
|
102
|
+
return Distribution::Normal.cdf(x) if y>LIMIT
|
103
|
+
|
104
|
+
#puts "x:#{x} - y:#{y}"
|
105
|
+
x=-LIMIT if x<-LIMIT
|
106
|
+
x=LIMIT if x>LIMIT
|
107
|
+
y=-LIMIT if y<-LIMIT
|
108
|
+
y=LIMIT if y>LIMIT
|
109
|
+
|
110
|
+
x_squares=((LIMIT+x) / SIDE).to_i
|
111
|
+
y_squares=((LIMIT+y) / SIDE).to_i
|
112
|
+
sum=0
|
113
|
+
x_squares.times do |i|
|
114
|
+
y_squares.times do |j|
|
115
|
+
z1=-LIMIT+(i+1)*SIDE
|
116
|
+
z2=-LIMIT+(j+1)*SIDE
|
117
|
+
#puts " #{z1}-#{z2}"
|
118
|
+
h=(pdf(z1,z2,rho,s1,s2)+pdf(z1-SIDE,z2,rho,s1,s2)+pdf(z1,z2-SIDE,rho,s1,s2) + pdf(z1-SIDE,z2-SIDE,rho,s1,s2)).quo(4)
|
119
|
+
sum+= (SIDE**2)*h # area
|
120
|
+
end
|
121
|
+
end
|
122
|
+
sum
|
123
|
+
end
|
124
|
+
# Normal cumulative distribution function (cdf) for a given x, y and rho.
|
125
|
+
# Ported from Fortran code by Alan Genz
|
126
|
+
#
|
127
|
+
# Original documentation
|
128
|
+
# DOUBLE PRECISION FUNCTION BVND( DH, DK, R )
|
129
|
+
# A function for computing bivariate normal probabilities.
|
130
|
+
#
|
131
|
+
# Alan Genz
|
132
|
+
# Department of Mathematics
|
133
|
+
# Washington State University
|
134
|
+
# Pullman, WA 99164-3113
|
135
|
+
# Email : alangenz_AT_wsu.edu
|
136
|
+
#
|
137
|
+
# This function is based on the method described by
|
138
|
+
# Drezner, Z and G.O. Wesolowsky, (1989),
|
139
|
+
# On the computation of the bivariate normal integral,
|
140
|
+
# Journal of Statist. Comput. Simul. 35, pp. 101-107,
|
141
|
+
# with major modifications for double precision, and for |R| close to 1.
|
142
|
+
#
|
143
|
+
# Original location:
|
144
|
+
# * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f
|
145
|
+
def cdf_genz(x,y,rho)
|
146
|
+
dh=-x
|
147
|
+
dk=-y
|
148
|
+
r=rho
|
149
|
+
twopi = 6.283185307179586
|
150
|
+
|
151
|
+
w=11.times.collect {[nil]*4};
|
152
|
+
x=11.times.collect {[nil]*4}
|
153
|
+
|
154
|
+
data=[
|
155
|
+
0.1713244923791705E+00, -0.9324695142031522E+00,
|
156
|
+
0.3607615730481384E+00, -0.6612093864662647E+00,
|
157
|
+
0.4679139345726904E+00, -0.2386191860831970E+00]
|
158
|
+
|
159
|
+
(1..3).each {|i|
|
160
|
+
w[i][1]=data[(i-1)*2]
|
161
|
+
x[i][1]=data[(i-1)*2+1]
|
162
|
+
|
163
|
+
}
|
164
|
+
data=[
|
165
|
+
0.4717533638651177E-01,-0.9815606342467191E+00,
|
166
|
+
0.1069393259953183E+00,-0.9041172563704750E+00,
|
167
|
+
0.1600783285433464E+00,-0.7699026741943050E+00,
|
168
|
+
0.2031674267230659E+00,-0.5873179542866171E+00,
|
169
|
+
0.2334925365383547E+00,-0.3678314989981802E+00,
|
170
|
+
0.2491470458134029E+00,-0.1252334085114692E+00]
|
171
|
+
(1..6).each {|i|
|
172
|
+
w[i][2]=data[(i-1)*2]
|
173
|
+
x[i][2]=data[(i-1)*2+1]
|
174
|
+
|
175
|
+
|
176
|
+
}
|
177
|
+
data=[
|
178
|
+
0.1761400713915212E-01,-0.9931285991850949E+00,
|
179
|
+
0.4060142980038694E-01,-0.9639719272779138E+00,
|
180
|
+
0.6267204833410906E-01,-0.9122344282513259E+00,
|
181
|
+
0.8327674157670475E-01,-0.8391169718222188E+00,
|
182
|
+
0.1019301198172404E+00,-0.7463319064601508E+00,
|
183
|
+
0.1181945319615184E+00,-0.6360536807265150E+00,
|
184
|
+
0.1316886384491766E+00,-0.5108670019508271E+00,
|
185
|
+
0.1420961093183821E+00,-0.3737060887154196E+00,
|
186
|
+
0.1491729864726037E+00,-0.2277858511416451E+00,
|
187
|
+
0.1527533871307259E+00,-0.7652652113349733E-01]
|
188
|
+
|
189
|
+
(1..10).each {|i|
|
190
|
+
w[i][3]=data[(i-1)*2]
|
191
|
+
x[i][3]=data[(i-1)*2+1]
|
192
|
+
|
193
|
+
|
194
|
+
}
|
195
|
+
|
196
|
+
|
197
|
+
if ( r.abs < 0.3 )
|
198
|
+
ng = 1
|
199
|
+
lg = 3
|
200
|
+
elsif ( r.abs < 0.75 )
|
201
|
+
ng = 2
|
202
|
+
lg = 6
|
203
|
+
else
|
204
|
+
ng = 3
|
205
|
+
lg = 10
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
h = dh
|
210
|
+
k = dk
|
211
|
+
hk = h*k
|
212
|
+
bvn = 0
|
213
|
+
if ( r.abs < 0.925 )
|
214
|
+
if ( r.abs > 0 )
|
215
|
+
hs = ( h*h + k*k ).quo(2)
|
216
|
+
asr = Math::asin(r)
|
217
|
+
(1..lg).each do |i|
|
218
|
+
[-1,1].each do |is|
|
219
|
+
sn = Math::sin(asr*(is* x[i][ng]+1).quo(2) )
|
220
|
+
bvn = bvn + w[i][ng] * Math::exp( ( sn*hk-hs ).quo( 1-sn*sn ) )
|
221
|
+
end # do
|
222
|
+
end # do
|
223
|
+
bvn = bvn*asr.quo( 2*twopi )
|
224
|
+
end # if
|
225
|
+
bvn = bvn + Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k)
|
226
|
+
|
227
|
+
|
228
|
+
else # r.abs
|
229
|
+
if ( r < 0 )
|
230
|
+
k = -k
|
231
|
+
hk = -hk
|
232
|
+
end
|
233
|
+
|
234
|
+
if ( r.abs < 1 )
|
235
|
+
as = ( 1 - r )*( 1 + r )
|
236
|
+
a = Math::sqrt(as)
|
237
|
+
bs = ( h - k )**2
|
238
|
+
c = ( 4 - hk ).quo(8)
|
239
|
+
d = ( 12 - hk ).quo(16)
|
240
|
+
asr = -( bs.quo(as) + hk ).quo(2)
|
241
|
+
if ( asr > -100 )
|
242
|
+
bvn = a*Math::exp(asr) * ( 1 - c*( bs - as )*( 1 - d*bs.quo(5) ).quo(3) + c*d*as*as.quo(5) )
|
243
|
+
end
|
244
|
+
if ( -hk < 100 )
|
245
|
+
b = Math::sqrt(bs)
|
246
|
+
bvn = bvn - Math::exp( -hk.quo(2) ) * Math::sqrt(twopi)*Distribution::Normal.cdf(-b.quo(a))*b *
|
247
|
+
( 1 - c*bs*( 1 - d*bs.quo(5) ).quo(3) )
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
a = a.quo(2)
|
252
|
+
(1..lg).each do |i|
|
253
|
+
[-1,1].each do |is|
|
254
|
+
xs = (a*( is*x[i][ng] + 1 ) )**2
|
255
|
+
rs = Math::sqrt( 1 - xs )
|
256
|
+
asr = -( bs/xs + hk ).quo(2)
|
257
|
+
if ( asr > -100 )
|
258
|
+
bvn = bvn + a*w[i][ng] * Math::exp( asr ) *
|
259
|
+
( Math::exp( -hk*( 1 - rs ).quo(2*( 1 + rs ) ) ) .quo(rs) - ( 1 + c*xs*( 1 + d*xs ) ) )
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
bvn = -bvn/twopi
|
264
|
+
end
|
265
|
+
|
266
|
+
if ( r > 0 )
|
267
|
+
bvn = bvn + Distribution::Normal.cdf(-[h,k].max)
|
268
|
+
else
|
269
|
+
bvn = -bvn
|
270
|
+
if ( k > h )
|
271
|
+
bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
bvn
|
276
|
+
end
|
277
|
+
private :f, :sgn
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|