distribution 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|