erv 0.0.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0116fa6cb4d3e6b11d3602ed2608b6b60a90f717
4
- data.tar.gz: aac7790d8d9f9ab82e5ed0c70157cc7e95ef3398
3
+ metadata.gz: 4df7f1fe74e08a93b0011dbce05db2862db6f742
4
+ data.tar.gz: bef0cb26a91b1353971c3d2f1de8cc071832b60b
5
5
  SHA512:
6
- metadata.gz: 94cc7f3280ae54020481e86d0e1caa181b539b0d8d6ca31e436e0eb4ed6ff0c12d000b9fc8443e32cb137aec706ef3b2831b1676d1751959c1c333cf72035ab4
7
- data.tar.gz: 5fb06905713c33f6fd563849c7c44ceae643a272cc52250a4a41cdaa6c01a9a79e334abe1d679a13ce833820e4b58b045f68d3b619d8fd123e6fbbd806a01904
6
+ metadata.gz: 85bc816dcaf649c8410138ddcb3496d449c701e9f847d842139c59c8e17a5f0e97b857ca362845c7365138afe0b524902bbdfd1eb060aa4151b03246582b1298
7
+ data.tar.gz: 4308c0e5862acb574b6adb771998e95459f19dc929749716f55118ac068246f319be8bcd3a801ee36d6aaa2a812a6c94ed08f41efcb7568773624c4a0a1c95b5
data/README.md CHANGED
@@ -10,31 +10,13 @@ variables with a given probability distribution (gaussian, uniform, etc.) and
10
10
  to sample from them. ruby-erv was built from code that I extracted out of
11
11
  several scientific software I wrote for my research projects.
12
12
 
13
- ruby-erv is designed to work on both YARV/MRI and JRuby. I have not tested it
14
- on Rubinius yet.
15
-
16
13
 
17
14
  ## Installation
18
15
 
19
- I have not released ruby-erv on RubyGems, yet. For the moment, if you want to
20
- try it just place this line:
21
-
22
- ```ruby
23
- gem 'erv', git: 'https://github.com/mtortonesi/ruby-erv.git'
24
- ```
25
-
26
- in your Gemfile and run:
27
-
28
- bundle install
29
-
30
- If using JRuby, you'll also need to run:
31
-
32
- rake get_latest_commons_math_snapshot
16
+ You can get the stable version of ruby-erv by installing the erv gem from
17
+ RubyGems:
33
18
 
