lib/distribution/normalmultivariate.rb
module Distribution
# Calculate cdf and inverse cdf for Multivariate Distribution.
module NormalMultivariate
class << self
# Returns multivariate cdf distribution
# * a is the array of lower values
# * b is the array of higher values
# * s is an symmetric positive definite covariance matrix
def cdf(aa, bb, sigma, epsilon = 0.0001, alpha = 2.5, max_iterations = 100) # :nodoc:
fail "Doesn't work yet"
a = [nil] + aa
b = [nil] + bb
m = aa.size
sigma = sigma.to_gsl if sigma.respond_to? :to_gsl
cc = GSL::Linalg::Cholesky.decomp(sigma)
c = cc.lower
intsum = 0
varsum = 0
n = 0
d = Array.new(m + 1, nil)
e = Array.new(m + 1, nil)
f = Array.new(m + 1, nil)
(1..m).each do|i|
d[i] = 0.0 if a[i].nil?
e[i] = 1.0 if b[i].nil?
end
d[1] = uPhi(a[1].quo(c[0, 0])) unless d[1] == 0
e[1] = uPhi(b[1].quo(c[0, 0])) unless e[1] == 1
f[1] = e[1] - d[1]
error = 1000
begin
w = (m + 1).times.collect { |_i| rand * epsilon }
y = []
(2..m).each do |i|
y[i - 1] = iPhi(d[i - 1] + w[i - 1] * (e[i - 1] - d[i - 1]))
sumc = 0
(1..(i - 1)).each do |j|
sumc += c[i - 1, j - 1] * y[j]
end
d[i] = uPhi((a[i] - sumc).quo(c[i - 1, i - 1])) unless a[i].nil?
# puts "sumc:#{sumc}"
unless b[i].nil?
# puts "e[#{i}] :#{c[i-1,i-1]}"
e[i] = uPhi((b[i] - sumc).quo(c[i - 1, i - 1]))
end
f[i] = (e[i] - d[i]) * f[i - 1]
end
intsum += intsum + f[m]
varsum += f[m]**2
n += 1
error = alpha * Math.sqrt((varsum.quo(n) - (intsum.quo(n))**2).quo(n))
end while(error > epsilon && n < max_iterations)
f = intsum.quo(n)
# p intsum
# puts "f:#{f}, n:#{n}, error:#{error}"
f
end
def iPhi(pr)
Distribution::Normal.p_value(pr)
end
def uPhi(x)
Distribution::Normal.cdf(x)
end
end
end
end