simulator 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'guard-cucumber'
7
+ gem 'guard-rspec'
8
+ gem 'ruby_gntp'
9
+ gem 'pry'
10
+ end
11
+ group :test do
12
+ gem "rspec"
13
+ gem "rspec-expectations", "~>2.12.1"
14
+ gem "cucumber"
15
+ end
16
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jamie Ly
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,67 @@
1
+ # Simulator
2
+
3
+ Use to easily create models and view results across periods.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'simulator'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install simulator
18
+
19
+ ## Usage
20
+
21
+ See the features for some examples.
22
+
23
+ bundle exec cucumber
24
+
25
+ See the specs for some simpler examples.
26
+
27
+ bundle exec rspec
28
+
29
+ See the `examples` subdirectory for examples as well. Including the one
30
+ excerpted below:
31
+
32
+ ```ruby
33
+ # We create a model that simulates a ball drop
34
+ model = Simulator::Model.new do
35
+ name = "Ball drop model"
36
+ # create a couple static variables to represent acceleration with
37
+ # default values
38
+ var :ax, 0
39
+ var :ay, - 9.8
40
+
41
+ # create dynamic variables bound to some computation, with default
42
+ # values.
43
+
44
+ # velocity is affected by acceleration
45
+ eqtn(:vx, 20) { vx + ax }
46
+ eqtn(:vy, 50) { vy + ay }
47
+
48
+ # position is affected by velocity
49
+ eqtn(:x, 10) { x + vx }
50
+ eqtn(:y, 100) { y + vy }
51
+ end
52
+
53
+ # Run the model 10 periods
54
+ model_run = model.new_run
55
+ 10.times do
56
+ model_run.step
57
+ end
58
+
59
+ # retrieve the data
60
+ series = model_run.data.series :x, :y
61
+ puts series
62
+ # > [[30, 50, 70, 90, 110, 130, 150, 170, 190, 210, 210],
63
+ # > [140.2, 170.6, 191.2, 202.0, 203.0, 194.2, 175.6, 147.2, 108.99999999999999, 60.999999999999986, 60.999999999999986]]
64
+
65
+ # Then plot it or do whatever you like
66
+ ```
67
+
data/RELEASE.md ADDED
@@ -0,0 +1,31 @@
1
+ v0.1.2
2
+ ======
3
+ * Added detail to gemspec
4
+
5
+ v0.1.1
6
+ ======
7
+ * Added mortgage example
8
+
9
+ v0.1.0
10
+ ======
11
+ * First minor release
12
+ * Removes `puts` in `Model.rb`
13
+ * Alters beer_spec to use new var default syntax
14
+
15
+ v0.0.5
16
+ ======
17
+ * Added "bounce" example
18
+ * Added arg to pass default value of variable with eqtn call
19
+
20
+ v0.0.4
21
+ ======
22
+
23
+ v0.0.3
24
+ ======
25
+ * Added block parameter to Model instantiation to more easily create
26
+ variables and equations.
27
+ * Added "interest" spec to test a simple interest model
28
+ * Added "beer" spec for a more complex model example
29
+ * Added `delay` function which allows equations to interact with past periods
30
+
31
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem 'simulator', path: '../..'
4
+ gem 'chunky_png'
5
+
Binary file
@@ -0,0 +1,70 @@
1
+ require 'json'
2
+ require 'chunky_png'
3
+ require 'simulator'
4
+
5
+ module Drop
6
+ class Program
7
+ attr_accessor :model, :steps_per_second
8
+
9
+ def initialize
10
+ steps_per_second = 3.0
11
+ @steps_per_second = steps_per_second
12
+ @model = ::Simulator::Model.new do
13
+ name = "Drop model"
14
+ var :ax, 0
15
+ var :ay, - 9.8/steps_per_second
16
+ eqtn(:vx, 20) { vx + ax }
17
+ eqtn(:vy, 50) { vy + ay }
18
+ eqtn(:x, 10) { x + vx }
19
+ eqtn(:y, 100) { y + vy }
20
+ end
21
+ @height = 500
22
+ @width = 700
23
+ end
24
+
25
+ def model_data
26
+ # Run the model 30 steps
27
+ model_run = @model.new_run
28
+ 30.times do
29
+ model_run.step
30
+ end
31
+
32
+ # get the data
33
+ model_run.data
34
+ end
35
+
36
+ def norm_data(data)
37
+ xs, ys = data.series :x, :y
38
+
39
+ # normalize
40
+ xs = xs.collect(&:round)
41
+ # Flip the y coordinates so we can draw
42
+ ys = ys.collect {|y| @height - y.round}
43
+
44
+ xs.zip(ys)
45
+ end
46
+
47
+ def plot_data(filename, pts)
48
+ # display the data in an image
49
+ image = ChunkyPNG::Image.new @width, @height,
50
+ ChunkyPNG::Color::BLACK
51
+ pts.each do |pt|
52
+ x, y = pt
53
+ image.circle x, y, 3, ChunkyPNG::Color('red')
54
+ end
55
+ image.save filename
56
+ end
57
+
58
+
59
+ def run
60
+ data = model_data
61
+ pts = norm_data data
62
+ plot_data 'drop.png', pts
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ # Run the program
69
+ Drop::Program.new.run
70
+
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem 'simulator', path: '../..'
4
+ gem 'chunky_png'
5
+
Binary file
@@ -0,0 +1,91 @@
1
+ require 'simulator'
2
+ require 'chunky_png'
3
+
4
+ module Mortgage
5
+ class Program
6
+ include Simulator
7
+ def model
8
+ @model = Model.new do
9
+ name = "Mortgage model"
10
+
11
+ # monthly steps
12
+ var :base_rate, 0.08
13
+ eqtn(:annual_rate) { base_rate + rand(10).to_f/1000 }
14
+ eqtn(:monthly_rate) { annual_rate / 12.0 }
15
+ var :payment, 2000
16
+ eqtn :balance, 250000 do
17
+ balance * (1 + monthly_rate) - payment
18
+ end
19
+ end
20
+ end
21
+
22
+ def model_data
23
+ # fixed rate mortgage
24
+ fixed = @model.new_run
25
+ fixed.set payment: 2100
26
+ (30 * 12).times { fixed.step }
27
+
28
+ # balloon
29
+ balloon = @model.new_run
30
+ balloon.set payment: 1850
31
+ (30 * 12).times { balloon.step }
32
+
33
+ variable = @model.new_run
34
+ # first 10 years, stick with low payment
35
+ variable.set payment: 1800
36
+ (10 * 12).times do
37
+ variable.step
38
+ end
39
+
40
+ # subsequent years, balloon to higher payment until its paid
41
+ variable.set payment: 2100
42
+ (20 * 12).times {variable.step}
43
+ @balances = {
44
+ variable: variable.data.series(:balance),
45
+ fixed: fixed.data.series(:balance),
46
+ balloon: balloon.data.series(:balance)
47
+ }
48
+
49
+ @balances
50
+ end
51
+ def plot
52
+ @height = 500
53
+ @width = 800
54
+
55
+ # display the data in an image
56
+ image = ChunkyPNG::Image.new @width, @height,
57
+ ChunkyPNG::Color::BLACK
58
+
59
+ peg = @balances[:variable]
60
+ count = peg.length
61
+ max = peg.max.to_f
62
+ colors = {
63
+ variable: ChunkyPNG::Color('blue'),
64
+ fixed: ChunkyPNG::Color('yellow'),
65
+ balloon: ChunkyPNG::Color('red')
66
+ }
67
+ @balances.keys.each do |type|
68
+ balances = @balances[type]
69
+ color = colors[type]
70
+
71
+ balances.each_index do |i|
72
+ x = i/count.to_f * @width
73
+ y = @height - (balances[i]/max * @height).to_i
74
+ image.circle x, y, 3, color
75
+ end
76
+ end
77
+
78
+ image.save @filename
79
+ end
80
+ def run
81
+ model
82
+ model_data
83
+ @filename = "mortgage.png"
84
+ plot
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ Mortgage::Program.new.run
91
+
@@ -0,0 +1,17 @@
1
+ Feature: equations
2
+ In order to create simulations
3
+ As a simulation author
4
+ I want to be able to create equations which model the behavior of a system
5
+
6
+ Scenario: adding equations to scenarios
7
+ Given a model
8
+ When I add a new equation
9
+ Then it should be accessible in the list of equations
10
+
11
+ Scenario: creating an equation based on the pythagorean equation
12
+ Given a variable context
13
+ And a value 3 bound to x
14
+ And a value 4 bound to z
15
+ When I create a new equation "Math.sqrt(x^2 + z^2)"
16
+ Then I get a value result 5
17
+
@@ -0,0 +1,22 @@
1
+ Feature: Kinematics estimation
2
+ In order to determine the path of a ball
3
+ As someone studying physics
4
+ I want to be able model kinematics equations
5
+
6
+ Scenario: dropping a ball from rest
7
+ Given a model
8
+ And variable "velocity_y"
9
+ And variable "acceleration_y"
10
+ And variable "displacement_y"
11
+ And variable "t"
12
+ And equation "acceleration_y * t" bound to velocity_y
13
+ And equation "0.5 * acceleration_y * t**2" bound to displacement_y
14
+ And equation "t + 1" bound to t
15
+ And a new run of the model
16
+ And the value 0 bound to displacement_y
17
+ And the value 1 bound to t
18
+ And the value -9.8 bound to acceleration_y
19
+ When I step the run for 10 periods
20
+ Then the value -490 should be bound to displacement_y
21
+ And the value -98 should be bound to velocity_y
22
+
@@ -0,0 +1,17 @@
1
+ Feature: savings simulation
2
+ In order to simulate the outcome of savings rates across a number of periods
3
+ As a simulation runner
4
+ I want the simulation to output the outcome of the decisions made
5
+
6
+ Scenario: constant savings rate
7
+ Given a savings model
8
+ And variable "savings_rate"
9
+ And variable "savings"
10
+ And equation "savings * (1+savings_rate)" bound to savings
11
+ And a new run of the model
12
+ And the value 100 bound to savings
13
+ And the value 0.05 bound to savings_rate
14
+ When I step the run for 10 periods
15
+ Then the value 162.89 should be bound to savings
16
+
17
+
@@ -0,0 +1,52 @@
1
+ require 'simulator'
2
+ include Simulator
3
+
4
+ Given /^a variable context$/ do
5
+ @context = VariableContext.new
6
+ end
7
+
8
+ Given /^a value (\d+) bound to (\w+)$/ do |value, name|
9
+ @var = Variable.new name.to_sym
10
+ @context.add_variables @var
11
+ @context.set name.to_sym => value.to_i
12
+ end
13
+
14
+ When /^I create a new equation "(.*?)"$/ do |arg1|
15
+ @pythagorean_eqtn = Equation.new @var do
16
+ Math.sqrt( x*x + z*z )
17
+ end
18
+ end
19
+
20
+ Given /^variables with values x=(\d+), and y=(\d+)$/ do |x_value, y_value|
21
+ @context = VariableContext.new
22
+ @context.add x: 3, z: 4
23
+
24
+ # set the values of the variables in this context
25
+ @context.set x: x_value.to_i, z: y_value.to_i
26
+ end
27
+
28
+ Then /^I get a value result (\d+)$/ do |equation_result|
29
+ # the context evaluates an equation in its own context
30
+ @pythagorean_eqtn.evaluate_in(@context).should eq equation_result.to_i
31
+ end
32
+
33
+ Then /^a bound variable "(.*?)" with value (\d+)$/ do |var_name, value|
34
+ @context.get(var_name.to_sym).value.should eq value.to_i
35
+ end
36
+
37
+ Given /^a model$/ do
38
+ @model = Model.new
39
+ end
40
+
41
+ When /^I add a new equation$/ do
42
+ @new_equation = Equation.new nil do
43
+ 1 + 1
44
+ end
45
+ @model.add_equation @new_equation
46
+ end
47
+
48
+ Then /^it should be accessible in the list of equations$/ do
49
+ @model.equations.member?(@new_equation).should be true
50
+ end
51
+
52
+