34
- to fetch the latest version of Apache Commons Math 3.3-SNAPSHOT. See the
35
- [implementation notes below](#implementation-notes) for more information. (Note
36
- that the rake-based installation of Apache Commons Math 3.3-SNAPSHOT requires
37
- [nokogiri](http://nokogiri.org/).)
19
+ gem install erv
38
20
 
39
21
 
40
22
  ## Examples
@@ -45,49 +27,39 @@ variables using ruby-erv, and how to sample from them:
45
27
  ```ruby
46
28
  require 'erv'
47
29
 
30
+ # Gaussian random variable with mean 10 and standard deviation 2
48
31
  gaussian_rv = ERV::RandomVariable.new(distribution: :gaussian,
49
32
  mean: 10, sd: 2)
50
33
  s1 = gaussian_rv.sample
34
+
35
+ # Geometric random variable with probability of success 0.3
36
+ geometric_rv = ERV::RandomVariable.new(distribution: :geometric,
37
+ probability_of_success: 0.3)
38
+ s2 = geometric_rv.sample
39
+ ```
40
+
41
+ Starting from version 0.2.0, ruby-erv also supports mixture models. Here is a
42
+ simple example of how to create a random variable with an exponential mixture
43
+ distribution:
44
+
45
+ ```ruby
46
+ require 'erv'
47
+
48
+ emd = ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 100.0 },
49
+ { distribution: :exponential, rate: 2.0, weight: 200.0 },
50
+ { distribution: :exponential, rate: 3.0, weight: 300.0 } ])
51
+ s3 = emd.sample
51
52
  ```
52
53
 
53
54
 
54
55
  ## Implementation notes
55
56
 
56
- In YARV/MRI, ruby-erv leverages the GNU Scientific Library (GSL) for random
57
- number generation according to the desired probability distribution.
58
- Unfortunately, ruby-gsl is unmaintained and broken. (See [the
59
- patch](http://rubyforge.org/tracker/?func=detail&atid=1169&aid=29353&group_id=285)
60
- that I sent them ages ago and that was never merged.) So, ruby-erv uses the
61
- [gsl-nmatrix](https://github.com/SciRuby/rb-gsl) fork of ruby-gsl.
62
-
63
- In JRuby, ruby-erv leverages the [Apache Commons
64
- Math](http://commons.apache.org/proper/commons-math/) library to access the
65
- same random number generation functions. Unfortunately, at the time of this
66
- writing the Apache Commons Math maintainers have not shipped the 3.3 release
67
- yet. Commons Math 3.3 should include support for geometric distribution (that I
68
- need for several of my projects), thanks to [a
69
- patch](https://issues.apache.org/jira/browse/MATH-973) that I submitted and
70
- that was merged some time ago. So, for the moment ruby-env builds on top of the
71
- 3.3-SNAPSHOT version of Apache Commons Math.
72
-
73
- To facilitate the installation of ruby-env under JRuby, I have decided to
74
- bundle the jar archive of Apache Commons Math 3.3-SNAPSHOT in (the jars
75
- directory of) the ruby-env gem package. This is a rather dirty but not uncommon
76
- approach, as many other gems (including the awesome
77
- [Nokogiri](https://github.com/sparklemotion/nokogiri/tree/master/lib)) bundle
78
- external jar dependencies in their JRuby version. However, in future I might
79
- decide to switch to a more powerful, Maven-based automated installation of
80
- Apache Commons Math 3.3-SNAPSHOT. For instance, based on Christian Meier's
81
- [jar-dependencies](https://github.com/mkristian/jar-dependencies).
82
-
83
-
84
- ## Acknowledgment
85
-
86
- I would like to thank [Christian Meier](https://github.com/mkristian) for his
87
- very valuable suggestions on how to package this gem for JRuby. If you're
88
- interested in building serious applications for JRuby, I strongly recommend you
89
- to check out Christian's [jbundler](https://github.com/mkristian/jbundler) and
90
- [jar-dependencies](https://github.com/mkristian/jar-dependencies).
57
+ Starting from version 0.2.0, ruby-erv makes use of the standard (Pseudo) Random
58
+ Number Generator provided by Ruby VMs, which is a variant of the
59
+ Mersenne-Twister algorithm modified to have a period of 2<sup>19937</sup>-1.
60
+ The randomness provided by Ruby's PRNG, whose adoption significantly improved
61
+ ruby-erv's portability to different Ruby VMs (MRI, JRuby, etc.), should be more
62
+ than enough for most purposes.
91
63
 
92
64
 
93
65
  ## License
data/Rakefile CHANGED
@@ -1,55 +1,11 @@
1
- if RUBY_PLATFORM =~ /java/
1
+ require 'bundler/gem_tasks'
2
2
 
3
- require 'lib/erv/version'
4
- require 'bundler/gem_helper'
5
-
6
- require 'nokogiri'
7
- require 'open-uri'
8
-
9
- # setup absolute path for jars directory
10
- JAR_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'jars'))
11
-
12
- directory JAR_DIR
13
-
14
- desc 'Get latest snapshot of Apache Commons Math 3.3'
15
- task :get_latest_commons_math_snapshot => [ JAR_DIR ] do
16
- # base URL of the apache commons math 3 snapshot repository
17
- BASE_URL = 'http://repository.apache.org/content/groups/snapshots/org/apache/commons/commons-math3/3.3-SNAPSHOT/'
18
-
19
- # retrieve timestamp and build number of latest snapshot
20
- puts 'Retrieving metadata information on latest Apache Commons Math 3.3 snapshot.'
21
- doc = Nokogiri::HTML(open(BASE_URL + 'maven-metadata.xml'))
22
- timestamp = doc.xpath('//timestamp/text()')
23
- buildnumber = doc.xpath('//buildnumber/text()')
24
-
25
- # get archive name of latest snapshot
26
- filename = "commons-math3-3.3-#{timestamp}-#{buildnumber}.jar"
27
-
28
- # get destination file name
29
- jar_path = File.join(JAR_DIR, filename)
30
-
31
- # don't download if file already exists
32
- if File.exists?(jar_path)
33
- puts 'Archive already present in jars directory.'
34
- else
35
- puts 'Retrieving latest Apache Commons Math 3.3 snapshot.'
36
- file_url = BASE_URL + filename
37
- File.write(jar_path, open(file_url).read)
38
- end
39
-
40
- # clean JAR_DIR of every file except filename
41
- puts 'Removing obsolete archives from jars directory.'
42
- FileUtils.rm(Dir.glob("#{JAR_DIR}/*").reject!{|file| file == jar_path })
43
- end
44
-
45
- desc "Build erv-#{ERV::VERSION}-java.gem into the pkg directory."
46
- task :build => [ :get_latest_commons_math_snapshot ] do
47
- Bundler::GemHelper.instance = Bundler::GemHelper.new
48
- Bundler::GemHelper.instance.build_gem
49
- end
50
-
51
- else # RUBY_PLATFORM !~ /java/
52
-
53
- require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
54
4
 
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ t.test_files = Dir.glob('test/**/*_test.rb').sort
8
+ t.verbose = true
55
9
  end
10
+
11
+ task :default => :test
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ * add specs
2
+ * documentation
data/erv.gemspec CHANGED
@@ -18,16 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency 'bundler', '~> 1.3'
22
- spec.add_development_dependency 'rake'
23
- spec.add_development_dependency 'rspec'
24
-
25
- if RUBY_PLATFORM =~ /java/
26
- # we need to release a JRuby-specific gem
27
- spec.platform = 'java'
28
- # include Apache Commons Math 3.3 jar archive
29
- spec.files.concat(Dir['jars/*.jar'])
30
- else
31
- spec.add_dependency 'gsl-nmatrix'
32
- end
21
+ spec.add_development_dependency 'bundler', '~> 1.14'
22
+ spec.add_development_dependency 'rake', '~> 12.0'
23
+ spec.add_development_dependency 'minitest', '~> 5.10'
24
+ spec.add_development_dependency 'minitest-reporters', '~> 1.1'
25
+ spec.add_development_dependency 'minitest-spec-context', '~> 0.0.3'
33
26
  end
@@ -7,8 +7,19 @@ module ERV
7
7
  super(opts)
8
8
 
9
9
  raise ArgumentError unless opts[:value]
10
- val = opts[:value].to_f
11
- @func = Proc.new { val }
10
+ @val = opts[:value].to_f
11
+ end
12
+
13
+ def mean
14
+ @val
15
+ end
16
+
17
+ def variance
18
+ 0.0
19
+ end
20
+
21
+ def sample
22
+ @val
12
23
  end
13
24
  end
14
25
 
@@ -1,15 +1,15 @@
1
- require 'erv/rng'
2
-
3
1
  module ERV
4
2
 
5
3
  class Distribution
6
4
  def initialize(opts)
7
- # create RNG object
8
- @rng = RNG.make_rng(opts[:seed])
9
- end
10
-
11
- def sample
12
- @func.call
5
+ # use provided RNG or create a new one
6
+ if opts[:rng]
7
+ @rng = opts[:rng]
8
+ elsif opts[:seed]
9
+ @rng = Random.new(opts[:seed])
10
+ else
11
+ @rng = Random.new
12
+ end
13
13
  end
14
14
  end
15
15
 
@@ -1,30 +1,28 @@
1
- if RUBY_PLATFORM == 'java'
2
- require 'java'
3
- JExponentialDistribution = org.apache.commons.math3.distribution.ExponentialDistribution
4
- end
5
-
6
1
  require 'erv/distribution'
2
+ require 'erv/support/try'
7
3
 
8
4
 
9
5
  module ERV
10
6
 
11
7
  class ExponentialDistribution < Distribution
8
+ attr_reader :mean, :variance
9
+
12
10
  def initialize(opts)
13
11
  super(opts)
14
12
 
15
- raise ArgumentError unless opts[:mean]
16
- mean = opts[:mean].to_f
17
-
18
- if RUBY_PLATFORM == 'java'
19
- # create distribution
20
- d = JExponentialDistribution.new(@rng, mean,
21
- JExponentialDistribution::DEFAULT_INVERSE_ABSOLUTE_ACCURACY)
22
- # setup sampling function
23
- @func = Proc.new { d.sample }
24
- else
25
- # setup sampling function
26
- @func = Proc.new { @rng.exponential(mean) }
27
- end
13
+ @rate = opts[:rate].try(:to_f)
14
+ raise ArgumentError unless @rate and @rate > 0.0
15
+
16
+ @mean = 1 / @rate
17
+ @variance = @mean ** 2
18
+ end
19
+
20
+ def sample
21
+ # starting from a random variable X ~ U(0,1), which is provided by the
22
+ # RNG, we can obtain a random variable Y ~ Exp(\lambda), with mean = 1 /
23
+ # \lambda, through the transformation: Y = - (1 / \lambda) ln X. see
24
+ # [GROESE11], section 4.2.3.
25
+ - @mean * Math.log(@rng.rand)
28
26
  end
29
27
  end
30
28
 
@@ -1,8 +1,3 @@
1
- if RUBY_PLATFORM == 'java'
2
- require 'java'
3
- java_import org.apache.commons.math3.distribution.NormalDistribution
4
- end
5
-
6
1
  require 'erv/distribution'
7
2
 
8
3
 
@@ -13,19 +8,28 @@ module ERV
13
8
  super(opts)
14
9
 
15
10
  raise ArgumentError unless opts[:mean] and opts[:sd]
16
- mean = opts[:mean].to_f
17
- sd = opts[:sd].to_f
18
-
19
- if RUBY_PLATFORM == 'java'
20
- # create distribution
21
- d = NormalDistribution.new(@rng, mean, sd,
22
- NormalDistribution::DEFAULT_INVERSE_ABSOLUTE_ACCURACY)
23
- # setup sampling function
24
- @func = Proc.new { d.sample }
25
- else
26
- # setup sampling function
27
- @func = Proc.new { mean + @rng.ran_gaussian(sd) }
28
- end
11
+ @mu = opts[:mean].to_f
12
+ @sigma = opts[:sd].to_f
13
+ end
14
+
15
+ def sample
16
+ # use box-muller algorithm (see [GROESE11], section 4.2.11, algorithm
17
+ # 4.47) to obtain x ~ N(0,1).
18
+ u_1 = @rng.rand
19
+ u_2 = @rng.rand
20
+ x = Math.sqrt(-2.0 * Math.log(u_1)) * Math.cos(2.0 * Math.PI * u_2)
21
+
22
+ # use location-scale transformation to obtain a N(\mu, \sigma^2)
23
+ # distribution. see [GROESE11], section 3.1.2.2.
24
+ @mu + @sigma * x
25
+ end
26
+
27
+ def mean
28
+ @mu
29
+ end
30
+
31
+ def variance
32
+ @sigma ** 2
29
33
  end
30
34
  end
31
35
 
@@ -0,0 +1,81 @@
1
+ require 'erv/constant_distribution'
2
+ require 'erv/discrete_uniform_distribution'
3
+ require 'erv/exponential_distribution'
4
+ require 'erv/gamma_distribution'
5
+ require 'erv/gaussian_distribution'
6
+ require 'erv/general_pareto_distribution'
7
+ require 'erv/geometric_distribution'
8
+ require 'erv/uniform_distribution'
9
+
10
+ module ERV
11
+
12
+ class MixtureDistribution
13
+ def initialize(confs, opts={})
14
+ raise ArgumentError, "Please, provide at least 2 distributions!" unless confs.length >= 2
15
+
16
+ @mixture = []
17
+ @weight_sum = 0.0
18
+ while dist_conf = confs.shift
19
+ # get weight ...
20
+ weight = dist_conf.delete(:weight).to_f
21
+
22
+ # ... and keep track of it
23
+ @weight_sum += weight
24
+
25
+ # get distribution name
26
+ dist_name = dist_conf.delete(:distribution).to_s
27
+
28
+ # get class name that corresponds to the requested distribution
29
+ klass_name = dist_name.split('_').push('distribution').map(&:capitalize).join
30
+
31
+ # create distribution object
32
+ distribution = ERV.const_get(klass_name).new(dist_conf)
33
+
34
+ # add distribution to mixture
35
+ @mixture << { weight: weight, distribution: distribution }
36
+ end
37
+
38
+ seed = opts[:seed]
39
+ @mixture_sampler = (seed ? Random.new(seed) : Random.new)
40
+ end
41
+
42
+ def sample
43
+ x = @mixture_sampler.rand
44
+
45
+ # find index of distribution we are supposed to sample from
46
+ i = 0
47
+ while x > (@mixture[i][:weight] / @weight_sum)
48
+ x -= (@mixture[i][:weight] / @weight_sum)
49
+ i += 1
50
+ end
51
+
52
+ # return sample
53
+ @mixture[i][:distribution].sample
54
+ end
55
+
56
+ def mean
57
+ @mean ||= calculate_mean
58
+ end
59
+
60
+ def variance
61
+ @variance ||= calculate_variance
62
+ end
63
+
64
+ private
65
+
66
+ def calculate_mean
67
+ @mixture.inject(0.0) do |s,x|
68
+ s += (x[:weight] / @weight_sum * x[:distribution].mean)
69
+ end
70
+ end
71
+
72
+ def calculate_variance
73
+ @mixture.inject(0.0) do |s,x|
74
+ s += (x[:weight] / @weight_sum *
75
+ ((x[:distribution].mean - self.mean) ** 2 +
76
+ x[:distribution].variance))
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -18,6 +18,7 @@ module ERV
18
18
 
19
19
  # get class name that corresponds to the requested distribution
20
20
  klass_name = dist_name.split('_').push('distribution').map(&:capitalize).join
21
+
21
22
  # create distribution object
22
23
  @dist = ERV.const_get(klass_name).new(opts)
23
24
  end
@@ -30,9 +31,9 @@ module ERV
30
31
 
31
32
  class SequentialRandomVariable
32
33
  def initialize(args)
33
- @first = args.delete(:first_value)
34
- @most_recent = @first || 0.0
35
- @var = RandomVariable.new(args)
34
+ first = args[:first_value]
35
+ @most_recent = first.nil? ? 0.0 : first
36
+ @var = RandomVariable.new(args.reject{|k,v| k == :first_value })
36
37
  end
37
38
 
38
39
  def next
@@ -1,8 +1,3 @@
1
- if RUBY_PLATFORM == 'java'
2
- require 'java'
3
- java_import org.apache.commons.math3.distribution.UniformRealDistribution
4
- end
5
-
6
1
  require 'erv/distribution'
7
2
  require 'erv/support/try'
8
3
 
@@ -15,18 +10,15 @@ module ERV
15
10
 
16
11
  raise ArgumentError unless opts[:max_value]
17
12
  max = opts[:max_value].to_f
18
- min = opts[:min_value].try(:to_f) || 0.0
13
+ @min = opts[:min_value].try(:to_f) || 0.0
14
+ @range = max - @min
15
+ end
19
16
 
20
- if RUBY_PLATFORM == 'java'
21
- # create distribution
22
- d = UniformRealDistribution.new(@rng, min, max,
23
- UniformRealDistribution::DEFAULT_INVERSE_ABSOLUTE_ACCURACY)
24
- # setup sampling function
25
- @func = Proc.new { d.sample }
26
- else
27
- # setup sampling function
28
- @func = Proc.new { @rng.flat(min, max) }
29
- end
17
+ def sample
18
+ # starting from a random variable X ~ U(0,1), which is provided by the
19
+ # RNG, we can obtain a random variable Y ~ U(a,b) through location-scale
20
+ # transformation: Y = a + (b-a) X. see [GROESE11], section 3.1.2.2.
21
+ @min + @range * @rng.rand
30
22
  end
31
23
  end
32
24
 
data/lib/erv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ERV
2
- VERSION = '0.0.2'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/erv.rb CHANGED
@@ -1,10 +1,2 @@
1
- # Load Apache Commons Math 3.3 jar if we're using JRuby
2
- if RUBY_PLATFORM =~ /java/
3
- JARS_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'jars'))
4
- Dir["#{JARS_DIR}/*.jar"].each do |jar|
5
- $CLASSPATH << jar unless $CLASSPATH.include?(jar)
6
- end
7
- end
8
-
9
1
  require 'erv/version'
10
2
  require 'erv/random_variable'
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'test_helper'
2
2
 
3
3
  require 'erv/constant_distribution'
4
4
 
@@ -7,21 +7,19 @@ describe ERV::ConstantDistribution do
7
7
  it 'should require a reference value' do
8
8
  lambda do
9
9
  ERV::ConstantDistribution.new
10
- end.should raise_error
10
+ end.must_raise ArgumentError
11
11
  end
12
12
 
13
13
  context 'reference value' do
14
14
 
15
15
  it 'should be accepted at initialization time' do
16
- lambda do
17
- ERV::ConstantDistribution.new(value: 10)
18
- end.should_not raise_error
16
+ ERV::ConstantDistribution.new(value: 10)
19
17
  end
20
18
 
21
19
  it 'should match the value returned by sampling' do
22
20
  val = rand(100)
23
21
  crv = ERV::ConstantDistribution.new(value: val)
24
- crv.sample.should == val
22
+ crv.sample.must_equal val
25
23
  end
26
24
 
27
25
  end
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ require 'erv/distribution'
4
+
5
+ describe ERV::Distribution do
6
+
7
+ context 'when explicitly given an RNG' do
8
+
9
+ it 'should use the given RNG' do
10
+ rng = Random.new
11
+ d = ERV::Distribution.new(rng: rng)
12
+ d.instance_variable_get(:@rng).must_equal rng
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ require 'erv/mixture_distribution'
4
+
5
+ describe ERV::MixtureDistribution do
6
+ it 'should require at least two distributions' do
7
+ lambda do
8
+ ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 0.5 } ])
9
+ end.must_raise ArgumentError
10
+ end
11
+
12
+ it 'should keep track of distribution weights (for normalization)' do
13
+ # create a mixture distribution with unnormalized weights
14
+ uw_md = ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 100.0 },
15
+ { distribution: :exponential, rate: 2.0, weight: 200.0 },
16
+ { distribution: :exponential, rate: 3.0, weight: 300.0 } ])
17
+ uw_md.instance_variable_get("@weight_sum").must_equal 600.0
18
+ end
19
+
20
+ let :md do
21
+ ERV::MixtureDistribution.new([ { distribution: :exponential, rate: 1.0, weight: 0.3 },
22
+ { distribution: :exponential, rate: 2.0, weight: 0.2 },
23
+ { distribution: :exponential, rate: 3.0, weight: 0.5 } ])
24
+ end
25
+
26
+ context 'sampling' do
27
+
28
+ it 'should allow sampling from the mixture' do
29
+ md.sample
30
+ end
31
+
32
+ end
33
+
34
+ context 'moments' do
35
+
36
+ let :expected_mean do
37
+ 0.3 * 1/1.0 + 0.2 * 1/2.0 + 0.5 * 1/3.0
38
+ end
39
+
40
+ let :expected_variance do
41
+ 0.3 * (1/1.0 - expected_mean) ** 2 + (1/1.0) ** 2 +
42
+ 0.2 * (1/2.0 - expected_mean) ** 2 + (1/2.0) ** 2 +
43
+ 0.5 * (1/3.0 - expected_mean) ** 2 + (1/3.0) ** 2
44
+ end
45
+
46
+ it 'should correctly calculate the mean of the mixture' do
47
+ md.mean.must_equal expected_mean
48
+ end
49
+
50
+ it 'should correctly calculate the variance of the mixture' do
51
+ md.mean.must_equal expected_mean
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ require 'erv/random_variable'
4
+
5
+ describe ERV::SequentialRandomVariable do
6
+
7
+ it 'should require the :first_value parameter' do
8
+ lambda do
9
+ ERV::SequentialRandomVariable.new
10
+ end.must_raise ArgumentError
11
+ end
12
+
13
+ it 'should consider starting value' do
14
+ first = 1.0
15
+ srv = ERV::SequentialRandomVariable.new(first_value: first, distribution: :exponential, rate: 2.0)
16
+ srv.next.must_be :>, first
17
+ end
18
+
19
+ it 'should consider previous sample' do
20
+ first = 1.0
21
+ srv = ERV::SequentialRandomVariable.new(first_value: first, distribution: :exponential, rate: 2.0)
22
+ previous_sample = srv.next
23
+ 10.times do
24
+ new_sample = srv.next
25
+ new_sample.must_be :>, previous_sample
26
+ previous_sample = new_sample
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,6 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/spec'
3
+ require 'minitest-spec-context'
4
+
5
+ require 'minitest/reporters'
6
+ Minitest::Reporters.use!
metadata CHANGED
@@ -1,72 +1,86 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mauro Tortonesi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-04 00:00:00.000000000 Z
11
+ date: 2017-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '1.14'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '1.14'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '12.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '12.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '5.10'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '5.10'
55
55
  - !ruby/object:Gem::Dependency
56
- name: gsl-nmatrix
56
+ name: minitest-reporters
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
61
+ version: '1.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-spec-context
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.3
76
+ type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - '>='
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '0'
69
- description: erv-0.0.2
82
+ version: 0.0.3
83
+ description: erv-0.2.0
70
84
  email:
71
85
  - mauro.tortonesi@unife.it
72
86
  executables: []
@@ -77,6 +91,7 @@ files:
77
91
  - LICENSE
78
92
  - README.md
79
93
  - Rakefile
94
+ - TODO
80
95
  - erv.gemspec
81
96
  - lib/erv.rb
82
97
  - lib/erv/constant_distribution.rb
@@ -87,13 +102,16 @@ files:
87
102
  - lib/erv/gaussian_distribution.rb
88
103
  - lib/erv/general_pareto_distribution.rb
89
104
  - lib/erv/geometric_distribution.rb
105
+ - lib/erv/mixture_distribution.rb
90
106
  - lib/erv/random_variable.rb
91
- - lib/erv/rng.rb
92
107
  - lib/erv/support/try.rb
93
108
  - lib/erv/uniform_distribution.rb
94
109
  - lib/erv/version.rb
95
- - spec/erv/constant_distribution_spec.rb
96
- - spec/spec_helper.rb
110
+ - test/erv/constant_distribution_test.rb
111
+ - test/erv/distribution_test.rb
112
+ - test/erv/mixture_distribution_test.rb
113
+ - test/erv/random_variable_test.rb
114
+ - test/test_helper.rb
97
115
  homepage: https://github.com/mtortonesi/ruby-erv
98
116
  licenses:
99
117
  - MIT
@@ -104,20 +122,23 @@ require_paths:
104
122
  - lib
105
123
  required_ruby_version: !ruby/object:Gem::Requirement
106
124
  requirements:
107
- - - '>='
125
+ - - ">="
108
126
  - !ruby/object:Gem::Version
109
127
  version: '0'
110
128
  required_rubygems_version: !ruby/object:Gem::Requirement
111
129
  requirements:
112
- - - '>='
130
+ - - ">="
113
131
  - !ruby/object:Gem::Version
114
132
  version: '0'
115
133
  requirements: []
116
134
  rubyforge_project:
117
- rubygems_version: 2.1.11
135
+ rubygems_version: 2.6.8
118
136
  signing_key:
119
137
  specification_version: 4
120
138
  summary: Easy/elegant Ruby library providing support for random variable generation
121
139
  test_files:
122
- - spec/erv/constant_distribution_spec.rb
123
- - spec/spec_helper.rb
140
+ - test/erv/constant_distribution_test.rb
141
+ - test/erv/distribution_test.rb
142
+ - test/erv/mixture_distribution_test.rb
143
+ - test/erv/random_variable_test.rb
144
+ - test/test_helper.rb
data/lib/erv/rng.rb DELETED
@@ -1,29 +0,0 @@
1
- if RUBY_PLATFORM == 'java'
2
- require 'java'
3
- java_import org.apache.commons.math3.random.MersenneTwister
4
- else
5
- require 'gsl'
6
- end
7
-
8
-
9
- module ERV
10
-
11
- class RNG
12
- def self.make_rng(seed = nil)
13
- # if not explicitly provided, seed is taken from the (lower quality)
14
- # pseudo-random Kernel::rand generator
15
- if RUBY_PLATFORM == 'java'
16
- # this is a somewhat ugly workaround in order to avoid ambibuities in
17
- # the constructor method that will be called (we basically explicit the
18
- # signature of the constructor that we want to use)
19
- constructor = org.apache.commons.math3.random.MersenneTwister.java_class.constructor(Java::long)
20
- rng = constructor.new_instance(seed || Kernel::rand(2**31 - 1))
21
- else
22
- rng = seed ?
23
- GSL::Rng.alloc(GSL::Rng::MT19937, seed) :
24
- GSL::Rng.alloc(GSL::Rng::MT19937, Kernel::rand(2**31 - 1))
25
- end
26
- end
27
- end
28
-
29
- end
data/spec/spec_helper.rb DELETED
@@ -1,20 +0,0 @@
1
- # This file was generated by the `rspec --init` command. Conventionally, all
2
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
- # Require this file using `require "spec_helper"` to ensure that it is only
4
- # loaded once.
5
-
6
- # Required to setup classpath for Apache Commons Math 3.3-SNAPSHOT in JRuby
7
- require 'erv'
8
-
9
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
- RSpec.configure do |config|
11
- config.treat_symbols_as_metadata_keys_with_true_values = true
12
- config.run_all_when_everything_filtered = true
13
- config.filter_run :focus
14
-
15
- # Run specs in random order to surface order dependencies. If you find an
16
- # order dependency and want to debug it, you can fix the order by providing
17
- # the seed, which is printed after each run.
18
- # --seed 1234
19
- config.order = 'random'
20
- end