distribution-0.7.0/0000755000175000017500000000000012061653751013621 5ustar boutilboutildistribution-0.7.0/data/0000755000175000017500000000000012061653751014532 5ustar boutilboutildistribution-0.7.0/data/template/0000755000175000017500000000000012061653751016345 5ustar boutilboutildistribution-0.7.0/data/template/distribution/0000755000175000017500000000000012061653751021064 5ustar boutilboutildistribution-0.7.0/data/template/distribution/ruby.erb0000644000175000017500000000042112061653751022534 0ustar boutilboutilmodule Distribution module <%= distribution.capitalize %> module Ruby_ class << self def pdf(x <% parameters %>) end def cdf(x <% parameters %>) end def p_value(pr <% parameters %>) end end end end enddistribution-0.7.0/data/template/distribution/gsl.erb0000644000175000017500000000042012061653751022337 0ustar boutilboutilmodule Distribution module <%= distribution.capitalize %> module GSL_ class << self def pdf(x <% parameters %>) end def cdf(x <% parameters %>) end def p_value(pr <% parameters %>) end end end end enddistribution-0.7.0/data/template/spec.erb0000644000175000017500000000241512061653751017773 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::<%= distribution.capitalize %> do shared_examples_for "<%= distribution %> engine" do it "should return correct pdf" do if @engine.respond_to? :pdf else pending("No #{@engine}.pdf") end end it "should return correct cdf" do if @engine.respond_to? :cdf else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value else pending("No #{@engine}.cdf") end end end describe "singleton" do before do @engine=Distribution::<%= distribution.capitalize %> end it_should_behave_like "<%= distribution %> engine" end describe Distribution::<%= distribution.capitalize %>::Ruby_ do before do @engine=Distribution::<%= distribution.capitalize %>::Ruby_ end it_should_behave_like "<%= distribution %> engine" end if Distribution.has_gsl? describe Distribution::<%= distribution.capitalize %>::GSL_ do before do @engine=Distribution::<%= distribution.capitalize %>::GSL_ end it_should_behave_like "<%= distribution %> engine" end end end distribution-0.7.0/data/template/distribution.erb0000644000175000017500000000107312061653751021557 0ustar boutilboutilrequire 'distribution/<%= distribution.downcase %>/ruby' require 'distribution/<%= distribution.downcase %>/gsl' #require 'distribution/<%= distribution.downcase %>/java' module Distribution # TODO: Document this Distribution module <%= distribution.capitalize %> SHORTHAND='<%= distribution.downcase[0,4] %>' extend Distributable create_distribution_methods ## # :singleton-method: pdf(x <%= parameters %>) ## # :singleton-method: cdf(x <%= parameters %>) ## # :singleton-method: p_value(pr <%= parameters %>) end end distribution-0.7.0/metadata.yml0000644000175000017500000001650012061653751016126 0ustar boutilboutil--- !ruby/object:Gem::Specification name: distribution version: !ruby/object:Gem::Version hash: 3 prerelease: false segments: - 0 - 7 - 0 version: 0.7.0 platform: ruby authors: - Claudio Bustos autorequire: bindir: bin cert_chain: - | -----BEGIN CERTIFICATE----- MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhjbGJ1 c3RvczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t MB4XDTEwMDMyOTIxMzg1NVoXDTExMDMyOTIxMzg1NVowPzERMA8GA1UEAwwIY2xi dXN0b3MxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf8JVMGqE7m5kYb+PNN neZv2pcXV5fQCi6xkyG8bi2/SIFy/LyxuvLzEeOxBeaz1Be93bayIUquOIqw3dyw /KXWa31FxuNuvAm6CN8fyeRYX/ou4cw3OIUUnIvB7RMNIu4wbgeM6htV/QEsNLrv at1/mh9JpqawPrcjIOVMj4BIp67vmzJCaUf+S/H2uYtSO09F+YQE3tv85TPeRmqU yjyXyTc/oJiw1cXskUL8UtMWZmrwNLHXuZWWIMzkjiz3UNdhJr/t5ROk8S2WPznl 0bMy/PMIlAbqWolRn1zl2VFJ3TaXScbqImY8Wf4g62b/1ZSUlGrtnLNsCYXrWiso UPUCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFGu9 rrJ1H64qRmNNu3Jj/Qjvh0u5MA0GCSqGSIb3DQEBBQUAA4IBAQCV0Unka5isrhZk GjqSDqY/6hF+G2pbFcbWUpjmC8NWtAxeC+7NGV3ljd0e1SLfoyBj4gnFtFmY8qX4 K02tgSZM0eDV8TpgFpWXzK6LzHvoanuahHLZEtk/+Z885lFene+nHadkem1n9iAB cs96JO9/JfFyuXM27wFAwmfHCmJfPF09R4VvGHRAvb8MGzSVgk2i06OJTqkBTwvv JHJdoyw3+8bw9RJ+jLaNoQ+xu+1pQdS2bb3m7xjZpufml/m8zFCtjYM/7qgkKR8z /ZZt8lCiKfFArppRrZayE2FVsps4X6WwBdrKTMZ0CKSXTRctbEj1BAZ67eoTvBBt rpP0jjs0 -----END CERTIFICATE----- date: 2011-11-30 00:00:00 -03:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: rubyforge prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 7 segments: - 2 - 0 - 4 version: 2.0.4 type: :development version_requirements: *id001 - !ruby/object:Gem::Dependency name: rspec prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 2 - 0 version: "2.0" type: :development version_requirements: *id002 - !ruby/object:Gem::Dependency name: rubyforge prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id003 - !ruby/object:Gem::Dependency name: hoe prerelease: false requirement: &id004 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 47 segments: - 2 - 8 - 0 version: 2.8.0 type: :development version_requirements: *id004 description: |- Statistical Distributions library. Includes Normal univariate and bivariate, T, F, Chi Square, Binomial, Hypergeometric, Exponential, Poisson, Beta, LogNormal and Gamma. Uses Ruby by default and C (statistics2/GSL) or Java extensions where available. Includes code from statistics2 on Normal, T, F and Chi Square ruby code [http://blade.nagaokaut.ac.jp/~sinara/ruby/math/statistics2] email: - clbustos_at_gmail.com executables: - distribution extensions: [] extra_rdoc_files: - History.txt - Manifest.txt - README.txt files: - .autotest - History.txt - Manifest.txt - README.txt - Rakefile - benchmark/binomial_coefficient.rb - benchmark/binomial_coefficient/binomial_coefficient.ds - benchmark/binomial_coefficient/binomial_coefficient.xls - benchmark/binomial_coefficient/experiment.rb - benchmark/factorial_hash.rb - benchmark/factorial_method.rb - benchmark/odd.rb - benchmark/power.rb - bin/distribution - data/template/distribution.erb - data/template/distribution/gsl.erb - data/template/distribution/ruby.erb - data/template/spec.erb - lib/distribution.rb - lib/distribution/beta.rb - lib/distribution/beta/gsl.rb - lib/distribution/beta/java.rb - lib/distribution/beta/ruby.rb - lib/distribution/binomial.rb - lib/distribution/binomial/gsl.rb - lib/distribution/binomial/java.rb - lib/distribution/binomial/ruby.rb - lib/distribution/bivariatenormal.rb - lib/distribution/bivariatenormal/gsl.rb - lib/distribution/bivariatenormal/java.rb - lib/distribution/bivariatenormal/ruby.rb - lib/distribution/bivariatenormal/statistics2.rb - lib/distribution/chisquare.rb - lib/distribution/chisquare/gsl.rb - lib/distribution/chisquare/java.rb - lib/distribution/chisquare/ruby.rb - lib/distribution/chisquare/statistics2.rb - lib/distribution/exponential.rb - lib/distribution/exponential/gsl.rb - lib/distribution/exponential/ruby.rb - lib/distribution/f.rb - lib/distribution/f/gsl.rb - lib/distribution/f/java.rb - lib/distribution/f/ruby.rb - lib/distribution/f/statistics2.rb - lib/distribution/gamma.rb - lib/distribution/gamma/gsl.rb - lib/distribution/gamma/java.rb - lib/distribution/gamma/ruby.rb - lib/distribution/hypergeometric.rb - lib/distribution/hypergeometric/gsl.rb - lib/distribution/hypergeometric/java.rb - lib/distribution/hypergeometric/ruby.rb - lib/distribution/logistic.rb - lib/distribution/logistic/ruby.rb - lib/distribution/lognormal.rb - lib/distribution/lognormal/gsl.rb - lib/distribution/lognormal/ruby.rb - lib/distribution/math_extension.rb - lib/distribution/math_extension/chebyshev_series.rb - lib/distribution/math_extension/erfc.rb - lib/distribution/math_extension/exponential_integral.rb - lib/distribution/math_extension/gammastar.rb - lib/distribution/math_extension/gsl_utilities.rb - lib/distribution/math_extension/incomplete_beta.rb - lib/distribution/math_extension/incomplete_gamma.rb - lib/distribution/math_extension/log_utilities.rb - lib/distribution/normal.rb - lib/distribution/normal/gsl.rb - lib/distribution/normal/java.rb - lib/distribution/normal/ruby.rb - lib/distribution/normal/statistics2.rb - lib/distribution/normalmultivariate.rb - lib/distribution/poisson.rb - lib/distribution/poisson/gsl.rb - lib/distribution/poisson/java.rb - lib/distribution/poisson/ruby.rb - lib/distribution/t.rb - lib/distribution/t/gsl.rb - lib/distribution/t/java.rb - lib/distribution/t/ruby.rb - lib/distribution/t/statistics2.rb - spec/beta_spec.rb - spec/binomial_spec.rb - spec/bivariatenormal_spec.rb - spec/chisquare_spec.rb - spec/distribution_spec.rb - spec/exponential_spec.rb - spec/f_spec.rb - spec/gamma_spec.rb - spec/hypergeometric_spec.rb - spec/logistic_spec.rb - spec/lognormal_spec.rb - spec/math_extension_spec.rb - spec/normal_spec.rb - spec/poisson_spec.rb - spec/shorthand_spec.rb - spec/spec.opts - spec/spec_helper.rb - spec/t_spec.rb - vendor/java/commons-math-2.2.jar has_rdoc: true homepage: https://github.com/clbustos/distribution licenses: [] post_install_message: rdoc_options: - --main - README.txt require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: distribution rubygems_version: 1.3.7 signing_key: specification_version: 3 summary: Statistical Distributions library test_files: [] distribution-0.7.0/Manifest.txt0000644000175000017500000000605612061653751016137 0ustar boutilboutil.autotest History.txt Manifest.txt README.txt Rakefile benchmark/binomial_coefficient.rb benchmark/binomial_coefficient/binomial_coefficient.ds benchmark/binomial_coefficient/binomial_coefficient.xls benchmark/binomial_coefficient/experiment.rb benchmark/factorial_hash.rb benchmark/factorial_method.rb benchmark/odd.rb benchmark/power.rb bin/distribution data/template/distribution.erb data/template/distribution/gsl.erb data/template/distribution/ruby.erb data/template/spec.erb lib/distribution.rb lib/distribution/beta.rb lib/distribution/beta/gsl.rb lib/distribution/beta/java.rb lib/distribution/beta/ruby.rb lib/distribution/binomial.rb lib/distribution/binomial/gsl.rb lib/distribution/binomial/java.rb lib/distribution/binomial/ruby.rb lib/distribution/bivariatenormal.rb lib/distribution/bivariatenormal/gsl.rb lib/distribution/bivariatenormal/java.rb lib/distribution/bivariatenormal/ruby.rb lib/distribution/bivariatenormal/statistics2.rb lib/distribution/chisquare.rb lib/distribution/chisquare/gsl.rb lib/distribution/chisquare/java.rb lib/distribution/chisquare/ruby.rb lib/distribution/chisquare/statistics2.rb lib/distribution/exponential.rb lib/distribution/exponential/gsl.rb lib/distribution/exponential/ruby.rb lib/distribution/f.rb lib/distribution/f/gsl.rb lib/distribution/f/java.rb lib/distribution/f/ruby.rb lib/distribution/f/statistics2.rb lib/distribution/gamma.rb lib/distribution/gamma/gsl.rb lib/distribution/gamma/java.rb lib/distribution/gamma/ruby.rb lib/distribution/hypergeometric.rb lib/distribution/hypergeometric/gsl.rb lib/distribution/hypergeometric/java.rb lib/distribution/hypergeometric/ruby.rb lib/distribution/logistic.rb lib/distribution/logistic/ruby.rb lib/distribution/lognormal.rb lib/distribution/lognormal/gsl.rb lib/distribution/lognormal/ruby.rb lib/distribution/math_extension.rb lib/distribution/math_extension/chebyshev_series.rb lib/distribution/math_extension/erfc.rb lib/distribution/math_extension/exponential_integral.rb lib/distribution/math_extension/gammastar.rb lib/distribution/math_extension/gsl_utilities.rb lib/distribution/math_extension/incomplete_beta.rb lib/distribution/math_extension/incomplete_gamma.rb lib/distribution/math_extension/log_utilities.rb lib/distribution/normal.rb lib/distribution/normal/gsl.rb lib/distribution/normal/java.rb lib/distribution/normal/ruby.rb lib/distribution/normal/statistics2.rb lib/distribution/normalmultivariate.rb lib/distribution/poisson.rb lib/distribution/poisson/gsl.rb lib/distribution/poisson/java.rb lib/distribution/poisson/ruby.rb lib/distribution/t.rb lib/distribution/t/gsl.rb lib/distribution/t/java.rb lib/distribution/t/ruby.rb lib/distribution/t/statistics2.rb spec/beta_spec.rb spec/binomial_spec.rb spec/bivariatenormal_spec.rb spec/chisquare_spec.rb spec/distribution_spec.rb spec/exponential_spec.rb spec/f_spec.rb spec/gamma_spec.rb spec/hypergeometric_spec.rb spec/logistic_spec.rb spec/lognormal_spec.rb spec/math_extension_spec.rb spec/normal_spec.rb spec/poisson_spec.rb spec/shorthand_spec.rb spec/spec.opts spec/spec_helper.rb spec/t_spec.rb vendor/java/commons-math-2.2.jar distribution-0.7.0/README.txt0000644000175000017500000000463412061653751015326 0ustar boutilboutil= distribution * https://github.com/clbustos/distribution == DESCRIPTION: Statistical Distributions library. Includes Normal univariate and bivariate, T, F, Chi Square, Binomial, Hypergeometric, Exponential, Poisson, Beta, LogNormal and Gamma. Uses Ruby by default and C (statistics2/GSL) or Java extensions where available. Includes code from statistics2 on Normal, T, F and Chi Square ruby code [http://blade.nagaokaut.ac.jp/~sinara/ruby/math/statistics2] == FEATURES/PROBLEMS: * Very fast ruby 1.8.7/1.9.+ implementation, with improved method to calculate factorials and others common functions * All methods tested on several ranges. See spec/ * On Jruby and Rubinius, BivariateNormal returns incorrect pdf == API structure Distribution::.(cdf|pdf|p_value|rng) On discrete distributions, exact Ruby implementations of pdf, cdf and p_value could be provided, using Distribution::.exact_(cdf|pdf|p_value) module Distribution::Shorthand provides (you guess?) shortands method to call all methods _(cdf|pdf|p|r) On discrete distributions, exact cdf, pdf and p_value are _(ecdf|epdf|ep) Shortnames for distributions: * Normal: norm * Bivariate Normal: bnor * T: tdist * F: fdist * Chi Square: chisq * Binomial: bino * Hypergeometric: hypg * Exponential: expo * Poisson: pois * Beta: beta * Gamma: gamma * LogNormal: lognormal For example Distribution::T.cdf could be called after including Distribution::Shorthand tdist_cdf == SYNOPSIS: # Returns Gaussian PDF for x pdf=Distribution::Normal.pdf(x) # Returns Gaussian CDF for x cdf=Distribution::Normal.cdf(x) # Returns inverse CDF (or p-value) for x pv =Distribution::Normal.p_value(x) == REQUIREMENTS: I try to provide a Ruby version for each method. To increase (notably!) the speed, please install * Ruby 1.8-1.9: gsl (prefered) or statistics2 * Java: Not yet implemented == INSTALL: gem install distribution To speep up gem install gsl gem install statistics == DEVELOPERS: After checking out the source, run: $ rake newb This task will install any missing dependencies, run the tests/specs, and generate the RDoc. If you want to provide a new distribution, /lib/distribution run $ distribution --new your_distribution This should create the main distribution file, the directory with ruby and gsl engines and the rspec on /spec directory. == LICENSE: GPL V2 distribution-0.7.0/bin/0000755000175000017500000000000012061653751014371 5ustar boutilboutildistribution-0.7.0/bin/distribution0000644000175000017500000000323712061653751017040 0ustar boutilboutil#!/usr/bin/env ruby require 'optparse' require 'fileutils' require 'erb' gem_base=File.expand_path(File.dirname(__FILE__)+"/..") require gem_base+"/lib/distribution" new=false parameters="" OptionParser.new do |opts| opts.banner="Usage: distribution [--new] [--params parameters] distribution" opts.on("-n", "--new", "Create a new template for distribution") do new=true end opts.on("-PMANDATORY", "--params MANDATORY", String, "Parameters for distribution") do |n_param| parameters=", #{n_param}" end opts.on("-h", "--help", "Show this message") do puts opts exit end begin ARGV << "-h" if ARGV.empty? opts.parse!(ARGV) rescue OptionParser::ParseError => e STDERR.puts e.message, "\n", opts exit(-1) end end ARGV.each do |distribution| if new basename=distribution.downcase raise "You should be inside distribution lib directory" unless File.exists? "../distribution.rb" raise "Distribution already created" if File.exists? basename+".rb" main=ERB.new(File.read(gem_base+"/data/template/distribution.erb"),) ruby=ERB.new(File.read(gem_base+"/data/template/distribution/ruby.erb")) gsl=ERB.new(File.read(gem_base+"/data/template/distribution/gsl.erb")) spec=ERB.new(File.read(gem_base+"/data/template/spec.erb")) FileUtils.mkdir(basename) unless File.exists? basename File.open(basename+".rb","w") {|fp| fp.write(main.result(binding))} File.open(basename+"/ruby.rb","w") {|fp| fp.write(ruby.result(binding))} File.open(basename+"/gsl.rb","w") {|fp| fp.write(gsl.result(binding))} File.open("../../spec/#{basename}_spec.rb","w") {|fp| fp.write(spec.result(binding))} end end distribution-0.7.0/metadata.gz.sig0000644000175000017500000000040012061653751016516 0ustar boutilboutilІхaЃiцИ!*Кц§М0П…S*`&kЏРоееѕtwдgщяY‚ШЕˆpйЇŒэX2ЎІxП j€…ЁљƒтМЬЌœЮтЃz/<б^пt-Ќ~Ш^јфЅRЩоšJ_Ў№Aм}пzз;ПТСM‡8ŠIъЭ oињЬЋЃcMHУЃџŒяПˆЈОкvЂS5ђІУЇЇœ(FѓA‰‚f‚‡гмяНРIЅаX„ЊZ]Xz躐ݘ‰Ж&Ђ=€ЂИ{j?(-сыІ8Ty -Œ2”gэф?їdistribution-0.7.0/.autotest0000644000175000017500000000074012061653751015473 0ustar boutilboutil# -*- ruby -*- require 'autotest/restart' # Autotest.add_hook :initialize do |at| # at.extra_files << "../some/external/dependency.rb" # # at.libs << ":../some/external" # # at.add_exception 'vendor' # # at.add_mapping(/dependency.rb/) do |f, _| # at.files_matching(/test_.*rb$/) # end # # %w(TestA TestB).each do |klass| # at.extra_class_map[klass] = "test/test_misc.rb" # end # end # Autotest.add_hook :run_command do |at| # system "rake build" # end distribution-0.7.0/History.txt0000644000175000017500000000653612061653751016035 0ustar boutilboutil=== 0.7.0 / 2011-11-30 + Basic log-normal distribution support, with pdf and cdf for ruby [dennyabraham and clbustos] * Matthew Peterson add Java support for Poisson and Normal distributions. * Updated Logistic, Normal spec. Added LogNormal spec [clbustos] * Updated template for new distributions === 0.6.0 / 2011-09-23 * Incomplete Beta functions on math renamed to Regularized beta, because MathExtension::IncompleteBeta calculates regularized beta function, not Incomplete Beta. * Corrected documention on F distribution and added comments on gamma and beta[Claudio Bustos] * Moved ported methods from GSL to lib/math_extension. Updated spec for gamma and beta distributions[Claudio Bustos] * Added beta distribution functions. p_value does not seem to work yet.[John Woods] * Added most incomplete beta function GSL translations, also log_beta from GSL.[John Woods] * Added header information to the incomplete gamma files translated from GSL[John Woods] * Removed left-over invgammp function.[John Woods] * Fixed lots of bugs, translated most GSL error tests into rspec.[John Woods] * Added Gamma distribution, spec. No statistics2 functions for Gamma, so only implemented pure Ruby and GSL.[John Woods] * Added console task to rakefile[John Woods] === 0.5.0 / 2011-05-03 * Exception raises on calculation of T's cdf with ruby engine. For now, stick to gsl implementation * Added logistic distribution. * Raises an error on binomial if k>n. * New rng for exponential distribution, based on F^-1 [clbustos] * Added power benchmark === 0.4.0 / 2011-02-01 * Poisson and exponential distributions implemented. Implementation of inverse cdf for poisson is not perfect, yet. * +distribution+ executable can create template files for new distributions. * MathExtension should work fine with Ruby 1.8. Fixed shadowed variable on MathExtension.naive_factorial * Added factorial lookup table for n<20. * Added exact cdf for Binomial * Binomial coefficient in function of permutations. Deleted incomplete beta until we found a faster way to calculate it === 0.3.0 / 2011-01-28 * Included support for binomial distribution. p_value is not accurate * Included alias for ruby exact methods on discrete distributions, when they are available * Works on Jruby and Ruby 1.8.7 * Binomial coefficient optimized. Falling factorial method with Swing Prime on factorial provides a 10x improvement over naive version. * Working on binomial coefficient using gamma. The same problem as using Sterling: faster than exact version, but when it requires BigDecimal, is 2-3x slower * Deleted Fixnum extension on Hypergeometric === 0.2.0 / 2011-01-27 * Shorthands for F and T are 'fdist' and 'tdist' now, to avoid confussions * Added Hypergeometric distribution with pdf, cdf, p_value. The Ruby version uses a very slow factorial process, but also has pdf_with_stirling if you don't care about accuracy at all. This latter method needs to be improved, actually, in terms of which choose function it calls for the numerator and denominator. Once that's done, it can replace the slower pdf function. [John Woods] * Spec for cdf and p_value of Hypergeometric * New cdf and p_value on Hypergeometric[clbustos] * Hypergeometric#pdf returns 0 on max(0,n+m-t)<=k<=min(m,n) * Improved factorial calculation, using Luschny algorithms === 0.1.0 / 2011-01-26 * Basic set (pdf, cdf, p_value) for Normal, Chi Square, F and T distributions distribution-0.7.0/Rakefile0000644000175000017500000000126312061653751015270 0ustar boutilboutil# -*- ruby -*- $:.unshift(File.expand_path(File.dirname(__FILE__)+"/lib/")) require 'rubygems' require 'hoe' require 'distribution' require 'rubyforge' # Hoe.plugin :compiler # Hoe.plugin :gem_prelude_sucks Hoe.plugin :git # Hoe.plugin :inline # Hoe.plugin :racc Hoe.plugin :rubyforge Hoe.spec 'distribution' do self.developer('Claudio Bustos', 'clbustos_at_gmail.com') self.version=Distribution::VERSION self.extra_dev_deps << ["rspec",">=2.0"] << ["rubyforge",">=0"] end # git log --pretty=format:"*%s[%cn]" v0.5.0..HEAD >> History.txt desc "Open an irb session preloaded with distribution" task :console do sh "irb -rubygems -I lib -r distribution.rb" end # vim: syntax=ruby distribution-0.7.0/lib/0000755000175000017500000000000012061653751014367 5ustar boutilboutildistribution-0.7.0/lib/distribution/0000755000175000017500000000000012061653751017106 5ustar boutilboutildistribution-0.7.0/lib/distribution/math_extension.rb0000644000175000017500000002646212061653751022472 0ustar boutilboutil# The next few requires eventually probably need to go in their own gem. They're all functions and constants used by # GSL-adapted pure Ruby math functions. require "distribution/math_extension/chebyshev_series" require "distribution/math_extension/erfc" require "distribution/math_extension/exponential_integral" require "distribution/math_extension/gammastar" require "distribution/math_extension/gsl_utilities" require "distribution/math_extension/incomplete_gamma" require "distribution/math_extension/incomplete_beta" require "distribution/math_extension/log_utilities" if RUBY_VERSION<"1.9" require 'mathn' def Prime.each(upper,&block) @primes=Prime.new @primes.each do |prime| break if prime > upper.to_i block.call(prime) end end else require 'prime' end require 'bigdecimal' require 'bigdecimal/math' module Distribution # Extension for Ruby18 # Includes gamma and lgamma module MathExtension18 LOG_2PI = Math.log(2 * Math::PI)# log(2PI) N = 8 B0 = 1.0 B1 = -1.0 / 2.0 B2 = 1.0 / 6.0 B4 = -1.0 / 30.0 B6 = 1.0 / 42.0 B8 = -1.0 / 30.0 B10 = 5.0 / 66.0 B12 = -691.0 / 2730.0 B14 = 7.0 / 6.0 B16 = -3617.0 / 510.0 # From statistics2 def loggamma(x) v = 1.0 while (x < N) v *= x x += 1.0 end w = 1.0 / (x * x) ret = B16 / (16 * 15) ret = ret * w + B14 / (14 * 13) ret = ret * w + B12 / (12 * 11) ret = ret * w + B10 / (10 * 9) ret = ret * w + B8 / ( 8 * 7) ret = ret * w + B6 / ( 6 * 5) ret = ret * w + B4 / ( 4 * 3) ret = ret * w + B2 / ( 2 * 1) ret = ret / x + 0.5 * LOG_2PI - Math.log(v) - x + (x - 0.5) * Math.log(x) ret end # Gamma function. # From statistics2 def gamma(x) if (x < 0.0) return Math::PI / (Math.sin(Math::PI * x) * Math.exp(loggamma(1 - x))) #/ end Math.exp(loggamma(x)) end def lgamma(x) [loggamma(x.abs), Math.gamma(x) < 0 ? -1 : 1] end end # Useful additions to Math module MathExtension # Factorization based on Prime Swing algorithm, by Luschny (the king of factorial numbers analysis :P ) # == Reference # * The Homepage of Factorial Algorithms. (C) Peter Luschny, 2000-2010 # == URL: http://www.luschny.de/math/factorial/csharp/FactorialPrimeSwing.cs.html class SwingFactorial attr_reader :result SmallOddSwing=[ 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, 35102025, 5014575,145422675, 9694845, 300540195, 300540195] SmallFactorial=[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000] def bitcount(n) bc = n - ((n >> 1) & 0x55555555); bc = (bc & 0x33333333) + ((bc >> 2) & 0x33333333); bc = (bc + (bc >> 4)) & 0x0f0f0f0f; bc += bc >> 8; bc += bc >> 16; bc = bc & 0x3f; bc end def initialize(n) if (n<20) @result=SmallFactorial[n] #naive_factorial(n) else @prime_list=[] exp2 = n - bitcount(n); @result= recfactorial(n)<< exp2 end end def recfactorial(n) return 1 if n<2 (recfactorial(n/2)**2) * swing(n) end def swing(n) return SmallOddSwing[n] if (n<33) sqrtN = Math.sqrt(n).floor count=0 Prime.each(n/3) do |prime| next if prime<3 if (prime<=sqrtN) q=n _p=1 while((q=(q/prime).truncate)>0) do if((q%2)==1) _p*=prime end end if _p>1 @prime_list[count]=_p count+=1 end else if ((n/prime).truncate%2==1) @prime_list[count]=prime count+=1 end end end prod=get_primorial((n/2).truncate+1,n) prod * @prime_list[0,count].inject(1) {|ac,v| ac*v} end def get_primorial(low,up) prod=1; Prime.each(up) do |prime| next if prime LOG_FLOAT_MAX") if x + adx > LOG_FLOAT_MAX raise("Underflow Error in exp_err: x - adx < LOG_FLOAT_MIN") if x - adx < LOG_FLOAT_MIN [Math.exp(x), Math.exp(x) * [Float::EPSILON, Math.exp(adx) - 1.0/Math.exp(adx)] + 2.0 * Float::EPSILON * Math.exp(x).abs] end end enddistribution-0.7.0/lib/distribution/math_extension/incomplete_gamma.rb0000644000175000017500000004010712061653751025763 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Derived from GSL-1.9 source files in the specfunc/ dir. # require "statsample" module Distribution module MathExtension module IncompleteGamma NMAX = 5000 SMALL = Float::EPSILON ** 3 PG21 = -2.404113806319188570799476 # PolyGamma[2,1] class << self # Helper function for plot #def range_to_array r # r << (r.last - r.first)/100.0 if r.size == 2 # set dr as Dr/100.0 # arr = [] # pos = r[0] # while pos <= r[1] # arr << pos # pos += r[2] # end # arr #end # #def plot a, x_range, fun = :p # x_range = range_to_array(x_range) if x_range.is_a?(Array) # y_range = x_range.collect { |x| self.send(fun, a, x) } # graph = Statsample::Graph::Scatterplot.new x_range.to_scale, y_range.to_scale # f = File.new("test.svg", "w") # f.puts(graph.to_svg) # f.close # `google-chrome test.svg` #end # The dominant part, D(a,x) := x^a e^(-x) / Gamma(a+1) # gamma_inc_D in GSL-1.9. def d(a, x, with_error = false) error = nil if a < 10.0 ln_a = Math.lgamma(a+1.0).first lnr = a * Math.log(x) - x - ln_a result = Math.exp(lnr) error = 2.0 * Float::EPSILON * (lnr.abs + 1.0) + result.abs if with_error with_error ? [result,error] : result else ln_term = ln_term_error = nil if x < 0.5*a u = x/a.to_f ln_u = Math.log(u) ln_term = ln_u - u + 1.0 ln_term_error = (ln_u.abs + u.abs + 1.0) * Float::EPSILON if with_error else mu = (x-a)/a.to_f ln_term = Log::log_1plusx_minusx(mu, with_error) ln_term, ln_term_error = ln_term if with_error end gstar = Gammastar.evaluate(a, with_error) gstar,gstar_error = gstar if with_error term1 = Math.exp(a*ln_term) / Math.sqrt(2.0*Math::PI*a) result = term1/gstar error = 2.0*Float::EPSILON*((a*ln_term).abs+1.0) * result.abs + gstar_error/gstar.abs * result.abs if with_error with_error ? [result,error] : result end end # gamma_inc_P_series def p_series(a,x,with_error=false) d = d(a,x,with_error) d, d_err = d if with_error sum = 1.0 term = 1.0 n = 1 1.upto(NMAX-1) do |n| term *= x / (a+n).to_f sum += term break if (term/sum).abs < Float::EPSILON end result = d * sum if n == NMAX STDERR.puts("Error: n reached NMAX in p series") else return with_error ? [result,d_err * sum.abs + (1.0+n)*Float::EPSILON * result.abs] : result end end # This function does not exist in GSL, but is nonetheless GSL code. It's for calculating two specific ranges of p. def q_asymptotic_uniform_complement a,x,with_error=false q = q_asymptotic_uniform(a, x, with_error) q,q_err = q if with_error result = 1.0 - q return with_error ? [result, q_err + 2.0*Float::EPSILON*result.abs] : result end def q_continued_fraction_complement a,x,with_error=false q = q_continued_fraction(a,x,with_error) return with_error ? [1.0 - q.first, q.last + 2.0*Float::EPSILON*(1.0-q.first).abs] : 1.0 - q end def q_large_x_complement a,x,with_error=false q = q_large_x(a,x,with_error) return with_error ? [1.0 - q.first, q.last + 2.0*Float::EPSILON*(1.0-q.first).abs] : 1.0 - q end # The incomplete gamma function. # gsl_sf_gamma_inc_P_e def p a,x,with_error=false raise(ArgumentError, "Range Error: a must be positive, x must be non-negative") if a <= 0.0 || x < 0.0 if x == 0.0 return with_error ? [0.0, 0.0] : 0.0 elsif x < 20.0 || x < 0.5*a return p_series(a, x, with_error) elsif a > 1e6 && (x-a)*(x-a) < a return q_asymptotic_uniform_complement a, x, with_error elsif a <= x if a > 0.2*x return q_continued_fraction_complement(a, x, with_error) else return q_large_x_complement(a, x, with_error) end elsif (x-a)*(x-a) < a return q_asymptotic_uniform_complement a, x, with_error else return p_series(a, x, with_error) end end # gamma_inc_Q_e def q a,x,with_error=false raise(ArgumentError, "Range Error: a and x must be non-negative") if (a < 0.0 || x < 0.0) if x == 0.0 return with_error ? [1.0, 0.0] : 1.0 elsif a == 0.0 return with_error ? [0.0, 0.0] : 0.0 elsif x <= 0.5*a # If series is quick, do that. p = p_series(a,x, with_error) p,p_err = p if with_error result = 1.0 - p return with_error ? [result, p_err + 2.0*Float::EPSILON*result.abs] : result elsif a >= 1.0e+06 && (x-a)*(x-a) < a # difficult asymptotic regime, only way to do this region return q_asymptotic_uniform(a, x, with_error) elsif a < 0.2 && x < 5.0 return q_series(a,x, with_error) elsif a <= x return x <= 1.0e+06 ? q_continued_fraction(a, x, with_error) : q_large_x(a, x, with_error) else if x > a-Math.sqrt(a) return q_continued_fraction(a, x, with_error) else p = p_series(a, x, with_error) p, p_err = p if with_error result = 1.0 - p return with_error ? [result, p_err + 2.0*Float::EPSILON*result.abs] : result end end end # gamma_inc_Q_CF def q_continued_fraction a, x, with_error=false d = d(a, x, with_error) f = f_continued_fraction(a, x, with_error) if with_error [d.first*(a/x).to_f*f.first, d.last * ((a/x).to_f*f.first).abs + (d.first*a/x*f.last).abs] else d * (a/x).to_f * f end end # gamma_inc_Q_large_x in GSL-1.9 def q_large_x a,x,with_error=false d = d(a,x,with_error) d,d_err = d if with_error sum = 1.0 term = 1.0 last = 1.0 n = 1 1.upto(NMAX-1).each do |n| term *= (a-n)/x break if (term/last).abs > 1.0 break if (term/sum).abs < Float::EPSILON sum += term last = term end result = d*(a/x)*sum error = d_err * (a/x).abs * sum if with_error if n == NMAX STDERR.puts("Error: n reached NMAX in q_large_x") else return with_error ? [result,error] : result end end # Uniform asymptotic for x near a, a and x large # gamma_inc_Q_asymp_unif def q_asymptotic_uniform(a, x, with_error = false) rta = Math.sqrt(a) eps = (x-a).quo(a) ln_term = Log::log_1plusx_minusx(eps, with_error) ln_term, ln_term_err = ln_term if with_error eta = (eps >= 0 ? 1 : -1) * Math.sqrt(-2*ln_term) erfc = Math.erfc_e(eta*rta/SQRT2, with_error) erfc, erfc_err = erfc if with_error c0 = c1 = nil if eps.abs < ROOT5_FLOAT_EPSILON c0 = -1.quo(3) + eps*(1.quo(12) - eps*(23.quo(540) - eps*(353.quo(12960) - eps*589.quo(30240)))) c1 = -1.quo(540) - eps.quo(288) else rt_term = Math.sqrt(-2 * ln_term.quo(eps*eps)) lam = x.quo(a) c0 = (1 - 1/rt_term)/eps c1 = -(eta**3 * (lam*lam + 10*lam + 1) - 12*eps**3).quo(12 * eta**3 * eps**3) end r = Math.exp(-0.5*a*eta*eta) / (SQRT2*SQRTPI*rta) * (c0 + c1.quo(a)) result = 0.5 * erfc + r with_error ? [result, Float::EPSILON + (r*0.5*a*eta*eta).abs + 0.5*erfc_err + 2.0*Float::EPSILON + result.abs] : result end # gamma_inc_F_CF def f_continued_fraction a, x, with_error = false hn = 1.0 # convergent cn = 1.0 / SMALL dn = 1.0 n = 2 2.upto(NMAX-1).each do |n| an = n.odd? ? 0.5*(n-1)/x : (0.5*n-a)/x dn = 1.0 + an * dn dn = SMALL if dn.abs < SMALL cn = 1.0 + an / cn cn = SMALL if cn.abs < SMALL dn = 1.0 / dn delta = cn * dn hn *= delta break if (delta-1.0).abs < Float::EPSILON end if n == NMAX STDERR.puts("Error: n reached NMAX in f continued fraction") else with_error ? [hn,2.0*Float::EPSILON * hn.abs + Float::EPSILON*(2.0+0.5*n) * hn.abs] : hn end end def q_series(a,x,with_error=false) term1 = nil sum = nil term2 = nil begin lnx = Math.log(x) el = EULER + lnx c1 = -el c2 = Math::PI * Math::PI / 12.0 - 0.5*el*el c3 = el*(Math::PI*Math::PI/12.0 - el*el/6.0) + PG21/6.0 c4 = -0.04166666666666666667 * (-1.758243446661483480 + lnx) * (-0.764428657272716373 + lnx) * ( 0.723980571623507657 + lnx) * ( 4.107554191916823640 + lnx) c5 = -0.0083333333333333333 * (-2.06563396085715900 + lnx) * (-1.28459889470864700 + lnx) * (-0.27583535756454143 + lnx) * ( 1.33677371336239618 + lnx) * ( 5.17537282427561550 + lnx) c6 = -0.0013888888888888889 * (-2.30814336454783200 + lnx) * (-1.65846557706987300 + lnx) * (-0.88768082560020400 + lnx) * ( 0.17043847751371778 + lnx) * ( 1.92135970115863890 + lnx) * ( 6.22578557795474900 + lnx) c7 = -0.00019841269841269841 (-2.5078657901291800 + lnx) * (-1.9478900888958200 + lnx) * (-1.3194837322612730 + lnx) * (-0.5281322700249279 + lnx) * ( 0.5913834939078759 + lnx) * ( 2.4876819633378140 + lnx) * ( 7.2648160783762400 + lnx) c8 = -0.00002480158730158730 * (-2.677341544966400 + lnx) * (-2.182810448271700 + lnx) * (-1.649350342277400 + lnx) * (-1.014099048290790 + lnx) * (-0.191366955370652 + lnx) * ( 0.995403817918724 + lnx) * ( 3.041323283529310 + lnx) * ( 8.295966556941250 + lnx) * c9 = -2.75573192239859e-6 * (-2.8243487670469080 + lnx) * (-2.3798494322701120 + lnx) * (-1.9143674728689960 + lnx) * (-1.3814529102920370 + lnx) * (-0.7294312810261694 + lnx) * ( 0.1299079285269565 + lnx) * ( 1.3873333251885240 + lnx) * ( 3.5857258865210760 + lnx) * ( 9.3214237073814600 + lnx) * c10 = -2.75573192239859e-7 * (-2.9540329644556910 + lnx) * (-2.5491366926991850 + lnx) * (-2.1348279229279880 + lnx) * (-1.6741881076349450 + lnx) * (-1.1325949616098420 + lnx) * (-0.4590034650618494 + lnx) * ( 0.4399352987435699 + lnx) * ( 1.7702236517651670 + lnx) * ( 4.1231539047474080 + lnx) * ( 10.342627908148680 + lnx) term1 = a*(c1+a*(c2+a*(c3+a*(c4+a*(c5+a*(c6+a*(c7+a*(c8+a*(c9+a*c10))))))))) end n = 1 begin t = 1.0 sum = 1.0 1.upto(NMAX-1).each do |n| t *= -x/(n+1.0) sum += (a+1.0) / (a+n+1.0) * t break if (t/sum).abs < Float::EPSILON end end if n == NMAX STDERR.puts("Error: n reached NMAX in q_series") else term2 = (1.0 - term1) * a/(a+1.0) * x * sum result = term1+term2 with_error ? [result, Float::EPSILON*term1.abs + 2.0*term2.abs + 2.0*Float::EPSILON*result.abs] : result end end # gamma_inc_series def series a,x,with_error = false q = q_series(a,x,with_error) g = Math.gamma(a) STDERR.puts("Warning: Don't know error for Math.gamma. Error will be incorrect") if with_error # When we get the error from Gamma, switch the comment on the next to lines # with_error ? [q.first*g.first, (q.first*g.last).abs + (q.last*g.first).abs + 2.0*Float::EPSILON*(q.first*g.first).abs] : q*g with_error ? [q.first*g, (q.first*Float::EPSILON).abs + (q.last*g.first).abs + 2.0*Float::EPSILON(q.first*g).abs] : q*g end # gamma_inc_a_gt_0 def a_greater_than_0 a, x, with_error = false q = q(a,x,with_error) q,q_err = q if with_error g = Math.gamma(a) STDERR.puts("Warning: Don't know error for Math.gamma. Error will be incorrect") if with_error g_err = Float::EPSILON result = g*q error = (g*q_err).abs + (g_err*q).abs if with_error with_error ? [result,error] : result end # gamma_inc_CF def continued_fraction a,x, with_error=false f = f_continued_fraction(a,x,with_error) f,f_error = f if with_error pre = Math.exp((a-1.0)*Math.log(x) - x) STDERR.puts("Warning: Don't know error for Math.exp. Error will be incorrect") if with_error pre_error = Float::EPSILON result = f*pre if with_error error = (f_error*pre).abs + (f*pre_error) + (2.0+a.abs)*Float::EPSILON*result.abs [result,error] else result end end # Unnormalized incomplete gamma function. # gsl_sf_gamma_inc_e def unnormalized a,x,with_error = false raise(ArgumentError, "x cannot be negative") if x < 0.0 if x == 0.0 result = Math.gamma(a.to_f) STDERR.puts("Warning: Don't know error for Math.gamma. Error will be incorrect") if with_error return with_error ? [result, Float::EPSILON] : result elsif a == 0.0 return ExponentialIntegral.first_order(x.to_f, with_error) elsif a > 0.0 return a_greater_than_0(a.to_f, x.to_f, with_error) elsif x > 0.25 # continued fraction seems to fail for x too small return continued_fraction(a.to_f, x.to_f, with_error) elsif a.abs < 0.5 return series(a.to_f,x.to_f,with_error) else fa = a.floor.to_f da = a - fa g_da = da > 0.0 ? a_greater_than_0(da, x.to_f, with_error) : ExponentialIntegral.first_order(x.to_f, with_error) g_da, g_da_err = g_da if with_error alpha = da gax = g_da # Gamma(alpha-1,x) = 1/(alpha-1) (Gamma(a,x) - x^(alpha-1) e^-x) begin shift = Math.exp(-x + (alpha-1.0)*Math.log(x)) gax = (gax-shift) / (alpha-1.0) alpha -= 1.0 end while alpha > a result = gax return with_error ? [result, 2.0*(1.0 + a.abs) * Float::EPSILON*gax.abs] : result end end end end end enddistribution-0.7.0/lib/distribution/math_extension/exponential_integral.rb0000644000175000017500000000557212061653751026704 0ustar boutilboutilmodule Distribution module MathExtension # From GSL-1.9. module ExponentialIntegral class << self def first_order x, scale = 0, with_error = false xmaxt = -Math::LOG_FLOAT_MIN xmax = xmaxt - Math.log(xmaxt) result = nil error = with_error ? nil : 0.0 if x < -xmax && !scale raise("Overflow Error") elsif x <= -10.0 s = 1.0 / x * ( scale ? 1.0 : Math.exp(-x)) result_c = ChebyshevSeries.eval(20.0/x+1.0, :ae11, with_error) result_c, result_c_err = result_c if with_error result = s * (1.0 + result_c) error ||= (s * result_c_err) + 2.0*Float::EPSILON * (x.abs + 1.0) * result.abs elsif x <= -4.0 s = 1.0 / x * (scale ? 1.0 : Math.exp(-x)) result_c = ChebyshevSeries.eval((40.0/x+7.0)/3.0, :ae12, with_error) result_c, result_c_err = result_c if with_error result = s * (1.0 + result_c) error ||= (s * result_c_err) + 2.0*Float::EPSILON * result.abs elsif x <= -1.0 ln_term = - Math.log(x.abs) scale_factor = scale ? Math.exp(x) : 1.0 result_c = ChebyshevSeries.eval((2.0*x+5.0)/3.0, :e11, with_error) result_c, result_c_err = result_c if with_error result = scale_factor * (ln_term + result_c) error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0*Float::EPSILON*result.abs elsif x == 0.0 raise(ArgumentError, "Domain Error") elsif x <= 1.0 ln_term = - Math.log(x.abs) scale_factor = scale ? Math.exp(x) : 1.0 result_c = ChebyshevSeries.eval(x, :e12, with_error) result_c, result_c_err = result_c if with_error result = scale_factor * (ln_term - 0.6875 + x + result_c) error ||= scale_factor * (result_c_err + Float::EPSILON * ln_term.abs) + 2.0*Float::EPSILON*result.abs elsif x <= 4.0 s = 1.0 / x * (scale ? 1.0 : Math.exp(-x)) result_c = ChebyshevSeries.eval((8.0/x-5.0)/3.0, :ae13, with_error) result_c, result_c_err = result_c if with_error result = s * (1.0 + result_c) error ||= (s * result_c_err) + 2.0*Float::EPSILON * result.abs elsif x <= xmax || scale s = 1.0 / x * (scale ? 1.0 : Math.exp(-x)) result_c = ChebyshevSeries.eval(8.0/x-1.0, :ae14, with_error) result_c, result_c_err = result_c if with_error result = s * (1.0 + result_c) error ||= s * (Float::EPSILON + result_c_err) + 2.0*(x+1.0)*Float::EPSILON * result.abs raise("Underflow Error") if result == 0.0 else raise("Underflow Error") end with_error ? [result, error] : result end end end end end distribution-0.7.0/lib/distribution/math_extension/log_utilities.rb0000644000175000017500000000524612061653751025343 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Derived from GSL-1.9 source files in the specfunc/ dir. module Distribution module MathExtension # Various logarithm shortcuts, adapted from GSL-1.9. module Log C1 = -1.quo(2) C2 = 1.quo(3) C3 = -1.quo(4) C4 = 1.quo(5) C5 = -1.quo(6) C6 = 1.quo(7) C7 = -1.quo(8) C8 = 1.quo(9) C9 = -1.quo(10) class << self # gsl_log1p from GSL-1.9 sys/log1p.c # log for very small x def log1p x # in C, this is volatile double y. # Not sure how to reproduce that in Ruby. y = 1+x Math.log(y) - ((y-1)-x).quo(y) # cancel errors with IEEE arithmetic end # \log(1+x) for x > -1 # gsl_sf_log_1plusx_e def log_1plusx(x, with_error = false) raise(ArgumentError, "Range error: x must be > -1") if x <= -1 if x.abs < Math::ROOT6_FLOAT_EPSILON result = x * (1.0 + x * (C1 + x*(C2 + x*(C3 + x*(C4 + x*begin C5 + x*(C6 + x*(C7 + x*(C8 + x*C9))) # formerly t = this end))))) return with_error ? [result, Float::EPSILON * result.abs] : result elsif x.abs < 0.5 c = ChebyshevSeries.evaluate(:lopx, (8*x + 1).quo(2*x+4), with_error) return with_error ? [x * c.first, x * c.last] : x*c else result = Math.log(1+x) return with_error ? [result, Float::EPSILON*result.abs] : result end end # \log(1+x)-x for x > -1 # gsl_sf_log_1plusx_mx_e def log_1plusx_minusx x, with_error = false raise(ArgumentError, "Range error: x must be > -1") if x <= -1 if x.abs < Math::ROOT5_FLOAT_EPSILON result = x*x * (C1 + x*(C2 + x*(C3 + x*(C4 + x*begin C5 + x*(C6 + x*(C7 + x*(C8 + x*C9))) # formerly t = this end)))) return with_error ? [result, Float::EPSILON * result.abs] : result elsif x.abs < 0.5 c = ChebyshevSeries.evaluate(:lopxmx, (8*x + 1).quo(2*x+4), with_error) return with_error ? [x*x * c.first, x*x * c.last] : x*x*c else lterm = Math.log(1.0+x) error = Float::EPSILON * (lterm.abs + x.abs) if with_error result = lterm - x return with_error ? [result, error] : result end end protected # Abstracted from other log helper functions in GSL-1.9. def x_less_than_root_epsilon x, with_error result = square_x ? x*x : x with_error ? [result, Float::EPSILON * result.abs] : result end end end end end distribution-0.7.0/lib/distribution/math_extension/chebyshev_series.rb0000644000175000017500000004723712061653751026027 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Derived from GSL-1.9 source files in the specfunc/ and cheb/ dirs. module Distribution module MathExtension # Adapted from GSL-1.9. class ChebyshevSeries DATA = {:lopx => [ 2.16647910664395270521272590407, -0.28565398551049742084877469679, 0.01517767255690553732382488171, -0.00200215904941415466274422081, 0.00019211375164056698287947962, -0.00002553258886105542567601400, 2.9004512660400621301999384544e-06, -3.8873813517057343800270917900e-07, 4.7743678729400456026672697926e-08, -6.4501969776090319441714445454e-09, 8.2751976628812389601561347296e-10, -1.1260499376492049411710290413e-10, 1.4844576692270934446023686322e-11, -2.0328515972462118942821556033e-12, 2.7291231220549214896095654769e-13, -3.7581977830387938294437434651e-14, 5.1107345870861673561462339876e-15, -7.0722150011433276578323272272e-16, 9.7089758328248469219003866867e-17, -1.3492637457521938883731579510e-17, 1.8657327910677296608121390705e-18 ], :lopxmx => [ -1.12100231323744103373737274541, 0.19553462773379386241549597019, -0.01467470453808083971825344956, 0.00166678250474365477643629067, -0.00018543356147700369785746902, 0.00002280154021771635036301071, -2.8031253116633521699214134172e-06, 3.5936568872522162983669541401e-07, -4.6241857041062060284381167925e-08, 6.0822637459403991012451054971e-09, -8.0339824424815790302621320732e-10, 1.0751718277499375044851551587e-10, -1.4445310914224613448759230882e-11, 1.9573912180610336168921438426e-12, -2.6614436796793061741564104510e-13, 3.6402634315269586532158344584e-14, -4.9937495922755006545809120531e-15, 6.8802890218846809524646902703e-16, -9.5034129794804273611403251480e-17, 1.3170135013050997157326965813e-17], :gstar_a => [ 2.16786447866463034423060819465, -0.05533249018745584258035832802, 0.01800392431460719960888319748, -0.00580919269468937714480019814, 0.00186523689488400339978881560, -0.00059746524113955531852595159, 0.00019125169907783353925426722, -0.00006124996546944685735909697, 0.00001963889633130842586440945, -6.3067741254637180272515795142e-06, 2.0288698405861392526872789863e-06, -6.5384896660838465981983750582e-07, 2.1108698058908865476480734911e-07, -6.8260714912274941677892994580e-08, 2.2108560875880560555583978510e-08, -7.1710331930255456643627187187e-09, 2.3290892983985406754602564745e-09, -7.5740371598505586754890405359e-10, 2.4658267222594334398525312084e-10, -8.0362243171659883803428749516e-11, 2.6215616826341594653521346229e-11, -8.5596155025948750540420068109e-12, 2.7970831499487963614315315444e-12, -9.1471771211886202805502562414e-13, 2.9934720198063397094916415927e-13, -9.8026575909753445931073620469e-14, 3.2116773667767153777571410671e-14, -1.0518035333878147029650507254e-14, 3.4144405720185253938994854173e-15, -1.0115153943081187052322643819e-15 ], :gstar_b => [ 0.0057502277273114339831606096782, 0.0004496689534965685038254147807, -0.0001672763153188717308905047405, 0.0000615137014913154794776670946, -0.0000223726551711525016380862195, 8.0507405356647954540694800545e-06, -2.8671077107583395569766746448e-06, 1.0106727053742747568362254106e-06, -3.5265558477595061262310873482e-07, 1.2179216046419401193247254591e-07, -4.1619640180795366971160162267e-08, 1.4066283500795206892487241294e-08, -4.6982570380537099016106141654e-09, 1.5491248664620612686423108936e-09, -5.0340936319394885789686867772e-10, 1.6084448673736032249959475006e-10, -5.0349733196835456497619787559e-11, 1.5357154939762136997591808461e-11, -4.5233809655775649997667176224e-12, 1.2664429179254447281068538964e-12, -3.2648287937449326771785041692e-13, 7.1528272726086133795579071407e-14, -9.4831735252566034505739531258e-15, -2.3124001991413207293120906691e-15, 2.8406613277170391482590129474e-15, -1.7245370321618816421281770927e-15, 8.6507923128671112154695006592e-16, -3.9506563665427555895391869919e-16, 1.6779342132074761078792361165e-16, -6.0483153034414765129837716260e-17 ], :e11 => [ -16.11346165557149402600, 7.79407277874268027690, -1.95540581886314195070, 0.37337293866277945612, -0.05692503191092901938, 0.00721107776966009185, -0.00078104901449841593, 0.00007388093356262168, -0.00000620286187580820, 0.00000046816002303176, -0.00000003209288853329, 0.00000000201519974874, -0.00000000011673686816, 0.00000000000627627066, -0.00000000000031481541, 0.00000000000001479904, -0.00000000000000065457, 0.00000000000000002733, -0.00000000000000000108], :e12 => [ -0.03739021479220279500, 0.04272398606220957700, -0.13031820798497005440, 0.01441912402469889073, -0.00134617078051068022, 0.00010731029253063780, -0.00000742999951611943, 0.00000045377325690753, -0.00000002476417211390, 0.00000000122076581374, -0.00000000005485141480, 0.00000000000226362142, -0.00000000000008635897, 0.00000000000000306291, -0.00000000000000010148, 0.00000000000000000315 ], :ae11 => [ 0.121503239716065790, -0.065088778513550150, 0.004897651357459670, -0.000649237843027216, 0.000093840434587471, 0.000000420236380882, -0.000008113374735904, 0.000002804247688663, 0.000000056487164441, -0.000000344809174450, 0.000000058209273578, 0.000000038711426349, -0.000000012453235014, -0.000000005118504888, 0.000000002148771527, 0.000000000868459898, -0.000000000343650105, -0.000000000179796603, 0.000000000047442060, 0.000000000040423282, -0.000000000003543928, -0.000000000008853444, -0.000000000000960151, 0.000000000001692921, 0.000000000000607990, -0.000000000000224338, -0.000000000000200327, -0.000000000000006246, 0.000000000000045571, 0.000000000000016383, -0.000000000000005561, -0.000000000000006074, -0.000000000000000862, 0.000000000000001223, 0.000000000000000716, -0.000000000000000024, -0.000000000000000201, -0.000000000000000082, 0.000000000000000017], :ae12 => [ 0.582417495134726740, -0.158348850905782750, -0.006764275590323141, 0.005125843950185725, 0.000435232492169391, -0.000143613366305483, -0.000041801320556301, -0.000002713395758640, 0.000001151381913647, 0.000000420650022012, 0.000000066581901391, 0.000000000662143777, -0.000000002844104870, -0.000000000940724197, -0.000000000177476602, -0.000000000015830222, 0.000000000002905732, 0.000000000001769356, 0.000000000000492735, 0.000000000000093709, 0.000000000000010707, -0.000000000000000537, -0.000000000000000716, -0.000000000000000244, -0.000000000000000058], :ae13 => [ -0.605773246640603460, -0.112535243483660900, 0.013432266247902779, -0.001926845187381145, 0.000309118337720603, -0.000053564132129618, 0.000009827812880247, -0.000001885368984916, 0.000000374943193568, -0.000000076823455870, 0.000000016143270567, -0.000000003466802211, 0.000000000758754209, -0.000000000168864333, 0.000000000038145706, -0.000000000008733026, 0.000000000002023672, -0.000000000000474132, 0.000000000000112211, -0.000000000000026804, 0.000000000000006457, -0.000000000000001568, 0.000000000000000383, -0.000000000000000094, 0.000000000000000023], :ae14 => [ -0.18929180007530170, -0.08648117855259871, 0.00722410154374659, -0.00080975594575573, 0.00010999134432661, -0.00001717332998937, 0.00000298562751447, -0.00000056596491457, 0.00000011526808397, -0.00000002495030440, 0.00000000569232420, -0.00000000135995766, 0.00000000033846628, -0.00000000008737853, 0.00000000002331588, -0.00000000000641148, 0.00000000000181224, -0.00000000000052538, 0.00000000000015592, -0.00000000000004729, 0.00000000000001463, -0.00000000000000461, 0.00000000000000148, -0.00000000000000048, 0.00000000000000016, -0.00000000000000005], :erfc_xlt1 => [ 1.06073416421769980345174155056, -0.42582445804381043569204735291, 0.04955262679620434040357683080, 0.00449293488768382749558001242, -0.00129194104658496953494224761, -0.00001836389292149396270416979, 0.00002211114704099526291538556, -5.23337485234257134673693179020e-7, -2.78184788833537885382530989578e-7, 1.41158092748813114560316684249e-8, 2.72571296330561699984539141865e-9, -2.06343904872070629406401492476e-10, -2.14273991996785367924201401812e-11, 2.22990255539358204580285098119e-12, 1.36250074650698280575807934155e-13, -1.95144010922293091898995913038e-14, -6.85627169231704599442806370690e-16, 1.44506492869699938239521607493e-16, 2.45935306460536488037576200030e-18, -9.29599561220523396007359328540e-19 ], :erfc_x15 => [ 0.44045832024338111077637466616, -0.143958836762168335790826895326, 0.044786499817939267247056666937, -0.013343124200271211203618353102, 0.003824682739750469767692372556, -0.001058699227195126547306482530, 0.000283859419210073742736310108, -0.000073906170662206760483959432, 0.000018725312521489179015872934, -4.62530981164919445131297264430e-6, 1.11558657244432857487884006422e-6, -2.63098662650834130067808832725e-7, 6.07462122724551777372119408710e-8, -1.37460865539865444777251011793e-8, 3.05157051905475145520096717210e-9, -6.65174789720310713757307724790e-10, 1.42483346273207784489792999706e-10, -3.00141127395323902092018744545e-11, 6.22171792645348091472914001250e-12, -1.26994639225668496876152836555e-12, 2.55385883033257575402681845385e-13, -5.06258237507038698392265499770e-14, 9.89705409478327321641264227110e-15, -1.90685978789192181051961024995e-15, 3.50826648032737849245113757340e-16 ], :erfc_x510 => [ 1.11684990123545698684297865808, 0.003736240359381998520654927536, -0.000916623948045470238763619870, 0.000199094325044940833965078819, -0.000040276384918650072591781859, 7.76515264697061049477127605790e-6, -1.44464794206689070402099225301e-6, 2.61311930343463958393485241947e-7, -4.61833026634844152345304095560e-8, 8.00253111512943601598732144340e-9, -1.36291114862793031395712122089e-9, 2.28570483090160869607683087722e-10, -3.78022521563251805044056974560e-11, 6.17253683874528285729910462130e-12, -9.96019290955316888445830597430e-13, 1.58953143706980770269506726000e-13, -2.51045971047162509999527428316e-14, 3.92607828989125810013581287560e-15, -6.07970619384160374392535453420e-16, 9.12600607264794717315507477670e-17 ], :sin => [ -0.3295190160663511504173, 0.0025374284671667991990, 0.0006261928782647355874, -4.6495547521854042157541e-06, -5.6917531549379706526677e-07, 3.7283335140973803627866e-09, 3.0267376484747473727186e-10, -1.7400875016436622322022e-12, -1.0554678305790849834462e-13, 5.3701981409132410797062e-16, 2.5984137983099020336115e-17, -1.1821555255364833468288e-19], } PARAMS = { :lopx => [20, -1, 1, 10], :lopxmx => [19, -1, 1, 9], :gstar_a => [29, -1, 1, 17], :gstar_b => [29, -1, 1, 18], :e11 => [18, -1, 1, 13], :e12 => [15, -1, 1, 10], :ae11 => [38, -1, 1, 20], :ae12 => [24, -1, 1, 15], :ae13 => [24, -1, 1, 15], :ae14 => [25, -1, 1, 13], :erfc_xlt1 => [19, -1, 1, 12], :erfc_x15 => [24, -1, 1, 16], :erfc_x510 => [19, -1, 1, 12], :sin => [11, -1, 1, 11] } def initialize(coefficients, expansion_order, lower_interval_point, upper_interval_point, single_precision_order) @c = coefficients.is_a?(Symbol) ? DATA[coefficients] : coefficients @order = expansion_order @lower_interval_point = lower_interval_point @upper_interval_point = upper_interval_point @single_precision_order = single_precision_order end #double * c; /* coefficients */ #int order; /* order of expansion */ #double a; /* lower interval point */ #double b; /* upper interval point */ #int order_sp; /* effective single precision order */ attr_reader :lower_interval_point, :upper_interval_point, :single_precision_order, :order, :c def a; @lower_interval_point; end def b; @upper_interval_point; end def order_sp; @single_precision_order; end def coefficients(idx); @c[idx]; end class << self # cheb_eval_e in specfunc/cheb_eval.c (gsl-1.9) def evaluate series, x, with_error = false cs = Math.const_get "#{series.to_s.upcase}_CS" raise(ArgumentError, "Unrecognized series #{series.to_s}") if cs.nil? d = 0.0 dd = 0.0 y = (2*x - cs.a - cs.b).quo(cs.b - cs.a) y2 = 2*y e = 0.0 cs.order.downto(1) do |j| temp = d d = y2*d - dd + cs.c[j] e += (y2*temp).abs + dd.abs + cs.c[j].abs dd = temp end begin temp = d d = y*d - dd + 0.5 * cs.c[0] e += (y*temp).abs + dd.abs + 0.5*cs.c[0].abs end with_error ? [d, Float::EPSILON*e + (cs.c[cs.order])] : d end end end ChebyshevSeries::DATA.keys.each do |series| Math.const_set "#{series.to_s.upcase}_CS", ChebyshevSeries.new(series, *(ChebyshevSeries::PARAMS[series])) end end enddistribution-0.7.0/lib/distribution/math_extension/erfc.rb0000644000175000017500000000451312061653751023402 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Derived from GSL-1.9 source files in the specfunc/ dir. module Distribution module MathExtension # Error function from GSL-1.9, with epsilon information. Access it using Math.erfc_e module Erfc P = [ 2.97886562639399288862, 7.409740605964741794425, 6.1602098531096305440906, 5.019049726784267463450058, 1.275366644729965952479585264, 0.5641895835477550741253201704 ] Q = [ 3.3690752069827527677, 9.608965327192787870698, 17.08144074746600431571095, 12.0489519278551290360340491, 9.396034016235054150430579648, 2.260528520767326969591866945, 1.0 ] class << self # Estimates erfc(x) valid for 8 < x < 100 # erfc8_sum from GSL-1.9 def erfc8_sum(x) num = P[5] 4.downto(0) { |i| num = x*num + P[i] } den = Q[6] 5.downto(0) { |i| den = x*den + Q[i] } num / den end def erfc8(x) erfc8_sum(x) * Math.exp(-x*x) end # gsl_sf_erfc_e def evaluate(x, with_error = false) ax = x.abs e = nil if ax <= 1.0 t = 2*ax-1 e = ChebyshevSeries.evaluate(:erfc_xlt1, t, with_error) elsif ax <= 5.0 ex2 = Math.exp(-x*x) t = (ax-3).quo(2) e = ChebyshevSeries.evaluate(:erfc_x15, t, with_error) if with_error e[0] *= ex2 e[1] = ex2 * (e[1] + 2*x.abs*Float::EPSILON) else e *= ex2 end elsif ax < 10.0 exterm = Math.exp(-x*x) / ax t = (2*ax-15).quo(5) e = ChebyshevSeries.evaluate(:erfc_x510, t, with_error) if with_error e[0] *= exterm e[1] = exterm * (e[1] + 2*x.abs*Float::EPSILON + Float::EPSILON) else e *= exterm end else e8 = erfc8(ax) e = with_error ? [e8, (x*x + 1) * Float::EPSILON * e8.abs] : e8 end result = x < 0 ? 2 - (with_error ? e.first : e) : (with_error ? e.first : e) with_error ? [result, e.last + 2*Float::EPSILON*result.abs] : result end end end end enddistribution-0.7.0/lib/distribution/math_extension/incomplete_beta.rb0000644000175000017500000001671712061653751025626 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Derived from GSL-1.9 source files in the specfunc/ dir. module Distribution module MathExtension module Beta class << self # Based on gsl_sf_lnbeta_e and gsl_sf_lnbeta_sgn_e # Returns result and sign in an array. If with_error is specified, also returns the error. def log_beta(x,y, with_error=false) sign = nil raise(ArgumentError, "x and y must be nonzero") if x == 0.0 || y == 0.0 raise(ArgumentError, "not defined for negative integers") if [x,y].any? { |v| (v.is_a?(Fixnum) && v < 0) } # See if we can handle the positive case with min/max < 0.2 if x > 0 && y > 0 min, max = [x,y].minmax ratio = min.quo(max) if ratio < 0.2 gsx = Gammastar.evaluate(x, with_error) gsy = Gammastar.evaluate(y, with_error) gsxy = Gammastar.evaluate(x+y, with_error) lnopr = Log::log_1plusx(ratio, with_error) gsx, gsx_err, gsy, gsy_err, gsxy, gsxy_err, lnopr, lnopr_err = [gsx,gsy,gsxy,lnopr].flatten if with_error lnpre = Math.log((gsx*gsy).quo(gsxy) * Math::SQRT2 * Math::SQRTPI) lnpre_err = gsx_err.quo(gsx) + gsy_err(gsy) + gsxy_err.quo(gsxy) if with_error t1 = min * Math.log(ratio) t2 = 0.5 * Math.log(min) t3 = (x+y-0.5)*lnopr lnpow = t1 - t2 - t3 lnpow_err = Float::EPSILON * (t1.abs + t2.abs + t3.abs) + (x+y-0.5).abs * lnopr_err if with_error result = lnpre + lnpow error = lnpre_err + lnpow_err + 2.0*Float::EPSILON*result.abs if with_error return with_error ? [result, 1.0, error] : [result, 1.0] end end # General case: fallback lgx, sgx = Math.lgamma(x) lgy, sgy = Math.lgamma(y) lgxy, sgxy = Math.lgamma(x+y) sgn = sgx * sgy * sgxy raise("Domain error: sign is -") if sgn == -1 result = lgx + lgy - lgxy if with_error lgx_err, lgy_err, lgxy_err = begin STDERR.puts("Warning: Error is unknown for Math::lgamma, guessing.") [Math::EPSILON, Math::EPSILON, Math::EPSILON] end error = lgx_err + lgy_err + lgxy_err + Float::EPSILON*(lgx.abs+lgy.abs+lgxy.abs) + 2.0*(Float::EPSILON)*result.abs return [result, sgn, error] else return [result, sgn] end end end end # Calculate regularized incomplete beta function module IncompleteBeta MAX_ITER = 512 CUTOFF = 2.0 * Float::MIN class << self # Evaluate aa * beta_inc(a,b,x) + yy # # No error mode available. # # From GSL-1.9: cdf/beta_inc.c, beta_inc_AXPY def axpy(aa,yy,a,b,x) return aa*0 + yy if x == 0.0 return aa*1 + yy if x == 1.0 ln_beta = Math.logbeta(a, b) ln_pre = -ln_beta + a * Math.log(x) + b * Math::Log.log1p(-x) prefactor = Math.exp(ln_pre) if x < (a+1).quo(a+b+2) # Apply continued fraction directly epsabs = yy.quo((aa * prefactor).quo(a)).abs * Float::EPSILON cf = continued_fraction(a, b, x, epsabs) return aa * (prefactor * cf).quo(a) + yy else # Apply continued fraction after hypergeometric transformation epsabs = (aa + yy).quo( (aa*prefactor).quo(b) ) * Float::EPSILON cf = continued_fraction(b, a, 1-x, epsabs) term = (prefactor * cf).quo(b) return aa == -yy ? -aa*term : aa*(1-term)+yy end end # Evaluate the incomplete beta function # gsl_sf_beta_inc_e def evaluate(a,b,x,with_error=false) raise(ArgumentError, "Domain error: a(#{a}), b(#{b}) must be positive; x(#{x}) must be between 0 and 1, inclusive") if a <= 0 || b <= 0 || x < 0 || x > 1 if x == 0 return with_error ? [0.0,0.0] : 0.0 elsif x == 1 return with_error ? [1.0,0.0] : 1.0 else ln_beta = Beta.log_beta(a,b, with_error) ln_1mx = Log.log_1plusx(-x, with_error) ln_x = Math.log(x) ln_beta, ln_beta_err, ln_1mx, ln_1mx_err, ln_x_err = begin #STDERR.puts("Warning: Error is unknown for Math::log, guessing.") [ln_beta,ln_1mx,Float::EPSILON].flatten end ln_pre = -ln_beta + a*ln_x + b*ln_1mx ln_pre_err = ln_beta_err + (a*ln_x_err).abs + (b*ln_1mx_err).abs if with_error prefactor, prefactor_err = begin if with_error exp_err(ln_pre, ln_pre_err) else [Math.exp(ln_pre), nil] end end if x < (a+1).quo(a+b+2) # Apply continued fraction directly cf = continued_fraction(a,b,x, nil, with_error) cf,cf_err = cf if with_error result = (prefactor * cf).quo(a) return with_error ? [result, ((prefactor_err*cf).abs + (prefactor*cf_err).abs).quo(a)] : result else # Apply continued fraction after hypergeometric transformation cf = continued_fraction(b, a, 1-x, nil) cf,cf_err = cf if with_error term = (prefactor * cf).quo(b) result = 1 - term return with_error ? [result, (prefactor_err*cf).quo(b) + (prefactor*cf_err).quo(b) + 2.0*Float::EPSILON*(1+term.abs)] : result end end end def continued_fraction_cutoff(epsabs) return CUTOFF if epsabs.nil? 0.0/0 # NaN end # Continued fraction calculation of incomplete beta # beta_cont_frac from GSL-1.9 # # If epsabs is set, will execute the version of the GSL function in the cdf folder. Otherwise, does the # basic one in specfunc. def continued_fraction(a,b,x,epsabs=nil,with_error=false) num_term = 1 den_term = 1 - (a+b)*x.quo(a+1) k = 0 den_term = continued_fraction_cutoff(epsabs) if den_term.abs < CUTOFF den_term = 1.quo(den_term) cf = den_term 1.upto(MAX_ITER) do |k| coeff = k *(b-k)*x.quo(((a-1)+2*k)*(a+2*k)) # coefficient for step 1 delta_frac = nil 2.times do den_term = 1 + coeff*den_term num_term = 1 + coeff.quo(num_term) den_term = continued_fraction_cutoff(epsabs) if den_term.abs < CUTOFF num_term = continued_fraction_cutoff(epsabs) if num_term.abs < CUTOFF den_term = 1.quo(den_term) delta_frac = den_term * num_term cf *= delta_frac coeff = -(a+k)*(a+b+k)*x.quo((a+2*k)*(a+2*k+1)) # coefficient for step 2 end break if (delta_frac-1).abs < 2.0*Float::EPSILON break if !epsabs.nil? && (cf * (delta_frac-1).abs < epsabs) end if k > MAX_ITER raise("Exceeded maximum number of iterations") if epsabs.nil? return with_error ? [0.0/0, 0] : 0.0/0 # NaN if epsabs is set end with_error ? [cf, k * 4 * Float::EPSILON * cf.abs] : cf end end end end enddistribution-0.7.0/lib/distribution/poisson.rb0000644000175000017500000000222212061653751021123 0ustar boutilboutilrequire 'distribution/poisson/ruby' require 'distribution/poisson/gsl' require 'distribution/poisson/java' module Distribution # From Wikipedia # In probability theory and statistics, the Poisson distribution is # a discrete probability distribution that expresses the probability of # a number of events occurring in a fixed period of time if these # events occur with a known average rate and independently of the time # since the last event. module Poisson SHORTHAND='pois' extend Distributable create_distribution_methods ## # :singleton-method: pdf(k , l) # PDF for Poisson distribution, # [+k+] is the number of occurrences of an event # [+l+] is a positive real number, equal to the expected number of occurrences that occur during the given interval. ## # :singleton-method: cdf(k , l) # CDF for Poisson distribution # [+k+] is the number of occurrences of an event # [+l+] is a positive real number, equal to the expected number of occurrences that occur during the given interval. # TODO: Not implemented yet # :singleton-method: p_value(pr , l) end end distribution-0.7.0/lib/distribution/lognormal.rb0000644000175000017500000000246312061653751021432 0ustar boutilboutilrequire 'distribution/lognormal/gsl' require 'distribution/lognormal/ruby' module Distribution # From Wikipedia: # In probability theory, a log-normal distribution is a probability # distribution of a random variable whose logarithm is normally # distributed. If X is a random variable with a normal distribution, then # Y = exp(X) has a log-normal distribution; likewise, if Y is # log-normally distributed, then X = log(Y) is normally distributed. (This # is true regardless of the base of the logarithmic function: if loga(Y) is # normally distributed, then so is logb(Y), for any two positive numbers # a, b т‰  1.) # # This module calculate the pdf, cdf and inverse cdf for Beta Distribution. # module LogNormal extend Distributable SHORTHAND='lognormal' create_distribution_methods ## # :singleton-method: pdf(x,u,s) # Returns PDF of of Lognormal distribution with parameters u (position) and # s (deviation) ## # :singleton-method: cdf(x,u,s) # Returns the CDF of Lognormal distribution of x with parameters # u (position) and s(deviation) ## # :singleton-method: p_value(pr,u,s) # Return the quantile of the corresponding integral +pr+ # on a lognormal distribution's cdf with parameters z and s end end distribution-0.7.0/lib/distribution/logistic.rb0000644000175000017500000000240512061653751021251 0ustar boutilboutilrequire 'distribution/logistic/ruby' #require 'distribution/logistic/gsl' #require 'distribution/logistic/java' module Distribution # From Wikipedia: # In probability theory and statistics, the logistic distribution is a continuous probability distribution. Its cumulative distribution function is the logistic function, which appears in logistic regression and feedforward neural networks. It resembles the normal distribution in shape but has heavier tails (higher kurtosis). module Logistic SHORTHAND='logis' extend Distributable create_distribution_methods ## # :singleton-method: rng(u,s) # Returns a proc, which returns a different logistic # variate each time is called # * u: mean # * s: variance related parameter ## # :singleton-method: pdf(x , u,s) # Returns the pdf for logistic distribution (f(x,u,s)) # * u: mean # * s: variance related parameter ## # :singleton-method: cdf(x,u,s) # Returns the cdf for logistic distribution (F(x,u,s)) # * u: mean # * s: variance related parameter ## # :singleton-method: p_value(pr , u,s) # Returns the inverse cdf for logistic distribution # (F^-1(pr,u,s)) # * u: mean # * s: variance related parameter end end distribution-0.7.0/lib/distribution/beta.rb0000644000175000017500000000176112061653751020353 0ustar boutilboutilrequire 'distribution/beta/ruby' require 'distribution/beta/gsl' # no statistics2 functions for beta. require 'distribution/beta/java' module Distribution # From Wikipedia: # In probability theory and statistics, the beta distribution # is a family of continuous probability distributions defined # on the interval (0, 1) parameterized by two positive shape # parameters, typically denoted by alpha and beta. # This module calculate cdf and inverse cdf for Beta Distribution. # module Beta extend Distributable SHORTHAND='beta' create_distribution_methods ## # :singleton-method: pdf(x,a,b) # Returns PDF of of Beta distribution with parameters a and b ## # :singleton-method: cdf(x,a,b) # Returns the integral of Beta distribution with parameters a and b ## # :singleton-method: p_value(qn,a,b) # Return the quantile of the corresponding integral +qn+ # on a beta distribution's cdf with parameters a and b end end distribution-0.7.0/lib/distribution/binomial/0000755000175000017500000000000012061653751020700 5ustar boutilboutildistribution-0.7.0/lib/distribution/binomial/ruby.rb0000644000175000017500000000141412061653751022206 0ustar boutilboutilmodule Distribution module Binomial module Ruby_ class << self def pdf(k,n,pr) raise "k>n" if k>n Math.binomial_coefficient(n,k)*(pr**k)*(1-pr)**(n-k) end # TODO: Use exact_regularized_beta for # small values and regularized_beta for bigger ones. def cdf(k,n,pr) #(0..x.floor).inject(0) {|ac,i| ac+pdf(i,n,pr)} Math.regularized_beta(1-pr,n - k,k+1) end def exact_cdf(k,n,pr) (0..k).inject(0) {|ac,i| ac+pdf(i,n,pr)} end def p_value(prob,n,pr) ac=0 (0..n).each do |i| ac+=pdf(i,n,pr) return i if prob<=ac end end alias :exact_pdf :pdf end end end end distribution-0.7.0/lib/distribution/binomial/gsl.rb0000644000175000017500000000040312061653751022007 0ustar boutilboutilmodule Distribution module Binomial module GSL_ class << self def pdf(k,n,prob) GSL::Ran.binomial_pdf(k,prob,n) end def cdf(k,n,prob) GSL::Cdf.binomial_P(k,prob,n) end end end end enddistribution-0.7.0/lib/distribution/binomial/java.rb0000644000175000017500000000016112061653751022144 0ustar boutilboutilmodule Distribution module Binomial # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/bivariatenormal.rb0000644000175000017500000000142212061653751022611 0ustar boutilboutilrequire 'distribution/bivariatenormal/ruby' require 'distribution/bivariatenormal/gsl' require 'distribution/bivariatenormal/java' module Distribution # Calculate pdf and cdf for bivariate normal distribution. # # Pdf if easy to calculate, but CDF is not trivial. Several papers # describe methods to calculate the integral. module BivariateNormal SHORTHAND='bnor' extend Distributable create_distribution_methods ## # :singleton-method: pdf(k,n,prob) # Probability density function for exactly +k+ successes in +n+ trials # with success probability +prob+ # ## # :singleton-method: cdf(k,n,prob) # Cumulative density function for +k+ or less successes in +n+ trials # with success probability +prob+ end end distribution-0.7.0/lib/distribution/lognormal/0000755000175000017500000000000012061653751021100 5ustar boutilboutildistribution-0.7.0/lib/distribution/lognormal/ruby.rb0000644000175000017500000000063612061653751022413 0ustar boutilboutilmodule Distribution module LogNormal module Ruby_ class << self def pdf(x,u,s) raise "x should be > 0 " if x < 0 (1.0/(x*s*Math.sqrt(2*Math::PI)))*Math.exp(-((Math.log(x)-u)**2 / (2*s**2))) end #def p_value(pr,u,s) #end def cdf(x,u,s) Distribution::Normal.cdf((Math.log(x)-u) / s) end end end end end distribution-0.7.0/lib/distribution/lognormal/gsl.rb0000644000175000017500000000060512061653751022213 0ustar boutilboutilmodule Distribution module LogNormal module GSL_ class << self def pdf(x,u,s) GSL::Ran::lognormal_pdf(x.to_f, u.to_f, s.to_f) end def p_value(pr,u,s) GSL::Cdf::lognormal_Pinv(pr.to_f, u.to_f, s.to_f) end def cdf(x,u,s) GSL::Cdf::lognormal_P(x.to_f, u.to_f, s.to_f) end end end end end distribution-0.7.0/lib/distribution/f/0000755000175000017500000000000012061653751017333 5ustar boutilboutildistribution-0.7.0/lib/distribution/f/ruby.rb0000644000175000017500000000510112061653751020636 0ustar boutilboutilmodule Distribution module F module Ruby_ class << self def c_pdf(f,df) Distribution::ChiSquare.pdf(f,df) end def pdf(x,d1,d2) Math.sqrt(((d1*x)**d1*(d2**d2)).quo((d1*x+d2)**(d1+d2))).quo( x*Math.beta(d1/2.0, d2/2.0)) end # F-distribution ([1]) # Integral over [x, \infty) def q_f(df1, df2, f) if (f <= 0.0) then return 1.0; end if (df1 % 2 != 0 && df2 % 2 == 0) return 1.0 - q_f(df2, df1, 1.0 / f) end cos2 = 1.0 / (1.0 + df1.to_f * f / df2.to_f) sin2 = 1.0 - cos2 if (df1 % 2 == 0) prob = cos2 ** (df2.to_f / 2.0) temp = prob i = 2 while i < df1 temp *= (df2.to_f + i - 2) * sin2 / i prob += temp i += 2 end return prob end prob = Math.atan(Math.sqrt(df2.to_f / (df1.to_f * f))) temp = Math.sqrt(sin2 * cos2) i = 3 while i <= df1 prob += temp temp *= (i - 1).to_f * sin2 / i.to_f; i += 2.0 end temp *= df1.to_f i = 3 while i <= df2 prob -= temp temp *= (df1.to_f + i - 2) * cos2 / i.to_f i += 2 end prob * 2.0 / Math::PI end # inverse of F-distribution ([2]) def pfsub(x, y, z) (Math.sqrt(z) - y) / x / 2.0 end # Inverse CDF # [x, \infty) def pf(q, n1, n2) if(q < 0.0 || q > 1.0 || n1 < 1 || n2 < 1) $stderr.printf("Error : Illegal parameter in pf()!\n") return 0.0 end if n1 <= 240 || n2 <= 240 eps = 1.0e-5 if(n2 == 1) then eps = 1.0e-4 end fw = 0.0 s = 1000.0 loop do fw += s if s <= eps then return fw end if (qe = q_f(n1, n2, fw) - q) == 0.0 then return fw end if qe < 0.0 fw -= s s /= 10.0 #/ end end end eps = 1.0e-6 qn = q if q < 0.5 then qn = 1.0 - q u = pnorm(qn) w1 = 2.0 / n1 / 9.0 w2 = 2.0 / n2 / 9.0 w3 = 1.0 - w1 w4 = 1.0 - w2 u2 = u * u a = w4 * w4 - u2 * w2 b = -2. * w3 * w4 c = w3 * w3 - u2 * w1 d = b * b - 4 * a * c if(d < 0.0) fw = pfsub(a, b, 0.0) else if(a.abs > eps) fw = pfsub(a, b, d) else if(b.abs > eps) then return -c / b end fw = pfsub(a, b, 0.0) end end fw * fw * fw end end # F-distribution interface def cdf(f,n1, n2) 1.0 - q_f(n1, n2, f) end def p_value(y, n1, n2) pf(1.0 - y, n1, n2) end end end end end distribution-0.7.0/lib/distribution/f/statistics2.rb0000644000175000017500000000123112061653751022131 0ustar boutilboutilmodule Distribution module F module Statistics2_ class << self # Return the P-value of the corresponding integral with # k degrees of freedom # # Distribution::F.p_value(0.95,1,2) # Statistics2 have some problem with extreme values def p_value(pr,k1,k2) Statistics2.pfdist(k1,k2, pr) end # F cumulative distribution function (cdf). # # Returns the integral of F-distribution # with k1 and k2 degrees of freedom # over [0, x]. # Distribution::F.cdf(20,3,2) # def cdf(x, k1, k2) Statistics2.fdist(k1, k2,x) end end end end end distribution-0.7.0/lib/distribution/f/gsl.rb0000644000175000017500000000125612061653751020451 0ustar boutilboutilmodule Distribution module F module GSL_ class << self def pdf(x,k1,k2) GSL::Ran.fdist_pdf(x.to_f,k1,k2) end # Return the P-value of the corresponding integral with # k degrees of freedom # # Distribution::F.p_value(0.95,1,2) def p_value(pr,k1,k2) GSL::Cdf.fdist_Pinv(pr.to_f,k1,k2) end # F cumulative distribution function (cdf). # # Returns the integral of F-distribution # with k1 and k2 degrees of freedom # over [0, x]. # Distribution::F.cdf(20,3,2) # def cdf(x, k1, k2) GSL::Cdf.fdist_P(x.to_f.to_f,k1,k2) end end end end end distribution-0.7.0/lib/distribution/f/java.rb0000644000175000017500000000015212061653751020577 0ustar boutilboutilmodule Distribution module F # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/logistic/0000755000175000017500000000000012061653751020723 5ustar boutilboutildistribution-0.7.0/lib/distribution/logistic/ruby.rb0000644000175000017500000000065212061653751022234 0ustar boutilboutilmodule Distribution module Logistic module Ruby_ class << self def rng(u,s) lambda {p_value(rand(),u,s)} end def pdf(x,u,s ) (Math.exp(-(x-u) / s)) / (s*(1+Math.exp(-(x-u) / s)**2)) end def cdf(x,u,s ) 1/(1+Math.exp(-(x-u) / s)) end def p_value(pr,u,s ) u+s*Math.log(pr/(1-pr)) end end end end end distribution-0.7.0/lib/distribution/normal/0000755000175000017500000000000012061653751020376 5ustar boutilboutildistribution-0.7.0/lib/distribution/normal/ruby.rb0000644000175000017500000000521012061653751021702 0ustar boutilboutilmodule Distribution module Normal module Ruby_ class << self # random number within a gaussian distribution X ~ N(0,1) def rngu rng(0,1,nil) end # Return a proc which return a random number within a # gaussian distribution X ~ N(+mean+,+sigma+^2) # +seed+ feed the # == Reference: # * http://www.taygeta.com/random/gaussian.html def rng(mean=0,sigma=1,seed=nil) returned,y1,y2=0,0,0 lambda { if returned==0 begin x1 = 2.0 * rand - 1.0 x2 = 2.0 * rand - 1.0 w = x1 * x1 + x2 * x2 end while ( w >= 1.0 ) w = Math::sqrt( (-2.0 * Math::log( w ) ) / w ) y1 = x1 * w y2 = x2 * w returned=1 y1*sigma + mean else returned=0 y2 * sigma + mean end } end # Return the inverse CDF or P-value of the corresponding integral def p_value(qn) b = [1.570796288, 0.03706987906, -0.8364353589e-3, -0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5, -0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8, 0.3657763036e-10, 0.6936233982e-12] if(qn < 0.0 || 1.0 < qn) $stderr.printf("Error : qn <= 0 or qn >= 1 in pnorm()!\n") return 0.0; end qn == 0.5 and return 0.0 w1 = qn qn > 0.5 and w1 = 1.0 - w1 w3 = -Math.log(4.0 * w1 * (1.0 - w1)) w1 = b[0] 1.upto 10 do |i| w1 += b[i] * w3**i; end qn > 0.5 and return Math.sqrt(w1 * w3) -Math.sqrt(w1 * w3) end # Normal cumulative distribution function (cdf). # # Returns the integral of normal distribution # over (-Infty, z]. # def cdf(z) 0.0 if z < -12 1.0 if z > 12 0.5 if z == 0.0 if z > 0.0 e = true else e = false z = -z end z = z.to_f z2 = z * z t = q = z * Math.exp(-0.5 * z2) / SQ2PI 3.step(199, 2) do |i| prev = q t *= z2 / i q += t if q <= prev return(e ? 0.5 + q : 0.5 - q) end end e ? 1.0 : 0.0 end # Normal probability density function (pdf) # With x=0 and sigma=1 def pdf(x) (1.0 / SQ2PI)*Math::exp(-(x**2/2.0)) end end end end end distribution-0.7.0/lib/distribution/normal/statistics2.rb0000644000175000017500000000037012061653751023177 0ustar boutilboutilmodule Distribution module Normal module Statistics2_ class << self def cdf(x) Statistics2.normaldist(x) end def p_value(pr) Statistics2.pnormaldist(pr) end end end end end distribution-0.7.0/lib/distribution/normal/gsl.rb0000644000175000017500000000102712061653751021510 0ustar boutilboutilmodule Distribution module Normal module GSL_ class << self def rng(mean=0,sigma=1,seed=nil) seed||=rand(10e8) rng=GSL::Rng.alloc(GSL::Rng::MT19937,seed) lambda { mean+rng.gaussian(sigma)} end def cdf(x) # :nodoc: GSL::Cdf::ugaussian_P(x) end def pdf(x) # :nodoc: GSL::Ran::gaussian_pdf(x) end def p_value(qn) GSL::Cdf::ugaussian_Pinv(qn) end def gsl end end end end end distribution-0.7.0/lib/distribution/normal/java.rb0000644000175000017500000000163712061653751021653 0ustar boutilboutilmodule Distribution module Normal # TODO module Java_ class << self #== # Generate random variables from the provided distribution def rng(mean=0,sigma=1,seed=nil) dist = NormalDistributionImpl.new(mean, sigma) lambda { dist.sample } end #== # Get the inverse cumulative density function (p-value) for qn def p_value(qn) dist = NormalDistributionImpl.new dist.inverseCumulativeProbability(qn) end #== # Return the cumulative density function at x def cdf(x) dist = NormalDistributionImpl.new dist.cumulativeProbability(x) end #== # Return the probability density function at x def pdf(x) dist = NormalDistributionImpl.new dist.density(x) end end end end enddistribution-0.7.0/lib/distribution/exponential/0000755000175000017500000000000012061653751021434 5ustar boutilboutildistribution-0.7.0/lib/distribution/exponential/ruby.rb0000644000175000017500000000061612061653751022745 0ustar boutilboutilmodule Distribution module Exponential module Ruby_ class << self def rng(l) lambda {p_value(rand(),l)} end def pdf(x,l) return 0 if x<0 l*Math.exp(-l*x) end def cdf(x,l) return 0 if x<0 1-Math.exp(-l*x) end def p_value(pr,l) (-Math.log(1-pr)).quo(l) end end end end end distribution-0.7.0/lib/distribution/exponential/gsl.rb0000644000175000017500000000062112061653751022545 0ustar boutilboutilmodule Distribution module Exponential module GSL_ class << self def pdf(x,l) return 0 if x<0 GSL::Ran.exponential_pdf(x,1/l.to_f) end def cdf(x,l) return 0 if x<0 GSL::Cdf.exponential_P(x,1/l.to_f) end def p_value(pr,l) GSL::Cdf.exponential_Pinv(pr,1/l.to_f) end end end end enddistribution-0.7.0/lib/distribution/t.rb0000644000175000017500000000151212061653751017675 0ustar boutilboutilrequire 'distribution/t/ruby' require 'distribution/t/gsl' # Removed statistics2 support for t, because # can't calculate correctly cdf for rational d.f # require 'distribution/t/statistics2' require 'distribution/t/java' module Distribution # Calculate statisticals for T Distribution. module T SHORTHAND='tdist' extend Distributable create_distribution_methods ## # :singleton-method: pdf(x,k) # Returns the integral of T distribution # with +k+ degrees of freedom over [0, +x+] ## # :singleton-method: p_value(qn, k) # Return the P-value of the corresponding integral +qn+ with # +k+ degrees of freedom ## # :singleton-method: cdf(x,k) # Returns the integral of T distribution # with +k+ degrees of freedom over [0, +x+] end end distribution-0.7.0/lib/distribution/chisquare/0000755000175000017500000000000012061653751021072 5ustar boutilboutildistribution-0.7.0/lib/distribution/chisquare/ruby.rb0000644000175000017500000000376312061653751022411 0ustar boutilboutilmodule Distribution module ChiSquare module Ruby_ class << self include Math def pdf(x,n) if n == 1 1.0/Math.sqrt(2 * Math::PI * x) * Math::E**(-x/2.0) elsif n == 2 0.5 * Math::E**(-x/2.0) else n = n.to_f n2 = n/2 x = x.to_f 1.0 / 2**n2 / gamma(n2) * x**(n2 - 1.0) * Math.exp(-x/2.0) end end # CDF Inverse over [x, \infty) # Pr([x, \infty)) = y -> x def pchi2(n, y) if n == 1 w = Distribution::Normal.p_value(1 - y/2) # = p1.0-Distribution::Normal.cdf(y/2) w * w elsif n == 2 # v = (1.0 / y - 1.0) / 33.0 # newton_a(y, v) {|x| [q_chi2(n, x), -chi2dens(n, x)] } -2.0 * Math.log(y) else eps = 1.0e-5 v = 0.0 s = 10.0 loop do v += s if s <= eps then break end if (qe = q_chi2(n, v) - y) == 0.0 then break end if qe < 0.0 v -= s s /= 10.0 #/ end end v end end def p_value(pr,k) pchi2(k, 1.0-pr) end def cdf(x,k) 1.0-q_chi2(k,x) end # chi-square distribution ([1]) # Integral over [x, \infty) def q_chi2(df, chi2) chi2 = chi2.to_f if (df & 1) != 0 chi = Math.sqrt(chi2) if (df == 1) then return 2 * (1.0-Distribution::Normal.cdf(chi)); end s = t = chi * Math.exp(-0.5 * chi2) / SQ2PI k = 3 while k < df t *= chi2 / k; s += t; k += 2 end 2 * (1.0-(Distribution::Normal.cdf(chi)) + s) else s = t = Math.exp(-0.5 * chi2) k = 2 while k < df t *= chi2 / k; s += t; k += 2 end s end end end end end end distribution-0.7.0/lib/distribution/chisquare/statistics2.rb0000644000175000017500000000101312061653751023666 0ustar boutilboutilmodule Distribution module ChiSquare module Statistics2_ class << self # Return the P-value of the corresponding integral with # k degrees of freedom def p_value(pr,k) Statistics2.pchi2X_(k.to_i, pr) end # Chi-square cumulative distribution function (cdf). # # Returns the integral of Chi-squared distribution # with k degrees of freedom over [0, x] # def cdf(x, k) Statistics2.chi2dist(k.to_i,x) end end end end end distribution-0.7.0/lib/distribution/chisquare/gsl.rb0000644000175000017500000000120312061653751022200 0ustar boutilboutilmodule Distribution module ChiSquare module GSL_ class << self def rng(k,seed=nil) end def pdf(x,k) GSL::Ran::chisq_pdf(x.to_f,k.to_i) end # Return the P-value of the corresponding integral with # k degrees of freedom def p_value(pr,k) GSL::Cdf::chisq_Pinv(pr.to_f,k.to_i) end # Chi-square cumulative distribution function (cdf). # # Returns the integral of Chi-squared distribution # with k degrees of freedom over [0, x] # def cdf(x, k) GSL::Cdf::chisq_P(x.to_f,k.to_i) end end end end end distribution-0.7.0/lib/distribution/chisquare/java.rb0000644000175000017500000000016212061653751022337 0ustar boutilboutilmodule Distribution module ChiSquare # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/normalmultivariate.rb0000644000175000017500000000431312061653751023353 0ustar boutilboutilmodule 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: raise "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 {|i| d[i]=0.0 if a[i].nil? e[i]=1.0 if b[i].nil? } 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 if a[i]!=nil d[i]=uPhi((a[i]-sumc).quo(c[i-1,i-1])) end # puts "sumc:#{sumc}" if 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=varsum+f[m]**2 n+=1 error=alpha*Math::sqrt((varsum.quo(n) - (intsum.quo(n))**2).quo(n)) end while(error>epsilon and n 0.95 # * Hull:: Port from a C++ code # * Jantaravareerat:: Iterative (slow and buggy) # module BivariateNormal module Ruby_ class << self SIDE=0.1 # :nodoc: LIMIT=5 # :nodoc: # Return the partial derivative of cdf over x, with y and rho constant # Reference: # * Tallis, 1962, p.346, cited by Olsson, 1979 def partial_derivative_cdf_x(x,y,rho) Distribution::Normal.pdf(x) * Distribution::Normal.cdf((y-rho*x).quo( Math::sqrt( 1 - rho**2 ))) end alias :pd_cdf_x :partial_derivative_cdf_x # Probability density function for a given x, y and rho value. # # Source: http://en.wikipedia.org/wiki/Multivariate_normal_distribution def pdf(x,y, rho, s1=1.0, s2=1.0) 1.quo(2 * Math::PI * s1 * s2 * Math::sqrt( 1 - rho**2 )) * (Math::exp(-(1.quo(2*(1-rho**2))) * ((x**2.quo(s1)) + (y**2.quo(s2)) - (2*rho*x*y).quo(s1*s2)))) end def f(x,y,aprime,bprime,rho) r=aprime*(2*x-aprime)+bprime*(2*y-bprime)+2*rho*(x-aprime)*(y-bprime) Math::exp(r) end # CDF for a given x, y and rho value. # Uses Genz algorithm (cdf_genz method). # def cdf(a,b,rho) cdf_genz(a,b,rho) end def sgn(x) if(x>=0) 1 else -1 end end # Normal cumulative distribution function (cdf) for a given x, y and rho. # Based on Hull (1993, cited by Arne, 2003) # # References: # * Arne, B.(2003). Financial Numerical Recipes in C ++. Available on http://finance.bi.no/~bernt/gcc_prog/recipes/recipes/node23.html def cdf_hull(a,b,rho) #puts "a:#{a} - b:#{b} - rho:#{rho}" if (a<=0 and b<=0 and rho<=0) # puts "ruta 1" aprime=a.quo(Math::sqrt(2.0*(1.0-rho**2))) bprime=b.quo(Math::sqrt(2.0*(1.0-rho**2))) aa=[0.3253030, 0.4211071, 0.1334425, 0.006374323] bb=[0.1337764, 0.6243247, 1.3425378, 2.2626645] sum=0 4.times do |i| 4.times do |j| sum+=aa[i]*aa[j] * f(bb[i], bb[j], aprime, bprime,rho) end end sum=sum*(Math::sqrt(1.0-rho**2).quo(Math::PI)) return sum elsif(a*b*rho<=0.0) #puts "ruta 2" if(a<=0 and b>=0 and rho>=0) return Distribution::Normal.cdf(a) - cdf(a,-b,-rho) elsif (a>=0.0 and b<=0.0 and rho>=0) return Distribution::Normal.cdf(b) - cdf(-a,b,-rho) elsif (a>=0.0 and b>=0.0 and rho<=0) return Distribution::Normal.cdf(a) + Distribution::Normal.cdf(b) - 1.0 + cdf(-a,-b,rho) end elsif (a*b*rho>=0.0) #puts "ruta 3" denum=Math::sqrt(a**2 - 2*rho*a*b + b**2) rho1=((rho*a-b)*sgn(a)).quo(denum) rho2=((rho*b-a)*sgn(b)).quo(denum) delta=(1.0-sgn(a)*sgn(b)).quo(4) #puts "#{rho1} - #{rho2}" return cdf(a, 0.0, rho1) + cdf(b, 0.0, rho2) - delta end raise "Should'nt be here! #{a} - #{b} #{rho}" end # CDF. Iterative method by Jantaravareerat (n/d) # # Reference: # * Jantaravareerat, M. & Thomopoulos, N. (n/d). Tables for standard bivariate normal distribution def cdf_jantaravareerat(x,y,rho,s1=1,s2=1) # Special cases return 1 if x>LIMIT and y>LIMIT return 0 if x<-LIMIT or y<-LIMIT return Distribution::Normal.cdf(y) if x>LIMIT return Distribution::Normal.cdf(x) if y>LIMIT #puts "x:#{x} - y:#{y}" x=-LIMIT if x<-LIMIT x=LIMIT if x>LIMIT y=-LIMIT if y<-LIMIT y=LIMIT if y>LIMIT x_squares=((LIMIT+x) / SIDE).to_i y_squares=((LIMIT+y) / SIDE).to_i sum=0 x_squares.times do |i| y_squares.times do |j| z1=-LIMIT+(i+1)*SIDE z2=-LIMIT+(j+1)*SIDE #puts " #{z1}-#{z2}" 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) sum+= (SIDE**2)*h # area end end sum end # Normal cumulative distribution function (cdf) for a given x, y and rho. # Ported from Fortran code by Alan Genz # # Original documentation # DOUBLE PRECISION FUNCTION BVND( DH, DK, R ) # A function for computing bivariate normal probabilities. # # Alan Genz # Department of Mathematics # Washington State University # Pullman, WA 99164-3113 # Email : alangenz_AT_wsu.edu # # This function is based on the method described by # Drezner, Z and G.O. Wesolowsky, (1989), # On the computation of the bivariate normal integral, # Journal of Statist. Comput. Simul. 35, pp. 101-107, # with major modifications for double precision, and for |R| close to 1. # # Original location: # * http://www.math.wsu.edu/faculty/genz/software/fort77/tvpack.f def cdf_genz(x,y,rho) dh=-x dk=-y r=rho twopi = 6.283185307179586 w=11.times.collect {[nil]*4}; x=11.times.collect {[nil]*4} data=[ 0.1713244923791705E+00, -0.9324695142031522E+00, 0.3607615730481384E+00, -0.6612093864662647E+00, 0.4679139345726904E+00, -0.2386191860831970E+00] (1..3).each {|i| w[i][1]=data[(i-1)*2] x[i][1]=data[(i-1)*2+1] } data=[ 0.4717533638651177E-01,-0.9815606342467191E+00, 0.1069393259953183E+00,-0.9041172563704750E+00, 0.1600783285433464E+00,-0.7699026741943050E+00, 0.2031674267230659E+00,-0.5873179542866171E+00, 0.2334925365383547E+00,-0.3678314989981802E+00, 0.2491470458134029E+00,-0.1252334085114692E+00] (1..6).each {|i| w[i][2]=data[(i-1)*2] x[i][2]=data[(i-1)*2+1] } data=[ 0.1761400713915212E-01,-0.9931285991850949E+00, 0.4060142980038694E-01,-0.9639719272779138E+00, 0.6267204833410906E-01,-0.9122344282513259E+00, 0.8327674157670475E-01,-0.8391169718222188E+00, 0.1019301198172404E+00,-0.7463319064601508E+00, 0.1181945319615184E+00,-0.6360536807265150E+00, 0.1316886384491766E+00,-0.5108670019508271E+00, 0.1420961093183821E+00,-0.3737060887154196E+00, 0.1491729864726037E+00,-0.2277858511416451E+00, 0.1527533871307259E+00,-0.7652652113349733E-01] (1..10).each {|i| w[i][3]=data[(i-1)*2] x[i][3]=data[(i-1)*2+1] } if ( r.abs < 0.3 ) ng = 1 lg = 3 elsif ( r.abs < 0.75 ) ng = 2 lg = 6 else ng = 3 lg = 10 end h = dh k = dk hk = h*k bvn = 0 if ( r.abs < 0.925 ) if ( r.abs > 0 ) hs = ( h*h + k*k ).quo(2) asr = Math::asin(r) (1..lg).each do |i| [-1,1].each do |is| sn = Math::sin(asr*(is* x[i][ng]+1).quo(2) ) bvn = bvn + w[i][ng] * Math::exp( ( sn*hk-hs ).quo( 1-sn*sn ) ) end # do end # do bvn = bvn*asr.quo( 2*twopi ) end # if bvn = bvn + Distribution::Normal.cdf(-h) * Distribution::Normal.cdf(-k) else # r.abs if ( r < 0 ) k = -k hk = -hk end if ( r.abs < 1 ) as = ( 1 - r )*( 1 + r ) a = Math::sqrt(as) bs = ( h - k )**2 c = ( 4 - hk ).quo(8) d = ( 12 - hk ).quo(16) asr = -( bs.quo(as) + hk ).quo(2) if ( asr > -100 ) bvn = a*Math::exp(asr) * ( 1 - c*( bs - as )*( 1 - d*bs.quo(5) ).quo(3) + c*d*as*as.quo(5) ) end if ( -hk < 100 ) b = Math::sqrt(bs) bvn = bvn - Math::exp( -hk.quo(2) ) * Math::sqrt(twopi)*Distribution::Normal.cdf(-b.quo(a))*b * ( 1 - c*bs*( 1 - d*bs.quo(5) ).quo(3) ) end a = a.quo(2) (1..lg).each do |i| [-1,1].each do |is| xs = (a*( is*x[i][ng] + 1 ) )**2 rs = Math::sqrt( 1 - xs ) asr = -( bs/xs + hk ).quo(2) if ( asr > -100 ) bvn = bvn + a*w[i][ng] * Math::exp( asr ) * ( Math::exp( -hk*( 1 - rs ).quo(2*( 1 + rs ) ) ) .quo(rs) - ( 1 + c*xs*( 1 + d*xs ) ) ) end end end bvn = -bvn/twopi end if ( r > 0 ) bvn = bvn + Distribution::Normal.cdf(-[h,k].max) else bvn = -bvn if ( k > h ) bvn = bvn + Distribution::Normal.cdf(k) - Distribution::Normal.cdf(h) end end end bvn end private :f, :sgn end end end end distribution-0.7.0/lib/distribution/bivariatenormal/statistics2.rb0000644000175000017500000000000012061653751025054 0ustar boutilboutildistribution-0.7.0/lib/distribution/bivariatenormal/gsl.rb0000644000175000017500000000033312061653751023376 0ustar boutilboutilmodule Distribution module BivariateNormal module GSL_ class < 1 gab = Math.lgamma(a+b).first ga = Math.lgamma(a).first gb = Math.lgamma(b).first if x == 0.0 || x == 1.0 Math.exp(gab - ga - gb) * x**(a-1) * (1-x)**(b-1) else Math.exp(gab - ga - gb + Math.log(x)*(a-1) + Math::Log.log1p(-x)*(b-1)) end end # Gamma cumulative distribution function # Translated from GSL-1.9: cdf/beta.c gsl_cdf_beta_P def cdf(x,a,b) return 0.0 if x <= 0.0 return 1.0 if x >= 1.0 Math::IncompleteBeta.axpy(1.0, 0.0, a,b,x) end end end end end distribution-0.7.0/lib/distribution/beta/gsl.rb0000644000175000017500000000117712061653751021141 0ustar boutilboutilmodule Distribution module Beta module GSL_ class << self def pdf(x,a,b) GSL::Ran::beta_pdf(x.to_f, a.to_f, b.to_f) end # Return the P-value of the corresponding integral with # k degrees of freedom def p_value(pr,a,b) GSL::Cdf::beta_Pinv(pr.to_f, a.to_f, b.to_f) end # Beta cumulative distribution function (cdf). # # Returns the integral of Beta distribution # with parameters +a+ and +b+ over [0, x] # def cdf(x,a,b) GSL::Cdf::beta_P(x.to_f, a.to_f, b.to_f) end end end end end distribution-0.7.0/lib/distribution/beta/java.rb0000644000175000017500000000015512061653751021270 0ustar boutilboutilmodule Distribution module Beta # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/hypergeometric/0000755000175000017500000000000012061653751022134 5ustar boutilboutildistribution-0.7.0/lib/distribution/hypergeometric/ruby.rb0000644000175000017500000000356512061653751023453 0ustar boutilboutil# Added by John O. Woods, SciRuby project. # Optimized by Claudio Bustos module Distribution module Hypergeometric module Ruby_ class << self def bc(n,k) Math.binomial_coefficient(n,k) end # Hypergeometric probability density function # # Probability p(+k+, +m+, +n+, +total+) of drawing sets of size +m+ and +n+ with an intersection of size +k+ # from a total pool of size +total+, without replacement. # # ==References # * http://www.gnu.org/software/gsl/manual/html_node/The-Hypergeometric-Distribution.html # * http://en.wikipedia.org/wiki/Hypergeometric_distribution def pdf(k, m, n, total) min_m_n=mmin_m_n or k=pr end end # Cumulative distribution function. # The probability of obtain, from a sample of # size +n+, +k+ or less elements # in a population size +total+ with +m+ interesting elements. # # Slow, but secure def cdf(k, m, n, total) raise "k>m" if k>m raise "k>n" if k>n # Store the den den=bc(total,n) (0..k).collect { |ki| pdf_with_den(ki,m,n,total,den) }.inject { |sum,v| sum+v} end alias :exact_pdf :pdf alias :exact_p_value :p_value alias :exact_cdf :cdf end end end enddistribution-0.7.0/lib/distribution/hypergeometric/gsl.rb0000644000175000017500000000062212061653751023246 0ustar boutilboutilmodule Distribution module Hypergeometric module GSL_ class << self def pdf(k, m, n, total) # :nodoc: GSL::Ran::hypergeometric_pdf(k, m, total-m, n) end # The GSL::Cdf function for hypergeometric # def cdf(k, m, n, total) # :nodoc: GSL::Cdf::hypergeometric_P(k, m, total-m, n) end end end end enddistribution-0.7.0/lib/distribution/hypergeometric/java.rb0000644000175000017500000000016712061653751023406 0ustar boutilboutilmodule Distribution module Hypergeometric # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/f.rb0000644000175000017500000000141512061653751017661 0ustar boutilboutilrequire 'distribution/f/ruby' require 'distribution/f/gsl' require 'distribution/f/statistics2' require 'distribution/f/java' module Distribution # Calculate cdf and inverse cdf for F Distribution. # module F SHORTHAND='fdist' extend Distributable create_distribution_methods ## # :singleton-method: pdf(x,k1,k2) # Returns the PDF of F distribution # with +k1+ and +k2+ degrees of freedom over [0, +x+] ## # :singleton-method: p_value(qn, k1, k2) # Return the P-value of the corresponding integral +qn+ with # +k1+ and +k2+ degrees of freedom ## # :singleton-method: cdf(x,k1,k2) # Returns the integral of F distribution # with +k1+ and +k2+ degrees of freedom over [0, +x+] end end distribution-0.7.0/lib/distribution/exponential.rb0000644000175000017500000000235712061653751021770 0ustar boutilboutilrequire 'distribution/exponential/ruby' require 'distribution/exponential/gsl' #require 'distribution/exponential/java' module Distribution # From Wikipedia: # In probability theory and statistics, the exponential distribution # (a.k.a. negative exponential distribution) is a family of continuous # probability distributions. It describes the time between events in a # Poisson process, i.e. a process in which events occur continuously # and independently at a constant average rate. # # Parameter +l+ is the rate parameter, the number of occurrences/unit time. module Exponential SHORTHAND='expo' extend Distributable create_distribution_methods ## # :singleton-method: rng(l) # Returns a lambda, which generates exponential variates # with +l+ as rate parameter ## # :singleton-method: pdf(x,l) # PDF of exponential distribution, with parameters +x+ and +l+. # +l+ is rate parameter ## # :singleton-method: cdf(x,l) # CDF of exponential distribution, with parameters +x+ and +l+. # +l+ is rate parameter ## # :singleton-method: p_value(pr,l) # Inverse CDF of exponential distribution, with parameters +pr+ and +l+. # +l+ is rate parameter end end distribution-0.7.0/lib/distribution/chisquare.rb0000644000175000017500000000142512061653751021421 0ustar boutilboutilrequire 'distribution/chisquare/ruby' require 'distribution/chisquare/gsl' require 'distribution/chisquare/statistics2' require 'distribution/chisquare/java' module Distribution # Calculate cdf and inverse cdf for Chi Square Distribution. # module ChiSquare extend Distributable SHORTHAND='chisq' create_distribution_methods ## # :singleton-method: pdf(x) # Returns PDF of of Chi-squared distribution # with +k+ degrees of freedom ## # :singleton-method: cdf(x,k) # Returns the integral of Chi-squared distribution # with +k+ degrees of freedom over [0, +x+] ## # :singleton-method: p_value(qn, k) # Return the P-value of the corresponding integral +qn+ with # +k+ degrees of freedom end end distribution-0.7.0/lib/distribution/gamma.rb0000644000175000017500000000175512061653751020525 0ustar boutilboutilrequire 'distribution/gamma/ruby' require 'distribution/gamma/gsl' # no statistics2 functions for gamma. require 'distribution/gamma/java' module Distribution # From Wikipedia: # The gamma distribution is a two-parameter family of # continuous probability distributions. It has a scale parameter a # and a shape parameter b. # # Calculate pdf, cdf and inverse cdf for Gamma Distribution. # module Gamma extend Distributable SHORTHAND='gamma' create_distribution_methods ## # :singleton-method: pdf(x,a,b) # Returns PDF of of Gamma distribution with +a+ as scale # parameter and +b+ as shape parameter ## # :singleton-method: cdf(x,a,b) # Returns the integral of Gamma distribution with +a+ as scale # parameter and +b+ as shape parameter ## # :singleton-method: p_value(qn,a,b) # Return the upper limit for the integral of a # gamma distribution which returns +qn+ # with scale +a+ and shape +b+ end end distribution-0.7.0/lib/distribution/gamma/0000755000175000017500000000000012061653751020170 5ustar boutilboutildistribution-0.7.0/lib/distribution/gamma/ruby.rb0000644000175000017500000000277612061653751021512 0ustar boutilboutil# Added by John O. Woods, SciRuby project. module Distribution module Gamma module Ruby_ class << self include Math # Gamma distribution probability density function # # If you're looking at Wikipedia's Gamma distribution page, the arguments for this pdf function correspond # as follows: # # * +x+: same # * +a+: alpha or k # + +b+: theta or 1/beta # # This is confusing! But we're trying to most closely mirror the GSL function for the gamma distribution # (see references). # # Adapted the function itself from GSL-1.9 in rng/gamma.c: gsl_ran_gamma_pdf # # ==References # * http://www.gnu.org/software/gsl/manual/html_node/The-Gamma-Distribution.html # * http://en.wikipedia.org/wiki/Gamma_distribution def pdf(x,a,b) return 0 if x < 0 if x == 0 return 1.quo(b) if a == 1 return 0 elsif a == 1 Math.exp(-x.quo(b)).quo(b) else Math.exp((a-1)*Math.log(x.quo(b)) - x.quo(b) - Math.lgamma(a).first).quo(b) end end # Gamma cumulative distribution function def cdf(x,a,b) return 0.0 if x <= 0.0 y = x.quo(b) return (1-Math::IncompleteGamma.q(a, y)) if y > a return (Math::IncompleteGamma.p(a, y)) end #def p_value(pr,a,b) # cdf(1.0-pr,a,b) #end end end end end distribution-0.7.0/lib/distribution/gamma/gsl.rb0000644000175000017500000000121612061653751021302 0ustar boutilboutilmodule Distribution module Gamma module GSL_ class << self def pdf(x,a,b) GSL::Ran::gamma_pdf(x.to_f, a.to_f, b.to_f) end # Return the P-value of the corresponding integral with # k degrees of freedom def p_value(pr,a,b) GSL::Cdf::gamma_Pinv(pr.to_f, a.to_f, b.to_f) end # Chi-square cumulative distribution function (cdf). # # Returns the integral of Chi-squared distribution # with k degrees of freedom over [0, x] # def cdf(x,a,b) GSL::Cdf::gamma_P(x.to_f, a.to_f, b.to_f) end end end end end distribution-0.7.0/lib/distribution/gamma/java.rb0000644000175000017500000000015612061653751021440 0ustar boutilboutilmodule Distribution module Gamma # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution/t/0000755000175000017500000000000012061653751017351 5ustar boutilboutildistribution-0.7.0/lib/distribution/t/ruby.rb0000644000175000017500000000537712061653751020673 0ustar boutilboutilmodule Distribution module T module Ruby_ class << self def pdf(t,v) ((Math.gamma((v+1) / 2.0)) / (Math.sqrt(v*Math::PI)*Math.gamma(v/2.0))) * ((1+(t**2 / v.to_f))**(-(v+1) / 2.0)) end # Returns the integral of t-distribution with n degrees of freedom over (-Infty, x]. def cdf(t, n) p_t(n, t) end # t-distribution ([1]) # (-\infty, x] def p_t(df, t) if df.to_i!=df x=(t+Math.sqrt(t**2+df)) / (2*Math.sqrt(t**2+df)) return Math.regularized_beta(x,df/2.0,df/2.0) end df=df.to_i c2 = df.to_f / (df + t * t); s = Math.sqrt(1.0 - c2) s = -s if t < 0.0 p = 0.0; i = df % 2 + 2 while i <= df p += s s *= (i - 1) * c2 / i i += 2 end if df.is_a? Float or df & 1 != 0 0.5+(p*Math.sqrt(c2)+Math.atan(t/Math.sqrt(df))) / Math::PI else (1.0 + p) / 2.0 end end # inverse of t-distribution ([2]) # (-\infty, -q/2] + [q/2, \infty) def ptsub(q, n) q = q.to_f if(n == 1 && 0.001 < q && q < 0.01) eps = 1.0e-4 elsif (n == 2 && q < 0.0001) eps = 1.0e-4 elsif (n == 1 && q < 0.001) eps = 1.0e-2 else eps = 1.0e-5 end s = 10000.0 w = 0.0 loop do w += s if(s <= eps) then return w end if((qe = 2.0 - p_t(n, w)*2.0 - q) == 0.0) then return w end if(qe < 0.0) w -= s s /= 10.0 #/ end end end def pt(q, n) q = q.to_f if(q < 1.0e-5 || q > 1.0 || n < 1) $stderr.printf("Error : Illigal parameter in pt()!\n") return 0.0 end if(n <= 5) then return ptsub(q, n) end if(q <= 5.0e-3 && n <= 13) then return ptsub(q, n) end f1 = 4.0 * (f = n.to_f) f5 = (f4 = (f3 = (f2 = f * f) * f) * f) * f f2 *= 96.0 f3 *= 384.0 f4 *= 92160.0 f5 *= 368640.0 u = Normal.p_value(1.0 - q / 2.0) w0 = (u2 = u * u) * u w1 = w0 * u2 w2 = w1 * u2 w3 = w2 * u2 w4 = w3 * u2 w = (w0 + u) / f1 w += (5.0 * w1 + 16.0 * w0 + 3.0 * u) / f2 w += (3.0 * w2 + 19.0 * w1 + 17.0 * w0 - 15.0 * u) / f3 w += (79.0 * w3 + 776.0 * w2 + 1482.0 * w1 - 1920.0 * w0 - 9450.0 * u) / f4 w += (27.0 * w4 + 339.0 * w3 + 930.0 * w2 - 1782.0 * w1 - 765.0 * w0 + 17955.0 * u) / f5 u + w end # Returns the P-value of tdist(). def p_value(y,n) if y > 0.5 pt(2.0 - y*2.0, n) else - pt(y*2.0, n) end end end end end enddistribution-0.7.0/lib/distribution/t/statistics2.rb0000644000175000017500000000123412061653751022152 0ustar boutilboutilrequire 'rbconfig' module Distribution module T module Statistics2_ class << self # Return the P-value of the corresponding integral with # k degrees of freedom def p_value(pr,k) Statistics2.ptdist(k, pr) end # There are some problem on i686 with t on statistics2 if true or !RbConfig::CONFIG['arch']=~/i686/ # T cumulative distribution function (cdf). # # Returns the integral of t-distribution # with n degrees of freedom over (-Infty, x]. # def cdf(x,k) Statistics2.tdist(k,x) end end end end end enddistribution-0.7.0/lib/distribution/t/gsl.rb0000644000175000017500000000121112061653751020456 0ustar boutilboutilmodule Distribution module T module GSL_ class << self def pdf(x,k) GSL::Ran.tdist_pdf(x,k) end # Return the P-value of the corresponding integral with # k degrees of freedom # # Distribution::F.p_value(0.95,1,2) def p_value(pr,k) GSL::Cdf.tdist_Pinv(pr,k) end # F cumulative distribution function (cdf). # # Returns the integral of F-distribution # with k1 and k2 degrees of freedom # over [0, x]. # Distribution::F.cdf(20,3,2) # def cdf(x, k) GSL::Cdf.tdist_P(x.to_f, k) end end end end enddistribution-0.7.0/lib/distribution/t/java.rb0000644000175000017500000000015212061653751020615 0ustar boutilboutilmodule Distribution module T # TODO module Java_ class << self end end end enddistribution-0.7.0/lib/distribution.rb0000644000175000017500000001200012061653751017424 0ustar boutilboutil# = distribution.rb - # Distribution - Statistical Distributions package for Ruby # # Copyright (C) 2011 Claudio Bustos # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # == Other Sources # # * Code of several Ruby engines came from statistics2.rb, # created by Shin-ichiro HARA(sinara@blade.nagaokaut.ac.jp). # Retrieve from http://blade.nagaokaut.ac.jp/~sinara/ruby/math/statistics2/ # * Code of Beta and Gamma distribution came from GSL project. # Ported by John O. Woods # Specific notices will be placed where there are appropiate # if !respond_to? :define_singleton_method class Module public :define_method end class Object def define_singleton_method(name,&block) sc=class < 0.97500210485178 # Distribution::Normal.p_value(0.95) # => 1.64485364660836 module Distribution VERSION="0.7.0" module Shorthand EQUIVALENCES={:p_value=>:p, :cdf=>:cdf, :pdf=>:pdf, :rng=>:r, :exact_pdf=>:epdf, :exact_cdf=>:ecdf, :exact_p_value=>:ep} def self.add_shortcut(sh,m, &block) if EQUIVALENCES.include? m.to_sym sh_name=sh+"_#{m}" define_method(sh_name,&block) sh_name=sh+"_#{EQUIVALENCES[m.to_sym]}" define_method(sh_name,&block) end end end SQ2PI = Math.sqrt(2 * Math::PI) # Create a method 'has_' on Module # which require a library and return true or false # according to success of failure def self.create_has_library(library) #:nodoc: define_singleton_method("has_#{library}?") do cv="@@#{library}" if !class_variable_defined? cv begin require library.to_s class_variable_set(cv, true) rescue LoadError class_variable_set(cv, false) end end class_variable_get(cv) end end # Retrieves the libraries used to calculate # distributions def self.libraries_order order=[:Ruby_] order.unshift(:Statistics2_) if has_statistics2? order.unshift(:GSL_) if has_gsl? order.unshift(:Java_) if has_java? order end create_has_library :gsl create_has_library :statistics2 create_has_library :java # Magic module module Distributable #:nodoc: # Create methods for each module and add methods to # Distribution::Shorthand. # # Traverse Distribution.libraries_order adding # methods availables for each engine module on # the current library # # Kids: Metaprogramming trickery! Don't do at work. # This section was created between a very long reunion # and a 456 Km. travel def create_distribution_methods() Distribution.libraries_order.each do |l_name| if const_defined? l_name l =const_get(l_name) # Add methods from engine to base base, if not yet included l.singleton_methods.each do |m| if !singleton_methods.include? m define_method(m) do |*args| l.send(m,*args) end # Add method to Distribution::Shorthand sh=const_get(:SHORTHAND) Distribution::Shorthand.add_shortcut(sh,m) do |*args| l.send(m,*args) end module_function m end end end end # create alias for common methods alias_method :inverse_cdf, :p_value if singleton_methods.include? :p_value end end def self.init_java() $:.unshift(File.dirname(__FILE__)+"/../vendor/java") require 'commons-math-2.2.jar' java_import 'org.apache.commons.math.distribution.NormalDistributionImpl' java_import 'org.apache.commons.math.distribution.PoissonDistributionImpl' end require 'distribution/normal' require 'distribution/chisquare' require 'distribution/gamma' require 'distribution/beta' require 'distribution/t' require 'distribution/f' require 'distribution/bivariatenormal' require 'distribution/binomial' require 'distribution/hypergeometric' require 'distribution/exponential' require 'distribution/poisson' require 'distribution/logistic' require 'distribution/lognormal' if has_java? init_java() end end distribution-0.7.0/spec/0000755000175000017500000000000012061653751014553 5ustar boutilboutildistribution-0.7.0/spec/t_spec.rb0000644000175000017500000000552312061653751016362 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::T do shared_examples_for "T engine(with rng)" do it "should return correct rng" do pending() end end shared_examples_for "T engine(cdf with fractional df)" do it "should return correct cdf with fractional df" do @engine.cdf(1,2.5).should be_within(1e-6).of(0.7979695) @engine.cdf(2,3.5).should be_within(1e-6).of(0.9369307) @engine.cdf(3,4.5).should be_within(1e-6).of(0.9828096) end end shared_examples_for "T engine" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf [-2,0.1,0.5,1,2].each{|t| [2,5,10].each{|n| @engine.pdf(t,n).should be_within(1e-6).of(GSL::Ran.tdist_pdf(t,n)) @engine.pdf(t,n.to_f).should be_within(1e-6).of(@engine.pdf(t,n)) } } else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf # Testing with R values @engine.cdf(1,2).should be_within(1e-7).of(0.7886751) @engine.cdf(1,2.0).should be_within(1e-7).of(0.7886751) @engine.cdf(1,3.0).should be_within(1e-7).of(0.8044989) [-2,0.1,0.5,1,2].each{|t| [2,5,10].each{|n| @engine.cdf(t,n).should be_within(1e-4).of(GSL::Cdf.tdist_P(t,n)) @engine.cdf(t,n).should be_within(1e-4).of(@engine.cdf(t,n.to_f)) } } else pending("No #{@engine}.cdf") end end it_only_with_gsl "should return correct p_value" do if @engine.respond_to? :p_value [-2,0.1,0.5,1,2].each{|t| [2,5,10].each{|n| area=Distribution::T.cdf(t,n) @engine.p_value(area,n).should be_within(1e-4).of(GSL::Cdf.tdist_Pinv(area,n)) } } else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::T end it_should_behave_like "T engine" end describe Distribution::T::Ruby_ do before do @engine=Distribution::T::Ruby_ end it_should_behave_like "T engine" it_should_behave_like "T engine(cdf with fractional df)" end if Distribution.has_gsl? describe Distribution::T::GSL_ do before do @engine=Distribution::T::GSL_ end it_should_behave_like "T engine" it_should_behave_like "T engine(cdf with fractional df)" end end =begin if Distribution.has_statistics2? describe Distribution::T::Statistics2_ do before do @engine=Distribution::T::Statistics2_ end it_should_behave_like "T engine" end end =end if Distribution.has_java? describe Distribution::T::Java_ do before do @engine=Distribution::T::Java_ end it_should_behave_like "T engine" end end end distribution-0.7.0/spec/lognormal_spec.rb0000644000175000017500000000265012061653751020107 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::LogNormal do shared_examples_for "log-normal engine" do it "should return correct pdf" do if @engine.respond_to? :pdf 1.upto(10) { u=rand() s=rand()*100 x=rand()*50 exp=(1.0/(x*s*Math.sqrt(2*Math::PI)))*Math.exp(-((Math.log(x)-u)**2 / (2*s**2))) @engine.pdf(x,u,s).should be_within(1e-10).of(exp) } else pending("No #{@engine}.pdf") end end it "should return correct cdf" do if @engine.respond_to? :cdf 1.upto(10) { u=rand() s=rand()*100 x=rand()*50 exp=Distribution::Normal.cdf((Math.log(x) - u) / s) @engine.cdf(x,u,s).should be_within(1e-10).of(exp) } else pending("No #{@engine}.cdf") end end end describe "singleton" do before do @engine=Distribution::LogNormal end it_should_behave_like "log-normal engine" end describe Distribution::LogNormal::Ruby_ do before do @engine=Distribution::LogNormal::Ruby_ end it_should_behave_like "log-normal engine" end if Distribution.has_gsl? describe Distribution::LogNormal::GSL_ do before do @engine=Distribution::LogNormal::GSL_ end it_should_behave_like "log-normal engine" end end end distribution-0.7.0/spec/logistic_spec.rb0000644000175000017500000000272012061653751017730 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::Logistic do shared_examples_for "logistic engine" do it "should return correct pdf" do if @engine.respond_to? :pdf 1.upto(10) { u=rand() s=rand()+1 x=rand()*100-50 exp=Math.exp(-(x-u) / s) / (s*(1+Math.exp(-(x-u) / s)**2)) @engine.pdf(x,u,s).should eq(exp) } else pending("No #{@engine}.pdf") end end it "should return correct cdf" do if @engine.respond_to? :cdf 1.upto(100) { u=rand() s=rand()*100 x=rand()*100-50 exp=1/(1+Math.exp(-(x-u) / s)) @engine.cdf(x,u,s).should eq(exp) } else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value 1.upto(9) {|i| u=rand() s=rand()*100 x=@engine.p_value(i/10.0,u,s) @engine.cdf(x,u,s).should be_within(1e-10).of(i/10.0) } else pending("No #{@engine}.cdf") end end end describe "singleton" do before do @engine=Distribution::Logistic end it_should_behave_like "logistic engine" end describe Distribution::Logistic::Ruby_ do before do @engine=Distribution::Logistic::Ruby_ end it_should_behave_like "logistic engine" end end distribution-0.7.0/spec/distribution_spec.rb0000644000175000017500000000110612061653751020627 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution do it "should respond to has_gsl?" do lambda {Distribution.has_gsl?}.should_not raise_exception if Distribution.has_gsl? defined?(GSL).should be_true else defined?(GSL).should be_false end end it "should respond to has_statistics2?" do lambda {Distribution.has_statistics2?}.should_not raise_exception if Distribution.has_statistics2? defined?(Statistics2).should be_true else defined?(Statistics2).should be_false end end end distribution-0.7.0/spec/beta_spec.rb0000644000175000017500000000476712061653751017043 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::Beta do shared_examples_for "Beta engine" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf 1.upto(101) do |x| a=rand * x b=1 + rand * 5 g=GSL::Ran.beta_pdf(x,a,b) @engine.pdf(x,a,b).should be_within(1e-10).of(g) end else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf # From GSL-1.9. tol = 1048576.0*Float::EPSILON @engine.cdf(0.0, 1.2, 1.3).should eq(0.0) @engine.cdf(1e-100, 1.2, 1.3).should be_within(tol).of(1.34434944656489596e-120) @engine.cdf(0.001, 1.2, 1.3).should be_within(tol).of(3.37630042504535813e-4) @engine.cdf(0.01, 1.2, 1.3).should be_within(tol).of(5.34317264038929473e-3) @engine.cdf(0.1, 1.2, 1.3).should be_within(tol).of(8.33997828306748346e-2) @engine.cdf(0.325, 1.2, 1.3).should be_within(tol).of(3.28698654180583916e-1) @engine.cdf(0.5, 1.2, 1.3).should be_within(tol).of(5.29781429451299081e-1) @engine.cdf(0.9, 1.2, 1.3).should be_within(tol).of(9.38529397224430659e-1) @engine.cdf(0.99, 1.2, 1.3).should be_within(tol).of(9.96886438341254380e-1) @engine.cdf(0.999, 1.2, 1.3).should be_within(tol).of(9.99843792833067634e-1) @engine.cdf(1.0, 1.2, 1.3).should be_within(tol).of(1.0) else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value 2.upto(99) do |x| a=rand() * x b=1 + rand() * 5 pr=@engine.cdf(x/100.0,a,b) @engine.p_value(pr,a, b).should be_within(1e-10).of(x/100.0) end else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::Beta end it_should_behave_like "Beta engine" end describe Distribution::Beta::Ruby_ do before do @engine=Distribution::Beta::Ruby_ end it_should_behave_like "Beta engine" end if Distribution.has_gsl? describe Distribution::Beta::GSL_ do before do @engine=Distribution::Beta::GSL_ end it_should_behave_like "Beta engine" end end if Distribution.has_java? describe Distribution::Beta::Java_ do before do @engine=Distribution::Beta::Java_ end it_should_behave_like "Beta engine" end end end distribution-0.7.0/spec/math_extension_spec.rb0000644000175000017500000003350012061653751021140 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::MathExtension do it "binomial coefficient should be correctly calculated" do n=50 n.times do |k| Math.binomial_coefficient(n,k).should eq(Math.factorial(n).quo(Math.factorial(k)*Math.factorial(n-k))) end end it "ChebyshevSeries for :sin should return correct values" do #Math::SIN_CS.evaluate() end it "log_1plusx_minusx should return correct values" do # Tests from GSL-1.9 Math::Log.log_1plusx_minusx(1.0e-10).should be_within(1e-10).of(-4.999999999666666667e-21) Math::Log.log_1plusx_minusx(1.0e-8).should be_within(1e-10).of(-4.999999966666666917e-17) Math::Log.log_1plusx_minusx(1.0e-4).should be_within(1e-10).of(-4.999666691664666833e-09) Math::Log.log_1plusx_minusx(0.1).should be_within(1e-10).of(-0.004689820195675139956) Math::Log.log_1plusx_minusx(0.49).should be_within(1e-10).of(-0.09122388004263222704) Math::Log.log_1plusx_minusx(-0.49).should be_within(1e-10).of(-0.18334455326376559639) Math::Log.log_1plusx_minusx(1.0).should be_within(1e-10).of(Math::LN2 - 1.0) Math::Log.log_1plusx_minusx(-0.99).should be_within(1e-10).of(-3.615170185988091368) end it "log_1plusx should return correct values" do # Tests from GSL-1.9 Math::Log.log_1plusx(1.0e-10).should be_within(1e-10).of(9.999999999500000000e-11) Math::Log.log_1plusx(1.0e-8).should be_within(1e-10).of(9.999999950000000333e-09) Math::Log.log_1plusx(1.0e-4).should be_within(1e-10).of(0.00009999500033330833533) Math::Log.log_1plusx(0.1).should be_within(1e-10).of(0.09531017980432486004) Math::Log.log_1plusx(0.49).should be_within(1e-10).of(0.3987761199573677730) Math::Log.log_1plusx(-0.49).should be_within(1e-10).of(-0.6733445532637655964) Math::Log.log_1plusx(1.0).should be_within(1e-10).of(Math::LN2) Math::Log.log_1plusx(-0.99).should be_within(1e-10).of(-4.605170185988091368) end it "log_beta should return correct values" do Math::Beta.log_beta(1.0e-8, 1.0e-8).first.should be_within(1e-10).of(19.113827924512310617) Math::Beta.log_beta(1.0e-8, 0.01).first.should be_within(1e-10).of(18.420681743788563403) Math::Beta.log_beta(1.0e-8, 1.0).first.should be_within(1e-10).of(18.420680743952365472) Math::Beta.log_beta(1.0e-8, 10.0).first.should be_within(1e-10).of(18.420680715662683009) Math::Beta.log_beta(1.0e-8, 1000.0).first.should be_within(1e-10).of(18.420680669107656949) Math::Beta.log_beta(0.1, 0.1).first.should be_within(1e-10).of(2.9813614810376273949) Math::Beta.log_beta(0.1, 1.0).first.should be_within(1e-10).of(2.3025850929940456840) Math::Beta.log_beta(0.1, 100.0).first.should be_within(1e-10).of(1.7926462324527931217) Math::Beta.log_beta(0.1, 1000).first.should be_within(1e-10).of(1.5619821298353164928) Math::Beta.log_beta(1.0, 1.00025).first.should be_within(1e-10).of(-0.0002499687552073570) Math::Beta.log_beta(1.0, 1.01).first.should be_within(1e-10).of(-0.009950330853168082848) Math::Beta.log_beta(1.0, 1000.0).first.should be_within(1e-10).of(-6.907755278982137052) Math::Beta.log_beta(100.0, 100.0).first.should be_within(1e-10).of(-139.66525908670663927) Math::Beta.log_beta(100.0, 1000.0).first.should be_within(1e-10).of(-336.4348576477366051) Math::Beta.log_beta(100.0, 1.0e+8).first.should be_within(1e-10).of(-1482.9339185256447309) end it "regularized_beta should return correct values" do Math.regularized_beta(0.0,1.0, 1.0).should be_within(1e-10).of(0.0) Math.regularized_beta(1.0, 1.0, 1.0).should be_within(1e-10).of(1.0) Math.regularized_beta(1.0, 0.1, 0.1).should be_within(1e-10).of(1.0) Math.regularized_beta(0.5, 1.0, 1.0).should be_within(1e-10).of(0.5) Math.regularized_beta(0.5, 0.1, 1.0).should be_within(1e-10).of(0.9330329915368074160) Math.regularized_beta(0.5, 10.0, 1.0).should be_within(1e-10).of(0.0009765625000000000000) Math.regularized_beta(0.5, 50.0, 1.0).should be_within(1e-10).of(8.881784197001252323e-16) Math.regularized_beta(0.5, 1.0, 0.1).should be_within(1e-10).of(0.06696700846319258402) Math.regularized_beta(0.5, 1.0, 10.0).should be_within(1e-10).of(0.99902343750000000000) Math.regularized_beta(0.5, 1.0, 50.0).should be_within(1e-10).of(0.99999999999999911180) Math.regularized_beta(0.1, 1.0, 1.0).should be_within(1e-10).of(0.10) Math.regularized_beta(0.1, 1.0, 2.0).should be_within(1e-10).of(0.19) Math.regularized_beta(0.9, 1.0, 2.0).should be_within(1e-10).of(0.99) Math.regularized_beta(0.5, 50.0, 60.0).should be_within(1e-10).of(0.8309072939016694143) Math.regularized_beta(0.5, 90.0, 90.0).should be_within(1e-10).of(0.5) Math.regularized_beta(0.5, 500.0, 500.0).should be_within(1e-10).of(0.5) Math.regularized_beta(0.4, 5000.0, 5000.0).should be_within(1e-10).of(4.518543727260666383e-91) Math.regularized_beta(0.6, 5000.0, 5000.0).should be_within(1e-10).of(1.0) Math.regularized_beta(0.6, 5000.0, 2000.0).should be_within(1e-10).of(8.445388773903332659e-89) end it_only_with_gsl "incomplete_beta should return correct values" do a=rand()*10+1 b=rand()*10+1 ib = GSL::Function.alloc { |t| t**(a-1)*(1-t)**(b-1)} w = GSL::Integration::Workspace.alloc(1000) 1.upto(10) {|x| inte=ib.qag([0,x / 10.0],w) Math.incomplete_beta(x/10.0, a ,b).should be_within(1e-10).of(inte[0]) } end it "gammastar should return correct values" do # Tests from GSL-1.9 Math::Gammastar.evaluate(1.0e-08).should be_within(1e-10).of(3989.423555759890865) Math::Gammastar.evaluate(1.0e-05).should be_within(1e-10).of(126.17168469882690233) Math::Gammastar.evaluate(0.001).should be_within(1e-10).of(12.708492464364073506) Math::Gammastar.evaluate(1.5).should be_within(1e-10).of(1.0563442442685598666) Math::Gammastar.evaluate(3.0).should be_within(1e-10).of(1.0280645179187893045) Math::Gammastar.evaluate(9.0).should be_within(1e-10).of(1.0092984264218189715) Math::Gammastar.evaluate(11.0).should be_within(1e-10).of(1.0076024283104962850) Math::Gammastar.evaluate(100.0).should be_within(1e-10).of(1.0008336778720121418) Math::Gammastar.evaluate(1.0e+05).should be_within(1e-10).of(1.0000008333336805529) Math::Gammastar.evaluate(1.0e+20).should be_within(1e-10).of(1.0) end it "erfc_e should return correct values" do # From GSL-1.9. For troubleshooting gammq. Math::erfc_e(-10.0).should be_within(1e-10).of(2.0) Math::erfc_e(-5.0000002).should be_within(1e-10).of(1.9999999999984625433) Math::erfc_e(-5.0).should be_within(1e-10).of(1.9999999999984625402) Math::erfc_e(-1.0).should be_within(1e-10).of(1.8427007929497148693) Math::erfc_e(-0.5).should be_within(1e-10).of(1.5204998778130465377) Math::erfc_e(1.0).should be_within(1e-10).of(0.15729920705028513066) Math::erfc_e(3.0).should be_within(1e-10).of(0.000022090496998585441373) Math::erfc_e(7.0).should be_within(1e-10).of(4.183825607779414399e-23) Math::erfc_e(10.0).should be_within(1e-10).of(2.0884875837625447570e-45) end it "unnormalized_incomplete_gamma with x=0 should return correct values" do Math.unnormalized_incomplete_gamma(-1.5, 0).should be_within(1e-10).of(4.0*Math.sqrt(Math::PI) / 3.0) Math.unnormalized_incomplete_gamma(-0.5, 0).should be_within(1e-10).of(-2*Math.sqrt(Math::PI)) Math.unnormalized_incomplete_gamma(0.5, 0).should be_within(1e-10).of(Math.sqrt(Math::PI)) Math.unnormalized_incomplete_gamma(1.0, 0).should eq 1.0 Math.unnormalized_incomplete_gamma(1.5, 0).should be_within(1e-10).of(Math.sqrt(Math::PI) / 2.0) Math.unnormalized_incomplete_gamma(2.0, 0).should eq 1.0 Math.unnormalized_incomplete_gamma(2.5, 0).should be_within(1e-10).of(0.75*Math.sqrt(Math::PI)) Math.unnormalized_incomplete_gamma(3.0, 0).should be_within(1e-12).of(2.0) Math.unnormalized_incomplete_gamma(3.5, 0).should be_within(1e-10).of(15.0*Math.sqrt(Math::PI) / 8.0) Math.unnormalized_incomplete_gamma(4.0, 0).should be_within(1e-12).of(6.0) end it "incomplete_gamma should return correct values" do # Tests from GSL-1.9 Math.incomplete_gamma(1e-100, 0.001).should be_within(1e-10).of(1.0) Math.incomplete_gamma(0.001, 0.001).should be_within(1e-10).of(0.9936876467088602902) Math.incomplete_gamma(0.001, 1.0).should be_within(1e-10).of(0.9997803916424144436) Math.incomplete_gamma(0.001, 10.0).should be_within(1e-10).of(0.9999999958306921828) Math.incomplete_gamma(1.0, 0.001).should be_within(1e-10).of(0.0009995001666250083319) Math.incomplete_gamma(1.0, 1.01).should be_within(1e-10).of(0.6357810204284766802) Math.incomplete_gamma(1.0, 10.0).should be_within(1e-10).of(0.9999546000702375151) Math.incomplete_gamma(10.0, 10.01).should be_within(1e-10).of(0.5433207586693410570) Math.incomplete_gamma(10.0, 20.0).should be_within(1e-10).of(0.9950045876916924128) Math.incomplete_gamma(1000.0, 1000.1).should be_within(1e-10).of(0.5054666401440661753) Math.incomplete_gamma(1000.0, 2000.0).should be_within(1e-10).of(1.0) # designed to trap the a-x=1 problem # These next two are 1e-7 because they give the same output as GSL, but GSL is apparently not totally accurate here. # It's a problem with log_1plusx_mx (log_1plusx_minusx in my code) Math.incomplete_gamma(100, 99.0).should be_within(1e-7).of(0.4733043303994607) Math.incomplete_gamma(200, 199.0).should be_within(1e-7).of(0.4811585880878718) # Test for x86 cancellation problems Math.incomplete_gamma(5670, 4574).should be_within(1e-10).of(3.063972328743934e-55) end it "gammq should return correct values" do # Tests from GSL-1.9 Math.gammq(0.0, 0.001).should be_within(1e-10).of(0.0) Math.gammq(0.001, 0.001).should be_within(1e-10).of(0.006312353291139709793) Math.gammq(0.001, 1.0).should be_within(1e-10).of(0.00021960835758555639171) Math.gammq(0.001, 2.0).should be_within(1e-10).of(0.00004897691783098147880) Math.gammq(0.001, 5.0).should be_within(1e-10).of(1.1509813397308608541e-06) Math.gammq(1.0, 0.001).should be_within(1e-10).of(0.9990004998333749917) Math.gammq(1.0, 1.01).should be_within(1e-10).of(0.3642189795715233198) Math.gammq(1.0, 10.0).should be_within(1e-10).of(0.00004539992976248485154) Math.gammq(10.0, 10.01).should be_within(1e-10).of(0.4566792413306589430) Math.gammq(10.0, 100.0).should be_within(1e-10).of(1.1253473960842733885e-31) Math.gammq(1000.0, 1000.1).should be_within(1e-10).of(0.4945333598559338247) Math.gammq(1000.0, 2000.0).should be_within(1e-10).of(6.847349459614753180e-136) # designed to trap the a-x=1 problem Math.gammq(100, 99.0).should be_within(1e-10).of(0.5266956696005394) Math.gammq(200, 199.0).should be_within(1e-10).of(0.5188414119121281) # Test for x86 cancellation problems Math.gammq(5670, 4574).should be_within(1e-10).of(1.0000000000000000) # test suggested by Michel Lespinasse [gsl-discuss Sat, 13 Nov 2004] Math.gammq(1.0e+06-1.0, 1.0e+06-2.0).should be_within(1e-10).of(0.50026596175224547004) # tests in asymptotic regime related to Lespinasse test Math.gammq(1.0e+06+2.0, 1.0e+06+1.0).should be_within(1e-10).of(0.50026596135330304336) Math.gammq(1.0e+06, 1.0e+06-2.0).should be_within(1e-10).of(0.50066490399940144811) Math.gammq(1.0e+07, 1.0e+07-2.0).should be_within(1e-10).of(0.50021026104978614908) end it "rising_factorial should return correct values" do x=rand(10)+1 Math.rising_factorial(x,0).should eq 1 Math.rising_factorial(x,1).should eq x Math.rising_factorial(x,2).should eq x**2+x Math.rising_factorial(x,3).should eq x**3+3*x**2+2*x Math.rising_factorial(x,4).should eq x**4+6*x**3+11*x**2+6*x end it "permutations should return correct values" do n=rand(50)+50 10.times { |k| Math.permutations(n,k).should eq(Math.factorial(n) / Math.factorial(n-k)) } Math.permutations(n,n).should eq(Math.factorial(n) / Math.factorial(n-n)) end it "exact regularized incomplete beta should behave properly" do Math.exact_regularized_beta(0.5,5,5).should be_within(1e-6).of(0.5) Math.exact_regularized_beta(0.5,5,6).should be_within(1e-6).of(0.6230469) Math.exact_regularized_beta(0.5,5,7).should be_within(1e-6).of(0.725586) a=5 b=5 Math.exact_regularized_beta(0,a,b).should eq 0 Math.exact_regularized_beta(1,a,b).should eq 1 x=rand() Math.exact_regularized_beta(x,a,b).should be_within(1e-6). of(1-Math.regularized_beta(1-x,b,a)) end it "binomial coefficient(gamma) with n<=48 should be correct " do [1,5,10,25,48].each {|n| k=(n/2).to_i Math.binomial_coefficient_gamma(n,k).round.should eq(Math.binomial_coefficient(n,k)) } end it "binomial coefficient(gamma) with 4833" do ac=8683317618811886495518194401280000000 # 33! Math.factorial(33).should eq ac 34.upto(40).each do |i| ac*=i Math.factorial(i).should eq(ac) end end end end distribution-0.7.0/spec/binomial_spec.rb0000644000175000017500000000645312061653751017714 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::Binomial do shared_examples_for "binomial engine" do it "should return correct pdf" do if @engine.respond_to? :pdf [10,100,1000].each do |n| [1.quo(4),1.quo(2),3.quo(4)].each do |pr| [0, 1,n/2,n-1].each do |x| exp=Math.binomial_coefficient(n,x)*pr**x*(1-pr)**(n-x) obs=@engine.pdf(x,n,pr) obs.should be_within(1e-5).of(exp), "For pdf(#{x},#{n},#{pr}) expected #{exp}, obtained #{obs}" end end end else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct cdf for n<=100" do if @engine.respond_to? :pdf [10,100].each do |n| [0.25,0.5,0.75].each do |pr| [1,n/2,n-1].each do |x| exp=GSL::Cdf.binomial_P(x,pr,n) obs=@engine.cdf(x,n,pr) exp.should be_within(1e-5).of(obs), "For cdf(#{x},#{n},#{pr}) expected #{exp}, obtained #{obs}" end end end else pending("No #{@engine}.cdf") end end end describe "singleton" do before do @engine=Distribution::Binomial end it_should_behave_like "binomial engine" it {@engine.should respond_to(:exact_pdf) } it { pending("No exact_p_value") @engine.should respond_to(:exact_p_value) } it "exact_cdf should return same values as cdf for n=50" do pr=rand()*0.8+0.1 n=rand(10)+10 [1,(n/2).to_i,n-1].each do |k| @engine.exact_cdf(k,n,pr).should be_within(1e-10).of(@engine.cdf(k,n,pr)) end end it "exact_pdf should not return a Float if not float is used as parameter" do @engine.exact_pdf(1,1,1).should_not be_a(Float) @engine.exact_pdf(16, 80, 1.quo(2)).should_not be_a(Float) end end describe Distribution::Binomial::Ruby_ do before do @engine=Distribution::Binomial::Ruby_ end it_should_behave_like "binomial engine" it "should return correct cdf for n>100" do pending("incomplete beta function is slow. Should be replaced for a faster one") end it "should return correct p_value for n<=100" do pending("Can't calculate with precision x using p") [10,100].each do |n| [0.25,0.5,0.75].each do |pr| [n/2].each do |x| cdf=@engine.cdf(x,n,pr) p_value=@engine.p_value(cdf,n,pr) p_value.should eq(x), "For p_value(#{cdf},#{n},#{pr}) expected #{x}, obtained #{p_value}" end end end end end if Distribution.has_gsl? describe Distribution::Binomial::GSL_ do before do @engine=Distribution::Binomial::GSL_ end it_should_behave_like "binomial engine" end end #if Distribution.has_statistics2? # describe Distribution::Binomial::Statistics2_ do # # before do # @engine=Distribution::Binomial::Statistics2_ # end #it_should_behave_like "binomial engine" # end #end if Distribution.has_java? describe Distribution::Binomial::Java_ do before do @engine=Distribution::Binomial::Java_ end it_should_behave_like "binomial engine" end end end distribution-0.7.0/spec/bivariatenormal_spec.rb0000644000175000017500000000362612061653751021300 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::BivariateNormal do shared_examples_for "all pdf normal capables engines" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf [0.2,0.4,0.6,0.8,0.9, 0.99,0.999,0.999999].each {|rho| @engine.pdf(0,0, rho , 1,1).should be_within(1e-8).of(GSL::Ran::bivariate_gaussian_pdf(0, 0, 1,1,rho)) } else pending("No #{@engine}.pdf") end end end shared_examples_for "all cdf normal capables engines" do it "should return correct cdf" do if @engine.respond_to? :cdf @engine.cdf(2,0.5,0.5).should be_within(1e-3).of(0.686) @engine.cdf(2,0.0,0.5).should be_within(1e-3).of(0.498) @engine.cdf(1.5,0.5,0.5).should be_within(1e-3).of(0.671) v=rand @engine.cdf(10,0,v).should be_within(1e-3).of(Distribution::Normal.cdf(0)) else pending("No #{@engine}.cdf") end end end describe "singleton" do before do @engine=Distribution::BivariateNormal end it_should_behave_like "all pdf normal capables engines" it_should_behave_like "all cdf normal capables engines" end describe Distribution::Normal::Ruby_ do before do @engine=Distribution::BivariateNormal::Ruby_ end it_should_behave_like "all pdf normal capables engines" it_should_behave_like "all cdf normal capables engines" it "Ganz method should return similar method to Hull one" do [-3,-2,-1,0,1,1.5].each {|x| @engine.cdf_hull(x,x,0.5).should be_within(0.001).of(@engine.cdf_genz(x,x,0.5)) } end end describe Distribution::Normal::GSL_ do before do @engine=Distribution::BivariateNormal::GSL_ end it_should_behave_like "all pdf normal capables engines" end end distribution-0.7.0/spec/spec.opts0000644000175000017500000000002012061653751016404 0ustar boutilboutil--color -f s -b distribution-0.7.0/spec/shorthand_spec.rb0000644000175000017500000000223612061653751020107 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::Shorthand do include Distribution::Shorthand it "should have basic methods for all distributions" do [:Normal,:ChiSquare, :F, :Hypergeometric, :Binomial, :T].each do |d| klass=Distribution.const_get(d) shortname=klass::SHORTHAND methods=[:pdf, :cdf, :p_value].map {|m| "#{shortname}_#{m}".to_sym} methods.each do |m| Distribution::Shorthand.instance_methods.map {|v| v.to_sym}.should include(m) end end end it "should have exact methods discrete distributions" do [:Hypergeometric, :Binomial].each do |d| klass=Distribution.const_get(d) shortname=klass::SHORTHAND methods=[:epdf, :ecdf].map {|m| "#{shortname}_#{m}".to_sym} methods.each do |m| Distribution::Shorthand.instance_methods.map {|v| v.to_sym}.should include(m) end end end it "returns same values as long form" do x=rand() norm_cdf(x).should eql(Distribution::Normal.cdf(x)) norm_pdf(x).should eql(Distribution::Normal.pdf(x)) norm_p_value(x).should eql(Distribution::Normal.p_value(x)) end end distribution-0.7.0/spec/gamma_spec.rb0000644000175000017500000000527512061653751017205 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::Gamma do shared_examples_for "Gamma engine" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf 1.upto(101) do |x| a=rand * x b=1 + rand * 5 g=GSL::Ran.gamma_pdf(x,a,b) @engine.pdf(x,a,b).should be_within(1e-10).of(g) end else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf # From GSL-1.9. tol = 1048576.0*Float::EPSILON @engine.cdf(0.0, 1.0, 1.0).should eq(0.0) @engine.cdf(1e-100, 1.0, 1.0).should be_within(tol).of(1e-100) @engine.cdf(0.001, 1.0, 1.0).should be_within(tol).of(9.99500166625008332e-4) @engine.cdf(0.01, 1.0, 1.0).should be_within(tol).of(9.95016625083194643e-3) @engine.cdf(0.1, 1.0, 1.0).should be_within(tol).of(9.51625819640404268e-2) @engine.cdf(0.325, 1.0, 1.0).should be_within(tol).of(2.77472646357927811e-1) @engine.cdf(1.0, 1.0, 1.0).should be_within(tol).of(6.32120558828557678e-1) @engine.cdf(1.5, 1.0, 1.0).should be_within(tol).of(7.76869839851570171e-1) @engine.cdf(2.0, 1.0, 1.0).should be_within(tol).of(8.64664716763387308e-1) @engine.cdf(10.0, 1.0, 1.0).should be_within(tol).of(9.99954600070237515e-1) @engine.cdf(20.0, 1.0, 1.0).should be_within(tol).of(9.99999997938846378e-1) @engine.cdf(100.0, 1.0, 1.0).should be_within(tol).of(1e0) @engine.cdf(1000.0, 1.0, 1.0).should be_within(tol).of(1e0) @engine.cdf(10000.0, 1.0, 1.0).should be_within(tol).of(1e0) else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value 1.upto(20) do |x| a=rand()*0.5 b=1 + rand() * 5 pr=@engine.cdf(x,a,b) @engine.p_value(pr,a,b).should be_within(1e-3).of(x) end else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::Gamma end it_should_behave_like "Gamma engine" end describe Distribution::Gamma::Ruby_ do before do @engine=Distribution::Gamma::Ruby_ end it_should_behave_like "Gamma engine" end if Distribution.has_gsl? describe Distribution::Gamma::GSL_ do before do @engine=Distribution::Gamma::GSL_ end it_should_behave_like "Gamma engine" end end if Distribution.has_java? describe Distribution::Gamma::Java_ do before do @engine=Distribution::Gamma::Java_ end it_should_behave_like "Gamma engine" end end end distribution-0.7.0/spec/chisquare_spec.rb0000644000175000017500000000444012061653751020100 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::ChiSquare do shared_examples_for "Chi-square engine(with pdf)" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf 1.upto(10) do |k| v=1+rand(5) chi=GSL::Ran.chisq_pdf(v,k) @engine.pdf(v,k).should be_within(10e-10).of(chi) end else pending("No #{@engine}.pdf") end end end shared_examples_for "Chi-square engine" do it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf 1.upto(10) do |k| v=1+rand(5) chi=GSL::Cdf::chisq_P(v,k) @engine.cdf(v,k).should be_within(10e-10).of(chi) end else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value 1.upto(10) do |k| v=1+rand(5) pr=@engine.cdf(v,k) @engine.p_value(pr,k).should be_within(10e-4).of(v) end else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::ChiSquare end it_should_behave_like "Chi-square engine" it_should_behave_like "Chi-square engine(with pdf)" end describe Distribution::ChiSquare::Ruby_ do before do @engine=Distribution::ChiSquare::Ruby_ end it_should_behave_like "Chi-square engine" it_should_behave_like "Chi-square engine(with pdf)" end if Distribution.has_gsl? describe Distribution::ChiSquare::GSL_ do before do @engine=Distribution::ChiSquare::GSL_ end it_should_behave_like "Chi-square engine" it_should_behave_like "Chi-square engine(with pdf)" end end if Distribution.has_statistics2? describe Distribution::ChiSquare::Statistics2_ do before do @engine=Distribution::ChiSquare::Statistics2_ end it_should_behave_like "Chi-square engine" end end if Distribution.has_java? describe Distribution::ChiSquare::Java_ do before do @engine=Distribution::ChiSquare::Java_ end it_should_behave_like "Chi-square engine" it_should_behave_like "Chi-square engine(with pdf)" end end end distribution-0.7.0/spec/exponential_spec.rb0000644000175000017500000000347712061653751020453 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::Exponential do shared_examples_for "exponential engine" do it "should return correct pdf" do if @engine.respond_to? :pdf [0.5,1,1.5].each {|l| 1.upto(5) {|x| @engine.pdf(x,l).should be_within(1e-10).of(l*Math.exp(-l*x)) } } else pending("No #{@engine}.pdf") end end it "should return correct cdf" do if @engine.respond_to? :cdf [0.5,1,1.5].each {|l| 1.upto(5) {|x| @engine.cdf(x,l).should be_within(1e-10).of(1-Math.exp(-l*x)) } } else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value [0.5,1,1.5].each {|l| 1.upto(5) {|x| pr=@engine.cdf(x,l) @engine.p_value(pr,l).should be_within(1e-10).of(x) } } else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::Exponential end it_should_behave_like "exponential engine" end describe Distribution::Exponential::Ruby_ do before do @engine=Distribution::Exponential::Ruby_ end it_should_behave_like "exponential engine" end if Distribution.has_gsl? describe Distribution::Exponential::GSL_ do before do @engine=Distribution::Exponential::GSL_ end it_should_behave_like "exponential engine" end end # if Distribution.has_java? # describe Distribution::Exponential::Java_ do # before do # @engine=Distribution::Exponential::Java_ # end # it_should_behave_like "exponential engine" # # end # end end distribution-0.7.0/spec/hypergeometric_spec.rb0000644000175000017500000000622412061653751021144 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL #require 'ruby-prof' # Need to test: # * that Fixnum fast_choose returns same as choose # * that pdf and exact_pdf return the same value in Ruby_ # * that cdf in Ruby_ returns the same value as cdf in GSL_ describe Distribution::Hypergeometric do describe Distribution::Hypergeometric::GSL_ do before do @ruby=Distribution::Hypergeometric::Ruby_ @engine=Distribution::Hypergeometric::GSL_ end it_only_with_gsl "cdf should return values near to exact Ruby calculations" do #RubyProf.start if @engine.respond_to? :cdf #[2].each do |k| [0,1,2,4,8,16].each do |k| @engine.cdf(k, 80, 100, 10000).should be_within(1e-10).of(@ruby.cdf(k, 80, 100, 10000)) end #result = RubyProf.stop # Print a flat profile to text #printer = RubyProf::FlatPrinter.new(result) #printer.print(STDOUT) else pending("No #{@engine}.pdf") end end end describe Distribution::Hypergeometric::Ruby_ do before do @engine=Distribution::Hypergeometric::Ruby_ end it_only_with_gsl "pdf_fast should return same as pdf" do pending("Aprox. factorial doesn't work right") if @engine.respond_to? :pdf [0,1,2,4,8,16].each do |k| @engine.pdf_aprox(k, 80, 100, 1000).should be_within(1e-8).of(GSL::Ran::hypergeometric_pdf(k, 80, 920, 100)) end else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct pdf" do #RubyProf.start if @engine.respond_to? :pdf #[2].each do |k| [0,1,2,4,8,16].each do |k| #puts "k:#{k}->#{@engine.pdf(k, 80, 100, 10000).to_f}" @engine.pdf(k, 80, 100, 10000).to_f.should be_within(1e-8).of(GSL::Ran::hypergeometric_pdf(k, 80, 9920, 100)) end #result = RubyProf.stop # Print a flat profile to text #printer = RubyProf::FlatPrinter.new(result) #printer.print(STDOUT) else pending("No #{@engine}.pdf") end end it "should return correct cdf" do total=rand(5)+3000 n=rand(10)+15 m=rand(10)+5 ac=0 0.upto(m) do |i| ac+=@engine.pdf(i,m,n,total) @engine.cdf(i,m,n,total).should eq(ac) end end it "should return correct p_value" do #0.upto(10) do |i| # puts "#{i}:#{@engine.pdf(i,5,7,10)}" #end total=rand(5)+3000 n=rand(10)+15 m=rand(10)+5 ac=0 0.upto(m) do |k| ac+=@engine.pdf(k,m,n,total) @engine.p_value(ac, m, n, total).should eq(k) end end end describe Distribution::Hypergeometric do before do @engine=Distribution::Hypergeometric end it {@engine.should respond_to(:exact_pdf) } it {@engine.should respond_to(:exact_cdf) } it {@engine.should respond_to(:exact_p_value) } it "exact pdf should return a Rational" do @engine.exact_pdf(1,1,1,1).should_not be_a(Float) @engine.exact_pdf(16, 80, 100, 10000).should_not be_a(Float) end end enddistribution-0.7.0/spec/poisson_spec.rb0000644000175000017500000000414712061653751017612 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::Poisson do shared_examples_for "poisson engine" do it "should return correct pdf" do if @engine.respond_to? :pdf [0.5,1,1.5].each {|l| 1.upto(5) {|k| @engine.pdf(k,l).should be_within(1e-10).of( (l**k*Math.exp(-l)).quo(Math.factorial(k)) ) } } else pending("No #{@engine}.pdf") end end it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf [0.5,1,1.5,4,10].each {|l| 1.upto(5) {|k| @engine.cdf(k,l).should be_within(1e-10).of(GSL::Cdf.poisson_P(k,l)) } } else pending("No #{@engine}.cdf") end end it "should return correct p_value" do pending("No exact p_value") if @engine.respond_to? :p_value [0.1,1,5,10].each {|l| 1.upto(20) {|k| pr=@engine.cdf(k,l) @engine.p_value(pr,l).should eq(k) } } else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::Poisson end it_should_behave_like "poisson engine" end describe Distribution::Poisson::Ruby_ do before do @engine=Distribution::Poisson::Ruby_ end it_should_behave_like "poisson engine" end if Distribution.has_gsl? describe Distribution::Poisson::GSL_ do before do @engine=Distribution::Poisson::GSL_ end it_should_behave_like "poisson engine" end end if Distribution.has_java? describe Distribution::Poisson::Java_ do before do @engine=Distribution::Poisson::Java_ end it_should_behave_like "poisson engine" it "should return correct cdf" do [0.5,1,1.5,4,10].each {|l| 1.upto(5) {|k| @engine.cdf(k,l).should be_within(1e-10).of(Distribution::Poisson::Ruby_.cdf(k,l)) } } end end end end distribution-0.7.0/spec/normal_spec.rb0000644000175000017500000000546312061653751017412 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") describe Distribution::Normal do shared_examples_for "gaussian engine(with rng)" do it "should return correct rng" do samples=100 sum=0 ss=0 exp_mean=rand(10)-5 exp_sd=1 rng=@engine.rng(exp_mean,exp_sd) samples.times do v=rng.call sum+=v ss+=(v-exp_mean)**2 end mean=sum.to_f/samples sd=Math::sqrt(ss.to_f/samples) mean.should be_within(0.5).of(exp_mean) sd.should be_within(0.3).of(exp_sd) end end shared_examples_for "gaussian engine(with pdf)" do it "should return correct pdf" do if @engine.respond_to? :pdf 10.times do |i| x=(i-5)/2.0 pdf=(1.0 / Distribution::SQ2PI)*Math::exp(-(x**2/2.0)) @engine.pdf(x).should be_within(1e-10).of(pdf) end else pending("No #{@engine}.pdf") end end end shared_examples_for "gaussian engine" do it "should return correct cdf" do if @engine.respond_to? :cdf @engine.cdf(1.96).should be_within(1e-10).of(0.97500210485178) @engine.cdf(0).should be_within(1e-10).of(0.5) else pending("No #{@engine}.cdf") end end it "should return correct p_value" do if @engine.respond_to? :p_value @engine.p_value(0.5).should be_within(1e-3).of(0) 10.times do |i| x=(i-5) / 2.0 cdf=@engine.cdf(x) @engine.p_value(cdf).should be_within(1e-6).of(x) end else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::Normal end it_should_behave_like "gaussian engine" it_should_behave_like "gaussian engine(with rng)" it_should_behave_like "gaussian engine(with pdf)" end describe Distribution::Normal::Ruby_ do before do @engine=Distribution::Normal::Ruby_ end it_should_behave_like "gaussian engine" it_should_behave_like "gaussian engine(with rng)" it_should_behave_like "gaussian engine(with pdf)" end if Distribution.has_gsl? describe Distribution::Normal::GSL_ do before do @engine=Distribution::Normal::GSL_ end it_should_behave_like "gaussian engine" it_should_behave_like "gaussian engine(with rng)" it_should_behave_like "gaussian engine(with pdf)" end end if Distribution.has_statistics2? describe Distribution::Normal::Statistics2_ do before do @engine=Distribution::Normal::Statistics2_ end it_should_behave_like "gaussian engine" end end if Distribution.has_java? describe Distribution::Normal::Java_ do before do @engine=Distribution::Normal::Java_ end it_should_behave_like "gaussian engine" end end end distribution-0.7.0/spec/spec_helper.rb0000644000175000017500000000115112061653751017367 0ustar boutilboutil$:.unshift(File.dirname(__FILE__)+"/../lib") begin require 'simplecov' SimpleCov.start do add_filter "/spec/" add_group "Libraries", "lib" end rescue LoadError end require 'rspec' require 'distribution' module ExampleWithGSL def it_only_with_gsl(name,&block) it(name) do if Distribution.has_gsl? instance_eval(&block) else pending("Requires GSL") end end end def it_only_with_java(name,&block) it(name) do if Distribution.has_java? instance_eval(&block) else pending("Requires Java") end end end end distribution-0.7.0/spec/f_spec.rb0000644000175000017500000000461412061653751016344 0ustar boutilboutilrequire File.expand_path(File.dirname(__FILE__)+"/spec_helper.rb") include ExampleWithGSL describe Distribution::F do shared_examples_for "F engine(with rng)" do it "should return correct rng" do pending() end end shared_examples_for "F engine(with pdf)" do it_only_with_gsl "should return correct pdf" do if @engine.respond_to? :pdf [0.1,0.5,1,2,10,20,30].each{|f| [2,5,10].each{|n2| [2,5,10].each{|n1| @engine.pdf(f,n1,n2).should be_within(1e-4).of(GSL::Ran.fdist_pdf(f,n1,n2)) } } } else pending("No #{@engine}.pdf") end end end shared_examples_for "F engine" do it_only_with_gsl "should return correct cdf" do if @engine.respond_to? :cdf [0.1,0.5,1,2,10,20,30].each{|f| [2,5,10].each{|n2| [2,5,10].each{|n1| @engine.cdf(f,n1,n2).should be_within(1e-4).of(GSL::Cdf.fdist_P(f,n1,n2)) } } } else pending("No #{@engine}.cdf") end end it_only_with_gsl "should return correct p_value" do if @engine.respond_to? :p_value [0.1,0.5,1,2,10,20,30].each{|f| [2,5,10].each{|n2| [2,5,10].each{|n1| area=@engine.cdf(f,n1,n2) @engine.p_value(area,n1,n2).should be_within(1e-4).of(GSL::Cdf.fdist_Pinv(area,n1,n2)) } } } else pending("No #{@engine}.p_value") end end end describe "singleton" do before do @engine=Distribution::F end it_should_behave_like "F engine" it_should_behave_like "F engine(with pdf)" end describe Distribution::F::Ruby_ do before do @engine=Distribution::F::Ruby_ end it_should_behave_like "F engine" it_should_behave_like "F engine(with pdf)" end if Distribution.has_gsl? describe Distribution::F::GSL_ do before do @engine=Distribution::F::GSL_ end it_should_behave_like "F engine" it_should_behave_like "F engine(with pdf)" end end if Distribution.has_statistics2? describe Distribution::F::Statistics2_ do before do @engine=Distribution::F::Statistics2_ end it_should_behave_like "F engine" end end if Distribution.has_java? describe Distribution::F::Java_ do before do @engine=Distribution::F::Java_ end it_should_behave_like "F engine" it_should_behave_like "F engine(with pdf)" end end end distribution-0.7.0/benchmark/0000755000175000017500000000000012061653751015553 5ustar boutilboutildistribution-0.7.0/benchmark/binomial_coefficient/0000755000175000017500000000000012061653751021703 5ustar boutilboutildistribution-0.7.0/benchmark/binomial_coefficient/experiment.rb0000644000175000017500000000275512061653751024421 0ustar boutilboutil# This test create a database to adjust the best algorithm # to use on correlation matrix $:.unshift(File.expand_path(File.dirname(__FILE__)+"/../../lib")) require 'distribution' require 'statsample' require 'benchmark' if !File.exists?("binomial_coefficient.ds") or File.mtime(__FILE__) > File.mtime("binomial_coefficient.ds") reps=100 #number of repetitions ns={ 5=> [1,3], 10=> [1,3,5], 50=> [1,3,5,10,25], 100=> [1,3,5,10,25,50], 500=> [1,3,5,10,25,50,100,250], 1000=> [1,3,5,10,25,50,100,250,500], 5000=> [1,3,5,10,25,50,100,250,500,1000,2500], 10000=>[1,3,5,10,25,50,100,250,500,1000,2500,5000] } rs=Statsample::Dataset.new(%w{n k mixed_factorial multiplicative}) ns.each do |n,ks| ks.each do |k| time_factorial= Benchmark.realtime do reps.times { (((n-k+1)..n).inject(1) {|ac,v| ac * v}).quo(Math.factorial(k)) } end time_multiplicative= Benchmark.realtime do reps.times { (1..k).inject(1) {|ac, i| (ac*(n-k+i).quo(i))} } end puts "n:#{n}, k:#{k} -> factorial:%0.3f | multiplicative: %0.3f " % [time_factorial, time_multiplicative] rs.add_case({'n'=>n,'k'=>k,'mixed_factorial'=>time_factorial, 'multiplicative'=>time_multiplicative}) end end else rs=Statsample.load("binomial_coefficient.ds") end rs.fields.each {|f| rs[f].type=:scale} rs.update_valid_data rs.save("binomial_coefficient.ds") Statsample::Excel.write(rs,"binomial_coefficient.xls")distribution-0.7.0/benchmark/binomial_coefficient/binomial_coefficient.ds0000644000175000017500000000652312061653751026371 0ustar boutilboutilo:Statsample::Dataset : @nameI"Dataset 1:ET: @fields[ I"n;FI"k;FI"mixed_factorial;FI"multiplicative;F: @vectors{ I"n;Fu:Statsample::Vector${ I" data:EF[=i i iiii7i7i7i7i7iiiiiiiiiiiiiєiєiєiєiєiєiєiєiшiшiшiшiшiшiшiшiшiˆiˆiˆiˆiˆiˆiˆiˆiˆiˆiˆi'i'i'i'i'i'i'i'i'i'i'i'I"missing_values;F[I" labels;F{I" type;F: scaleI" name;FI" Vector 1;FI"k;Fu; ш{ I" data:EF[=iiiii iii iiiii iii7iii iii7iiiњiii iii7iiiњiєiii iii7iiiњiєiшiФ iii iii7iiiњiєiшiФ iˆI"missing_values;F[I" labels;F{I" type;F: scaleI" name;FI" Vector 2;FI"mixed_factorial;Fu; +{ I" data:EF[=f0.0005848407745361328f0.0008199214935302734f0.0005037784576416016f0.0008032321929931641f0.0010831356048583984f0.00049591064453125f0.0007839202880859375f0.001169443130493164f0.0018410682678222656f0.007485628128051758f0.0005395412445068359f0.0007987022399902344f0.0011131763458251953f0.0021491050720214844f0.00490260124206543f0.053803443908691406f0.0005381107330322266f0.0007991790771484375f0.0011074542999267578f0.0018732547760009766f0.004754781723022461f0.040105342864990234f0.11306977272033691f0.2937960624694824f0.0005099773406982422f0.0007784366607666016f0.0010867118835449219f0.0018830299377441406f0.0047130584716796875f0.039388179779052734f0.11153721809387207f0.2952287197113037f0.619046688079834f0.0005393028259277344f0.0008382797241210938f0.0011820793151855469f0.0020835399627685547f0.005173683166503906f0.05453968048095703f0.12773418426513672f0.2986032962799072f0.660742998123169f1.3285834789276123f4.752197980880737f0.0005733966827392578f0.0007886886596679688f0.0014104843139648438f0.0016720294952392578f0.005021572113037109f0.05472850799560547f0.1143183708190918f0.29619503021240234f0.6801633834838867f1.381115198135376f5.082608222961426f14.778673648834229I"missing_values;F[I" labels;F{I" type;F: scaleI" name;FI" Vector 3;FI"multiplicative;Fu; &{ I" data:EF[=f0.00047326087951660156f0.00119781494140625f0.00046706199645996094f0.0007853507995605469f0.0011129379272460938f0.0004639625549316406f0.0007953643798828125f0.0010991096496582031f0.0018818378448486328f0.018336057662963867f0.0005133152008056641f0.0008594989776611328f0.0011301040649414062f0.0021452903747558594f0.006609916687011719f0.029898643493652344f0.00046563148498535156f0.0008807182312011719f0.0011165142059326172f0.002197265625f0.024567842483520508f0.04833674430847168f0.09071612358093262f0.2599635124206543f0.00045490264892578125f0.0007786750793457031f0.0010988712310791016f0.002362489700317383f0.02189493179321289f0.05181241035461426f0.0947723388671875f0.2730567455291748f0.5700416564941406f0.0004899501800537109f0.0008633136749267578f0.0012662410736083984f0.017019987106323242f0.012119531631469727f0.03869891166687012f0.10341310501098633f0.29678893089294434f0.7340238094329834f1.8076701164245605f5.4109532833099365f0.00045609474182128906f0.0008265972137451172f0.0011692047119140625f0.002863168716430664f0.02634263038635254f0.03903698921203613f0.1197059154510498f0.3108999729156494f0.7560126781463623f1.8730740547180176f6.595805406570435f15.579787731170654I"missing_values;F[I" labels;F{I" type;F: scaleI" name;FI" Vector 4;F:@i0: @casesi=distribution-0.7.0/benchmark/binomial_coefficient/binomial_coefficient.xls0000644000175000017500000002100012061653751026554 0ustar boutilboutilаЯрЁБс;ўџ  ўџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџ Л ЬBАa==@ 8х"Зк1ШџArial1Ш МArial ЄGENERALрЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄ Р рЄ Р рЄ Р “€џ…Й Worksheet1ќ3nkmixed_factorialmultiplicativeџ | Л ЬBАa==@ 8х"Зк1ШџArial1Ш МArial ЄGENERALрЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄѕџ Р рЄ Р рЄ Р рЄ Р “€џ…Й Worksheet1ќ3nkmixed_factorialmultiplicativeџ | Л Ь d_€%ђСU}  9ђ€€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ ђ€ ђ€ ђ€ ђ€ ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€ђ€§ § § § Н*C???НоJ? S?Н*‚@?œ>?Н*RJ?МI?Н*ПQ??НЪАI?J?НЪ)S?R?Н Ъ* *^? е^?Н Ъf @Љ~? АЦ’?Н ’ ЎA? в@?Н ’ ,J? *L?Н ’ =R? „R?Н’*›a?“a?Н’fРt?{?Н’Ъ ŒЋ?Рž?НвЂA?„>?Нв0J?мL?Нв%R?KR?Нв*Б^?b?НвfРys?P(™?НвЪАˆЄ?˜ПЈ?Нв’$ђМ?,9З?НвъŽЭв?>Ѓа?НЂЖ@?а=?НЂ‚I?„I?НЂЮQ?R?НЂ*к^?€Zc?НЂfNs? k–?НЂЪА*Є?(‡Њ?НЂ’ДМ?CИ? ђ€!ђ€"ђ€#ђ€$ђ€%ђ€&ђ€'ђ€(ђ€)ђ€*ђ€+ђ€,ђ€-ђ€.ђ€/ђ€0ђ€1ђ€2ђ€3ђ€4ђ€5ђ€6ђ€7ђ€8ђ€Н Ђъ хв? Уyб?Н!Ђв!;Яу?!Ш=т?Н""N"ЌA?"@?Н#"N#xK?#JL?Н$"N$^S?$ПT?Н%"N*%€a?%Аm‘?Н&"Nf&1u?& вˆ?Н'"NЪ' ьЋ?'XаЃ?Н("N’(˜YР?(HyК?Н)"Nъ)Qг?)—ўв?Н*"Nв*€Ю$х?*€}ч?Н+"NЂ+РрAѕ?+€7ьќ?Н,"N',0@@,№аЄ@Н-Bœ-ЪB?-ф=?Н.Bœ.иI?.K?Н/Bœ/W?/(S?Н0Bœ*0e[?0€tg?Н1Bœf1€‘t?1љš?Н2BœЪ2`Ќ?2ЈќЃ?Н3Bœ’3јCН?3 ЅО?Н4Bœъ4мєв?4Щхг?Н5Bœв5цУх?5€A1ш?Н6BœЂ6@ і?6€ј§?Н7Bœ'7@—T@7аb@Н8Bœ"N8PЎŽ-@8№й(/@>Ж Root EntryџџџџџџџџЙWorkbookџџџџџџџџџџџџZпы2СЫZпы2СЫџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџўџџџ ўџџџўџџџўџџџ§џџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџdistribution-0.7.0/benchmark/factorial_hash.rb0000644000175000017500000000105212061653751021045 0ustar boutilboutil$:.unshift(File.expand_path(File.dirname(__FILE__)+"/../lib")) require 'bench_press' require 'distribution' extend BenchPress name 'calculate factorial vs looking on a Hash' author 'Claudio Bustos' date '2011-01-31' summary " Is better create a lookup table for factorial or just calculate it? Distribution::MathExtension::SwingFactorial has a lookup table for factorials n<20 " reps 1000 #number of repetitions measure "Lookup" do Math.factorial(19) end measure "calculate" do Distribution::MathExtension::SwingFactorial.naive_factorial(19) end distribution-0.7.0/benchmark/binomial_coefficient.rb0000644000175000017500000000225712061653751022236 0ustar boutilboutil$:.unshift(File.expand_path(File.dirname(__FILE__)+"/../lib")) require 'distribution' require 'bench_press' extend BenchPress samples=10.times.map {|i| 2**(i+1)} name 'binomial coefficient: multiplicative, factorial and optimized factorial methods' author 'Claudio Bustos' date '2011-01-27' summary "Exact calculation of Binomial Coefficient could be obtained using multiplicative, pure factorial or optimized factorial algorithm (failing + factorial). Which one is faster? Lower k is the best for all k=n/2 is the worst case. The factorial method uses the fastest Swing Prime Algorithm." reps 10 #number of repetitions x=100 n=100 k=50 measure "Multiplicative" do samples.each do |n| [5,n/2].each do |k| k=[k,n-k].min (1..k).inject(1) {|ac, i| (ac*(n-k+i).quo(i))} end end end measure "Pure Factorial" do samples.each do |n| [5,n/2].each do |k| k=[k,n-k].min Math.factorial(n).quo(Math.factorial(k) * Math.factorial(n - k)) end end end measure "Failing factorial + factorial" do samples.each do |n| [5,n/2].each do |k| k=[k,n-k].min (((n-k+1)..n).inject(1) {|ac,v| ac * v}).quo(Math.factorial(k)) end end end distribution-0.7.0/benchmark/power.rb0000644000175000017500000000102212061653751017227 0ustar boutilboutilrequire 'bench_press' require 'bigdecimal' extend BenchPress name 'Float vs Rational power' author 'Claudio Bustos' date '2011-02-02' summary " On ruby, the maximum size of a float is #{Float::MAX}. With Rational, we can raise to integer numbers and surpass Float maximum. What is the speed reduction using Rational?" reps 1000 #number of repetitions int=10 rat=10.quo(1) bd=BigDecimal("10") measure "Using float pow" do int**307 end measure "Using rational" do rat**307 end measure "Using big decimal pow" do bd**307 end distribution-0.7.0/benchmark/factorial_method.rb0000644000175000017500000000117012061653751021403 0ustar boutilboutil$:.unshift(File.dirname(__FILE__)+"/../lib") require 'distribution' require 'bench_press' extend BenchPress name 'aprox vs exact factorization method' author 'Claudio Bustos' date '2011-01-27' summary " Factorization requires a lot of processing, so approximation method could be required. But for greats value, bigdecimal are required and things start to get harder. * Approximation (fast_factorial): Luschny f.3 * Exact (factorial): Luschny Swing Prime " reps 10 #number of repetitions x=200 measure "Math.factorial(#{x})" do Math.factorial(x) end measure "Math.fast_factorial(#{x})" do Math.fast_factorial(x) end distribution-0.7.0/benchmark/odd.rb0000644000175000017500000000044412061653751016650 0ustar boutilboutil require 'bench_press' extend BenchPress name 'n&1==1 vs n%2==1 to detect odd numbers' author 'Claudio Bustos' date '2011-01-28' summary " Which is faster, n%1==1 or n%2==1 " reps 10_000 #number of repetitions n=100000 measure "Using &" do n%1==1 end measure "Using %" do n%2==1 end distribution-0.7.0/data.tar.gz.sig0000644000175000017500000000040012061653751016434 0ustar boutilboutil$ ЁRfТwтЊRdчлд‹U–ЪщЖм=ŽW.БwХfеІЪfчѓMr‚ ϘLэP '{YљbФ›еlБЛy–ЦФ;9ssЙ1)Dђю a<ЗО ` ;L‰IW\ГXF›ЦИŸ sb/cі‚]єGх…ј!фѓгЎї кЂ'Т[GUvцdаІЊ7Ў№–t\HХ‚ž{–ж0Y#}-ŽД­YfЬ&ЁУоSЙ[gL1nБІ љ[щuiЕW$E’ээпyЩ5Ÿ*ќСэU|АМŽЏ ЯQ…+m ђv€СSб