monte_carlo 0.0.1
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 +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +7 -0
- data/lib/monte_carlo.rb +8 -0
- data/lib/monte_carlo/errors.rb +7 -0
- data/lib/monte_carlo/experiment.rb +46 -0
- data/lib/monte_carlo/experiment_results.rb +53 -0
- data/lib/monte_carlo/result.rb +22 -0
- data/lib/monte_carlo/version.rb +3 -0
- data/monte_carlo.gemspec +25 -0
- data/spec/lib/monte_carlo/experiment_results_spec.rb +52 -0
- data/spec/lib/monte_carlo/experiment_spec.rb +47 -0
- data/spec/spec_helper.rb +8 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ba714d8eb65cabff56fc508ab075c62e0afaf188
|
4
|
+
data.tar.gz: 0b5910159859348ebab617e7abc1ccb9e23ce18d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 944b151e94f22a06db7ff167ee71897ea57436448c7e37dcf7dfcb0440e0aa34e050264183f2e03e5ae6d428b4a86820dd0c156fb5176d16c542e22453ed3596
|
7
|
+
data.tar.gz: c2aae5f7d6a5ddafcbbea7bf54995d2180f6c0a1e7144541cffcbb1c61090ee99fc9a697adabe6f6cdb9d1cf340cdf7c0b0ff32e4d855776cf5efd7bc62ffe3e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Assaf Gelber
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# MonteCarlo
|
2
|
+
|
3
|
+
A utility to write quick [Monte Carlo Method](http://en.wikipedia.org/wiki/Monte_Carlo_method) experiments.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'monte_carlo'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install monte_carlo
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Each experiment conatins:
|
24
|
+
- `times`: the number of sample to create (defaults to 10,000)
|
25
|
+
- `sample_method`: the method with which to generate a sample each iteration
|
26
|
+
- `computation`: an optional coputation method to run on each sample to obtain a result
|
27
|
+
|
28
|
+
For example;
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# Create an experiment with an optional number of times
|
32
|
+
experiment = MonteCarlo::Experiment.new(100000)
|
33
|
+
|
34
|
+
# Set your smaple method
|
35
|
+
experiment.sample_method = -> { rand }
|
36
|
+
|
37
|
+
# Set your optional computation method
|
38
|
+
experiment.computation = -> (sample) { sample > 0.5 }
|
39
|
+
|
40
|
+
# Run your experiment and get your results
|
41
|
+
results = experiment.run
|
42
|
+
```
|
43
|
+
|
44
|
+
Alternatively, you can write your sample and computation method as one with the shorthand block syntax:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
results = MonteCarlo::Experiment.run(100000) { rand > 0.5 }
|
48
|
+
```
|
49
|
+
|
50
|
+
The experiment returns a `MonteCarlo::ExperimentResults` object which contains an array of `MonteCarlo::Results` as well as some other handy methods.
|
51
|
+
|
52
|
+
Each `MonteCarlo::Result` contains:
|
53
|
+
- `index`: the index of the sample
|
54
|
+
- `value`: the final value returned from sampling, after computation
|
55
|
+
- `sample_value`: the value returned from the sample method, before computation
|
56
|
+
|
57
|
+
If no computation method was given, `value` and `sample_value` will be the same.
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
1. Fork it ( https://github.com/[agelber]/monte_carlo/fork )
|
62
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
63
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
64
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
65
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/monte_carlo.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module MonteCarlo
|
2
|
+
class Experiment
|
3
|
+
|
4
|
+
DEFAULT_TIMES = 10000
|
5
|
+
|
6
|
+
attr_accessor :times, :sample_method, :computation
|
7
|
+
|
8
|
+
def self.run(times = DEFAULT_TIMES, &block)
|
9
|
+
MonteCarlo::Experiment.new(times, &block).run
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(times = DEFAULT_TIMES, &block)
|
13
|
+
@times = times
|
14
|
+
@sample_method = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
if @sample_method.nil?
|
19
|
+
raise MonteCarlo::Errors::NoSampleMethodError, 'A sample method for this experiment is not defined'
|
20
|
+
end
|
21
|
+
|
22
|
+
results = MonteCarlo::ExperimentResults.new
|
23
|
+
|
24
|
+
@times.times do |index|
|
25
|
+
results << run_sample(index)
|
26
|
+
end
|
27
|
+
|
28
|
+
results
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def run_sample(index)
|
34
|
+
result = MonteCarlo::Result.new(index)
|
35
|
+
result.sample_value = @sample_method.call()
|
36
|
+
if @computation.nil?
|
37
|
+
result.value = result.sample_value
|
38
|
+
else
|
39
|
+
result.value = @computation.call(result.sample_value)
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module MonteCarlo
|
2
|
+
class ExperimentResults
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@results = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def each(&block)
|
10
|
+
@results.each do |result|
|
11
|
+
block_given? ? block.call(result) : yield(result)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def << result
|
16
|
+
@results << result
|
17
|
+
reset_memoizers
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
@results.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def probability_distribution
|
25
|
+
@probability_distribution ||= @results.group_by(&:value).inject({}) do |probabilites, (value, results)|
|
26
|
+
probabilites[value] = results.size.to_f / self.size
|
27
|
+
probabilites
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def frequency_distribution
|
32
|
+
@frequency_distribution ||= @results.group_by(&:value).inject({}) do |frequencies, (value, results)|
|
33
|
+
frequencies[value] = results.size
|
34
|
+
frequencies
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def probability_of(value)
|
39
|
+
probability_distribution.fetch(value, 0)
|
40
|
+
end
|
41
|
+
|
42
|
+
def frequency_of(value)
|
43
|
+
frequency_distribution.fetch(value, 0)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def reset_memoizers
|
49
|
+
@probability_distribution = nil
|
50
|
+
@frequency_distribution = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module MonteCarlo
|
2
|
+
class Result
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_accessor :value, :sample_value, :index
|
6
|
+
|
7
|
+
def initialize(index = nil, value = nil, sample_value = nil)
|
8
|
+
@value = value
|
9
|
+
@sample_value = sample_value
|
10
|
+
@index = index
|
11
|
+
end
|
12
|
+
|
13
|
+
def <=> other
|
14
|
+
self.to_i <=> other.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_i
|
18
|
+
@value
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/monte_carlo.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'monte_carlo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "monte_carlo"
|
8
|
+
spec.version = MonteCarlo::VERSION
|
9
|
+
spec.authors = ["Assaf Gelber"]
|
10
|
+
spec.email = ["assaf.gelber@gmail.com"]
|
11
|
+
spec.summary = %q{A small gem to help with Monte Carlo Method experiments in ruby.}
|
12
|
+
spec.description = %q{A small gem to help with Monte Carlo Method experiments in ruby.}
|
13
|
+
spec.homepage = "https://github.com/agelber/monte_carlo"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
24
|
+
spec.add_development_dependency "rspec-its"
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MonteCarlo::ExperimentResults do
|
4
|
+
|
5
|
+
let(:times) { 99 }
|
6
|
+
let(:results) do
|
7
|
+
results = MonteCarlo::ExperimentResults.new
|
8
|
+
times.times do |index|
|
9
|
+
results << MonteCarlo::Result.new(index, index % 3 == 0)
|
10
|
+
end
|
11
|
+
results
|
12
|
+
end
|
13
|
+
|
14
|
+
shared_examples_for :of_methdds do |method|
|
15
|
+
it 'returns 0 when the value does not exist' do
|
16
|
+
expect(results.send(method, 'does not exist')).to eq 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe :probability_distribution do
|
21
|
+
it 'should return the correct probability distribution for the results' do
|
22
|
+
expect(results.probability_distribution.keys).to contain_exactly(true, false)
|
23
|
+
expect(results.probability_distribution[true]).to eq 1 / 3.0
|
24
|
+
expect(results.probability_distribution[false]).to eq 2 / 3.0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :frequency_distribution do
|
29
|
+
it 'should return the correct frequency distribution for the results' do
|
30
|
+
expect(results.frequency_distribution.keys).to contain_exactly(true, false)
|
31
|
+
expect(results.frequency_distribution[true]).to eq 33
|
32
|
+
expect(results.frequency_distribution[false]).to eq 66
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe :probability_of do
|
37
|
+
it_behaves_like :of_methdds, :probability_of
|
38
|
+
|
39
|
+
it 'should return the correct probability of a value' do
|
40
|
+
expect(results.probability_of(true)).to eq 1 / 3.0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe :frequency_of do
|
45
|
+
it_behaves_like :of_methdds, :frequency_of
|
46
|
+
|
47
|
+
it 'should return the correct frequency of a value' do
|
48
|
+
expect(results.frequency_of(true)).to eq 33
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MonteCarlo::Experiment do
|
4
|
+
|
5
|
+
let(:times) { 1000 }
|
6
|
+
let(:sample_value) { 1 }
|
7
|
+
let(:computation) { -> (sample) {sample * 2} }
|
8
|
+
let(:experiment) do
|
9
|
+
experiment = MonteCarlo::Experiment.new
|
10
|
+
experiment.times = 1000
|
11
|
+
experiment.sample_method = -> { sample_value }
|
12
|
+
experiment.computation = computation
|
13
|
+
experiment
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :run do
|
17
|
+
it 'should raise a NoSampleMethodError if a sample method is not defined' do
|
18
|
+
experiment.sample_method = nil
|
19
|
+
expect {
|
20
|
+
experiment.run
|
21
|
+
}.to raise_error MonteCarlo::Errors::NoSampleMethodError
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should call the sample_method the correct number of times' do
|
25
|
+
sample_double = double(call: sample_value)
|
26
|
+
experiment.sample_method = sample_double
|
27
|
+
expect(sample_double).to receive(:call).exactly(times).times
|
28
|
+
experiment.run
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return an array of result objects' do
|
32
|
+
results = experiment.run
|
33
|
+
expect(results).to all( be_a MonteCarlo::Result )
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return results with correct sample values' do
|
37
|
+
results = experiment.run
|
38
|
+
expect(results.map(&:sample_value)).to all( eq sample_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return results with correct values' do
|
42
|
+
results = experiment.run
|
43
|
+
expect(results.map(&:value)).to all( eq computation.call(sample_value))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: monte_carlo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Assaf Gelber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-its
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: A small gem to help with Monte Carlo Method experiments in ruby.
|
70
|
+
email:
|
71
|
+
- assaf.gelber@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/monte_carlo.rb
|
82
|
+
- lib/monte_carlo/errors.rb
|
83
|
+
- lib/monte_carlo/experiment.rb
|
84
|
+
- lib/monte_carlo/experiment_results.rb
|
85
|
+
- lib/monte_carlo/result.rb
|
86
|
+
- lib/monte_carlo/version.rb
|
87
|
+
- monte_carlo.gemspec
|
88
|
+
- spec/lib/monte_carlo/experiment_results_spec.rb
|
89
|
+
- spec/lib/monte_carlo/experiment_spec.rb
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
homepage: https://github.com/agelber/monte_carlo
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.4.2
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: A small gem to help with Monte Carlo Method experiments in ruby.
|
115
|
+
test_files:
|
116
|
+
- spec/lib/monte_carlo/experiment_results_spec.rb
|
117
|
+
- spec/lib/monte_carlo/experiment_spec.rb
|
118
|
+
- spec/spec_helper.rb
|