bodhi-slam 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bodhi-slam/properties.rb +7 -2
- data/lib/bodhi-slam/simulation/normal_distribution.rb +103 -0
- data/lib/bodhi-slam/simulator.rb +94 -0
- data/lib/bodhi-slam/types.rb +2 -2
- data/lib/bodhi-slam.rb +8 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a728bbc653fe51f2aa54fd7fcc07874205616c8
|
4
|
+
data.tar.gz: ecd5e410504d479843dfcc4ebe2823815161c6fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ca39c510350b552edbd793a8b0c42700f0c3125ca103f613fd8ee1a8c618076e2063f9630a739b7e67a99c05378f0b0d9b2a05249c2c3162fbba64c60d3d3e4
|
7
|
+
data.tar.gz: 32749263d7225845eb31e8780a02b446c19ad2a559fcc295bc01767157f1f15a958f90fd32bb904346f4595bad27e3262794b696287e631ed734e1c5c2482fab
|
@@ -80,8 +80,13 @@ module Bodhi
|
|
80
80
|
# s.update_attributes(bar: 10)
|
81
81
|
# s.attributes # => { foo: "test", bar: 10 }
|
82
82
|
def update_attributes(params)
|
83
|
-
params.each do |
|
84
|
-
|
83
|
+
params.each do |property, value|
|
84
|
+
property_options = self.class.properties[property.to_sym]
|
85
|
+
if property_options.nil?
|
86
|
+
send("#{property}=", value)
|
87
|
+
else
|
88
|
+
send("#{property}=", Bodhi::Support.coerce(value, property_options))
|
89
|
+
end
|
85
90
|
end
|
86
91
|
end
|
87
92
|
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Bodhi
|
2
|
+
module Simulation
|
3
|
+
class NormalDistributionCurve
|
4
|
+
include Bodhi::Properties
|
5
|
+
include Bodhi::Validations
|
6
|
+
|
7
|
+
property :mean, type: Float
|
8
|
+
property :mean_range, type: Float, multi: true
|
9
|
+
|
10
|
+
property :std_dev, type: Float
|
11
|
+
property :std_dev_range, type: Float, multi: true
|
12
|
+
|
13
|
+
property :scale, type: Float
|
14
|
+
property :title, type: String
|
15
|
+
|
16
|
+
validates :mean, required: true
|
17
|
+
validates :std_dev, required: true, min: 0.0001
|
18
|
+
validates :scale, required: true, min: 0.0, max: 1.0
|
19
|
+
end
|
20
|
+
|
21
|
+
class NormalDistribution
|
22
|
+
include Bodhi::Properties
|
23
|
+
include Bodhi::Validations
|
24
|
+
|
25
|
+
GAUSSIAN_FUNCTION = lambda{|x,u,o,s| 1/Math.sqrt(2*Math::PI*(o**2)) * Math.exp(-((x-u)**2)/(2*(o**2))) * s }
|
26
|
+
|
27
|
+
property :curves, type: Bodhi::Simulation::NormalDistributionCurve, multi: true
|
28
|
+
validates :curves, required: true
|
29
|
+
|
30
|
+
# ================
|
31
|
+
# Class Methods
|
32
|
+
# ================
|
33
|
+
|
34
|
+
# Accepts an array of Bodhi::Simulation::NormalDistribution::Curves objects
|
35
|
+
# Randomizes the +mean+ and +std_dev+ properties based on the given
|
36
|
+
# +mean_range+ and +std_dev_range+ properties
|
37
|
+
# Returns a new Bodhi::Simulation::NormalDistribution object with the randomized properties
|
38
|
+
#
|
39
|
+
# curves = [{mean_range: [45.4, 50.0], std_dev_range: [1.2, 2.2], scale: 0.2, title: "Dinner rush"}]
|
40
|
+
#
|
41
|
+
# Bodhi::Simulation::NormalDistribution.randomize(curves)
|
42
|
+
# #=> #<Bodhi::Simulation::NormalDistribution @mean=47.1234 @std_dev=1.7543 @mean_range=[45.4, 50.0] @std_dev_range=[1.2, 2.2] @scale=0.2 @title="Dinner rush">
|
43
|
+
#
|
44
|
+
def self.randomize(curves)
|
45
|
+
unless curves.is_a?(Array)
|
46
|
+
raise ArgumentError.new("+curves+ must be an Array")
|
47
|
+
end
|
48
|
+
|
49
|
+
randomized_curves = curves.collect do |curve|
|
50
|
+
# Coerce the given +curve+ into a Bodhi::Simulation::NormalDistributionCurve
|
51
|
+
unless curve.is_a?(Bodhi::Simulation::NormalDistributionCurve)
|
52
|
+
begin
|
53
|
+
curve = Bodhi::Simulation::NormalDistributionCurve.new(curve)
|
54
|
+
rescue Exception => e
|
55
|
+
raise ArgumentError.new("The value: #{curve} is not a valid Bodhi::Simulation::NormalDistributionCurve object. Error: #{e}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check if the user supplied a range for mean and std_dev values
|
60
|
+
# These are optional properies, but a required for randomizing a curve
|
61
|
+
if curve.mean_range.nil? || curve.std_dev_range.nil?
|
62
|
+
raise ArgumentError.new("Unable to randomize the curve: #{curve.to_json}. Reason: missing mandatory +mean_range+ OR +std_dev_range+ properties.")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Calculate a random mean and standard deviation
|
66
|
+
random_mean = rand(curve.mean_range[0]..curve.mean_range[1])
|
67
|
+
random_std_dev = rand(curve.std_dev_range[0]..curve.std_dev_range[1])
|
68
|
+
|
69
|
+
# Create a new randomized curve object
|
70
|
+
randomized_curve = curve.clone
|
71
|
+
randomized_curve.mean = random_mean
|
72
|
+
randomized_curve.std_dev = random_std_dev
|
73
|
+
|
74
|
+
# Check if the randomized curve is valid
|
75
|
+
if randomized_curve.invalid?
|
76
|
+
raise ArgumentError.new("Invalid Bodhi::Simulation::NormalDistributionCurve. Reasons: #{randomized_curve.errors.to_a}")
|
77
|
+
end
|
78
|
+
|
79
|
+
# return the randomized curve
|
80
|
+
randomized_curve
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return a new NormalDistribution with the randomized curves
|
84
|
+
Bodhi::Simulation::NormalDistribution.new(curves: randomized_curves)
|
85
|
+
end
|
86
|
+
|
87
|
+
# ================
|
88
|
+
# Instance Methods
|
89
|
+
# ================
|
90
|
+
|
91
|
+
# Evaluates the value of +y+ at position +x+
|
92
|
+
# Raises ArgumentError if +x+ is not a Float or Integer
|
93
|
+
def calculate(x)
|
94
|
+
unless x.is_a?(Integer) || x.is_a?(Float)
|
95
|
+
raise ArgumentError.new("Expected Integer or Float but recieved: #{x.class}")
|
96
|
+
end
|
97
|
+
|
98
|
+
curves.collect{ |curve| GAUSSIAN_FUNCTION.call(x, curve.mean, curve.std_dev, curve.scale) }.reduce(:+)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Bodhi
|
2
|
+
class SimulationFrame
|
3
|
+
include Bodhi::Properties
|
4
|
+
include Bodhi::Validations
|
5
|
+
|
6
|
+
property :iteration, type: Integer, default: 0
|
7
|
+
property :time, type: DateTime
|
8
|
+
end
|
9
|
+
|
10
|
+
class Simulator
|
11
|
+
include Bodhi::Properties
|
12
|
+
include Bodhi::Validations
|
13
|
+
|
14
|
+
# Initial conditions
|
15
|
+
property :starts_at, type: DateTime
|
16
|
+
property :iterations, type: Integer
|
17
|
+
property :time_units, type: String
|
18
|
+
property :time_scale, type: Integer, default: 1
|
19
|
+
|
20
|
+
# Dynamic attributes
|
21
|
+
# Updated every iteration
|
22
|
+
property :current_frame, type: SimulationFrame
|
23
|
+
|
24
|
+
# Model validations
|
25
|
+
validates :starts_at, required: true
|
26
|
+
validates :iterations, required: true, min: 1
|
27
|
+
validates :time_units, required: true
|
28
|
+
validates :time_scale, min: 1
|
29
|
+
|
30
|
+
# ================
|
31
|
+
# Class Methods
|
32
|
+
# ================
|
33
|
+
|
34
|
+
# Run a new simulation using the given +settings+ and +&block+
|
35
|
+
# Yields the +simulation.current_time+ to the user defined +&block+
|
36
|
+
# Ignores +current_frame+ settings and zero's them before the simulation
|
37
|
+
#
|
38
|
+
# Bodhi::Simulator.execute(starts_at: "2016-05-10", iterations: 10, time_units: "days") do |current_time|
|
39
|
+
# # do some simulation stuff!
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# # You can even go crazy and do things like:
|
43
|
+
# Bodhi::Simulator.execute(...) do |outer_time|
|
44
|
+
# # do some simulation stuff!
|
45
|
+
# Bodhi::Simulator.execute(...) do |inner_time|
|
46
|
+
# # do a nested simulation!
|
47
|
+
# end
|
48
|
+
# # do more stuff after the netsted simulation...
|
49
|
+
# end
|
50
|
+
def self.execute(settings, &block)
|
51
|
+
simulation = Bodhi::Simulator.new(settings)
|
52
|
+
|
53
|
+
if simulation.invalid?
|
54
|
+
raise ArgumentError.new("Invalid settings: #{simulation.errors.to_a}")
|
55
|
+
end
|
56
|
+
|
57
|
+
if simulation.current_frame.nil?
|
58
|
+
simulation.current_frame = Bodhi::SimulationFrame.new(iteration: 0, time: simulation.starts_at)
|
59
|
+
else
|
60
|
+
simulation.current_frame.iteration = 0
|
61
|
+
simulation.current_frame.time = simulation.starts_at
|
62
|
+
end
|
63
|
+
|
64
|
+
until simulation.complete?
|
65
|
+
yield simulation.current_frame.clone
|
66
|
+
simulation.increment
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# ================
|
71
|
+
# Instance Methods
|
72
|
+
# ================
|
73
|
+
|
74
|
+
# returns true if the simulation has processed all iterations
|
75
|
+
def complete?
|
76
|
+
self.current_frame.iteration == self.iterations
|
77
|
+
end
|
78
|
+
|
79
|
+
# Increments the simulation loop by one iteration
|
80
|
+
# Updates +current_time+ to the new time offset
|
81
|
+
# Updates +current_iteration+ to the next iteration
|
82
|
+
#
|
83
|
+
# simulation = Bodhi::Simulator.new(starts_at: "2016-05-13", iterations: 2, time_units: "days")
|
84
|
+
# simulation.increment
|
85
|
+
# simulation #=> #<Bodhi::Simulator @starts_at: "2016-05-13" @iterations: 2, @time_units: "days", @current_time: "2016-05-14", @current_iteration: 1 >
|
86
|
+
#
|
87
|
+
def increment
|
88
|
+
self.current_frame.iteration += 1
|
89
|
+
self.current_frame.time = self.starts_at + (self.current_frame.iteration * 1.send(self.time_units) * self.time_scale)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
Dir[File.dirname(__FILE__) + "/simulation/*.rb"].each { |file| require file }
|
data/lib/bodhi-slam/types.rb
CHANGED
@@ -148,13 +148,13 @@ module Bodhi
|
|
148
148
|
raise ArgumentError.new("Expected #{type.class} to be a Bodhi::Type")
|
149
149
|
end
|
150
150
|
|
151
|
-
klass = Object.const_set(type.name, Class.new { include Bodhi::Resource })
|
151
|
+
klass = Object.const_set(type.name, Class.new { include Bodhi::Resource, ActiveModel::Model })
|
152
152
|
|
153
153
|
type.properties.each_pair do |attr_name, attr_properties|
|
154
154
|
attr_properties = Bodhi::Support.symbolize_keys(attr_properties)
|
155
155
|
|
156
156
|
# remove Sanitizers
|
157
|
-
attr_properties.delete_if{ |key, value| [:trim, :unique, :default, :isCurrentUser, :toLower].include?(key) }
|
157
|
+
attr_properties.delete_if{ |key, value| [:trim, :unique, :default, :isCurrentUser, :toLower, :encrypt].include?(key) }
|
158
158
|
|
159
159
|
# Do not add factories or validations for system properties
|
160
160
|
unless attr_properties[:system] == true
|
data/lib/bodhi-slam.rb
CHANGED
@@ -7,6 +7,11 @@ require 'faraday-http-cache'
|
|
7
7
|
require 'net/http/persistent'
|
8
8
|
require 'regexp-examples'
|
9
9
|
|
10
|
+
# Active Support
|
11
|
+
require 'active_model'
|
12
|
+
require 'active_support'
|
13
|
+
require 'active_support/core_ext'
|
14
|
+
|
10
15
|
require 'bodhi-slam/support'
|
11
16
|
require 'bodhi-slam/validations'
|
12
17
|
require 'bodhi-slam/errors'
|
@@ -25,6 +30,9 @@ require 'bodhi-slam/users'
|
|
25
30
|
require 'bodhi-slam/profiles'
|
26
31
|
require 'bodhi-slam/queries'
|
27
32
|
|
33
|
+
# Discrete Event Simulator
|
34
|
+
require 'bodhi-slam/simulator'
|
35
|
+
|
28
36
|
class BodhiSlam
|
29
37
|
# Defines a context to interact with the Bodhi API
|
30
38
|
# Including a +server+, +namespace+, +username+, +password+ or +cookie+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bodhi-slam
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- willdavis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activemodel
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.2'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.2'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: json
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,6 +185,8 @@ files:
|
|
171
185
|
- lib/bodhi-slam/properties.rb
|
172
186
|
- lib/bodhi-slam/queries.rb
|
173
187
|
- lib/bodhi-slam/resource.rb
|
188
|
+
- lib/bodhi-slam/simulation/normal_distribution.rb
|
189
|
+
- lib/bodhi-slam/simulator.rb
|
174
190
|
- lib/bodhi-slam/support.rb
|
175
191
|
- lib/bodhi-slam/types.rb
|
176
192
|
- lib/bodhi-slam/types/index.rb
|
@@ -209,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
225
|
version: '0'
|
210
226
|
requirements: []
|
211
227
|
rubyforge_project:
|
212
|
-
rubygems_version: 2.
|
228
|
+
rubygems_version: 2.5.1
|
213
229
|
signing_key:
|
214
230
|
specification_version: 4
|
215
231
|
summary: Ruby bindings for the Bodhi API & factories for random data generation
|