erv 0.0.2 → 0.2.0

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