fathom 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +2 -1
- data/VERSION +1 -1
- data/lib/fathom.rb +10 -15
- data/lib/fathom/agent.rb +49 -0
- data/lib/fathom/agent/agent_cluster.rb +23 -0
- data/lib/fathom/agent/properties.rb +48 -0
- data/lib/fathom/ext/faster_csv.rb +1 -0
- data/lib/fathom/ext/open_struct.rb +17 -0
- data/lib/fathom/import.rb +17 -4
- data/lib/fathom/import/csv_import.rb +2 -1
- data/lib/fathom/import/yaml_import.rb +3 -1
- data/lib/fathom/knowledge_base.rb +15 -3
- data/lib/fathom/plausible_range.rb +21 -1
- data/lib/fathom/simulation.rb +59 -0
- data/lib/fathom/simulation/tick_methods.rb +25 -0
- data/lib/fathom/simulation/tick_simulation.rb +12 -0
- data/spec/fathom/agent/agent_cluster_spec.rb +17 -0
- data/spec/fathom/agent_spec.rb +51 -0
- data/spec/fathom/import/csv_import_spec.rb +10 -0
- data/spec/fathom/import/yaml_import_spec.rb +11 -0
- data/spec/fathom/import_spec.rb +5 -1
- data/spec/fathom/plausible_range_spec.rb +22 -0
- data/spec/fathom/simulation/tick_simulation_spec.rb +32 -0
- data/spec/fathom/simulation_spec.rb +24 -0
- data/spec/fathom_spec.rb +8 -0
- data/spec/support/demo.yml +2 -2
- data/spec/support/demo_agent.rb +8 -0
- metadata +23 -4
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -26,7 +26,8 @@ Usage
|
|
26
26
|
=====
|
27
27
|
|
28
28
|
Enrico Fermi [said](http://www.lucidcafe.com/library/95sep/fermi.html):
|
29
|
-
There are two possible outcomes: if the result confirms the hypothesis, then you've made a measurement.
|
29
|
+
There are two possible outcomes: if the result confirms the hypothesis, then you've made a measurement.
|
30
|
+
If the result is contrary to the hypothesis, then you've made a discovery.
|
30
31
|
|
31
32
|
To put together a hypothesis, we gather what we know about our problem:
|
32
33
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/fathom.rb
CHANGED
@@ -7,23 +7,9 @@ $:.unshift(File.dirname(__FILE__))
|
|
7
7
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'fathom')))
|
8
8
|
|
9
9
|
require "gsl"
|
10
|
-
require 'ostruct'
|
11
10
|
require 'options_hash'
|
12
11
|
|
13
|
-
|
14
|
-
class OpenStruct
|
15
|
-
def table
|
16
|
-
@table
|
17
|
-
end
|
18
|
-
|
19
|
-
def values
|
20
|
-
@table.values
|
21
|
-
end
|
22
|
-
|
23
|
-
def keys
|
24
|
-
@table.keys
|
25
|
-
end
|
26
|
-
end
|
12
|
+
require 'ext/open_struct'
|
27
13
|
|
28
14
|
module Fathom
|
29
15
|
lib = File.expand_path(File.dirname(__FILE__))
|
@@ -55,10 +41,19 @@ module Fathom
|
|
55
41
|
autoload :SQLiteImport, 'import/sqlite_import'
|
56
42
|
|
57
43
|
autoload :NodeUtilities, 'node_utilities'
|
44
|
+
|
45
|
+
autoload :Simulation, 'simulation'
|
46
|
+
autoload :TickMethods, 'simulation/tick_methods'
|
47
|
+
autoload :TickSimulation, 'simulation/tick_simulation'
|
48
|
+
|
49
|
+
autoload :Agent, 'agent'
|
50
|
+
autoload :Properties, 'agent/properties'
|
51
|
+
autoload :AgentCluster, 'agent/agent_cluster'
|
58
52
|
|
59
53
|
def knowledge_base
|
60
54
|
@knowledge_base ||= KnowledgeBase.new
|
61
55
|
end
|
56
|
+
alias :kb :knowledge_base
|
62
57
|
end
|
63
58
|
|
64
59
|
# Temporary
|
data/lib/fathom/agent.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
+
class Fathom::Agent
|
3
|
+
|
4
|
+
# =================
|
5
|
+
# = Class Methods =
|
6
|
+
# =================
|
7
|
+
class << self
|
8
|
+
def define_node_accessor(name, node)
|
9
|
+
method_name = ("node_for_" + name.to_s.downcase.gsub(/\s+/, '_')).to_sym
|
10
|
+
define_method(method_name) do
|
11
|
+
node
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
include Properties
|
17
|
+
|
18
|
+
def initialize(opts={})
|
19
|
+
self.class.define_property_states
|
20
|
+
assert_node_accessors(opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
def states
|
24
|
+
@states ||= self.class.properties.inject({}) do |h, state_method_name|
|
25
|
+
h[state_method_name] = nil
|
26
|
+
h
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def callbacks
|
31
|
+
@callbacks ||= (self.methods - Object.methods).grep(/^on_(\w+)/)
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def assert_node_accessors(nodes)
|
36
|
+
nodes.each do |name, node|
|
37
|
+
next unless self.class.properties.include?(name)
|
38
|
+
states[name] = node.respond_to?(:rand) ? node.rand : node
|
39
|
+
self.class.define_node_accessor(name, node)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
if __FILE__ == $0
|
46
|
+
include Fathom
|
47
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
48
|
+
# Agent.new
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
+
|
3
|
+
=begin
|
4
|
+
This class is designed to hold a cluster of agents in memory. It runs the simulation locally and
|
5
|
+
speaks to other clusters via EventMachine. In this way, we don't need a Ruby runtime/thread/fiber
|
6
|
+
for each agent, just one per dozen/hundred/thousand agents, depending on what balances the
|
7
|
+
simulation.
|
8
|
+
=end
|
9
|
+
class Fathom::AgentCluster
|
10
|
+
|
11
|
+
attr_reader :agents
|
12
|
+
|
13
|
+
def initialize(*agents)
|
14
|
+
@agents = agents
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
if __FILE__ == $0
|
20
|
+
include Fathom
|
21
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
22
|
+
# AgentCluster.new
|
23
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
+
module Fathom
|
3
|
+
module Properties
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:extend, ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def properties
|
12
|
+
@properties ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def property(name, opts={})
|
16
|
+
self.properties << name_sym(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def define_property_states
|
20
|
+
return true if @property_states_defined
|
21
|
+
self.properties.each do |state_method_name|
|
22
|
+
unless self.instance_methods.include?(state_method_name.to_s)
|
23
|
+
define_method(state_method_name) do
|
24
|
+
states[state_method_name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
state_method_writer = "#{state_method_name}=".to_sym
|
29
|
+
unless self.instance_methods.include?(state_method_writer.to_s)
|
30
|
+
define_method(state_method_writer) do |value|
|
31
|
+
states[state_method_name] = value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
@property_states_defined = true
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def name_sym(name)
|
41
|
+
name.to_s.downcase.gsub(/\s+/, '_').to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
FasterCSV::HeaderConverters[:strip] = lambda{|h| h.strip}
|
data/lib/fathom/import.rb
CHANGED
@@ -35,6 +35,13 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
|
35
35
|
=end
|
36
36
|
class Fathom::Import
|
37
37
|
|
38
|
+
class << self
|
39
|
+
def import(opts={})
|
40
|
+
importer = new(opts)
|
41
|
+
importer.import
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
38
45
|
attr_reader :content, :options
|
39
46
|
|
40
47
|
def initialize(opts={})
|
@@ -47,7 +54,8 @@ class Fathom::Import
|
|
47
54
|
import_methods.each do |method|
|
48
55
|
klass, initialization_data = self.send(method.to_sym)
|
49
56
|
initialization_data.each do |values|
|
50
|
-
|
57
|
+
node = extract_nodes(klass, values)
|
58
|
+
results << node if node
|
51
59
|
end
|
52
60
|
end
|
53
61
|
results
|
@@ -55,10 +63,15 @@ class Fathom::Import
|
|
55
63
|
|
56
64
|
protected
|
57
65
|
|
66
|
+
# Just blankly try to initiate a node. If it fails, silently fail for now.
|
58
67
|
def extract_nodes(klass, values)
|
59
|
-
|
60
|
-
|
61
|
-
|
68
|
+
begin
|
69
|
+
node = klass.new(values)
|
70
|
+
Fathom.knowledge_base[node.name] = node
|
71
|
+
node
|
72
|
+
rescue
|
73
|
+
nil
|
74
|
+
end
|
62
75
|
end
|
63
76
|
|
64
77
|
def import_methods
|
@@ -4,6 +4,7 @@ require 'open-uri'
|
|
4
4
|
|
5
5
|
# TODO: Work this out with Ruby 1.9. We don't need to load this for all Rubies.
|
6
6
|
require 'fastercsv'
|
7
|
+
require 'ext/faster_csv'
|
7
8
|
|
8
9
|
module Fathom
|
9
10
|
class CSVImport < Import
|
@@ -23,7 +24,7 @@ module Fathom
|
|
23
24
|
def parse_options
|
24
25
|
return @parse_options if @parse_options
|
25
26
|
@parse_options = @options[:parse_options]
|
26
|
-
@parse_options ||= {:converters => [:all], :headers => true, :skip_blanks => true}
|
27
|
+
@parse_options ||= {:converters => [:all], :headers => true, :skip_blanks => true, :header_converters => [:strip, :symbol]}
|
27
28
|
@parse_options
|
28
29
|
end
|
29
30
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
2
|
require 'open-uri'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
class Fathom::YAMLImport < Import
|
5
6
|
def import_plausible_ranges
|
@@ -31,7 +32,8 @@ class Fathom::YAMLImport < Import
|
|
31
32
|
name, value = array.first, array.last
|
32
33
|
if value.is_a?(Hash)
|
33
34
|
value = OptionsHash.new(value)
|
34
|
-
list << value.merge(:name => name) if value[:min] and value[:max]
|
35
|
+
# list << value.merge(:name => name) if value[:min] and value[:max]
|
36
|
+
list << value.merge(:name => name)
|
35
37
|
end
|
36
38
|
list
|
37
39
|
end
|
@@ -1,17 +1,29 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
2
|
class Fathom::KnowledgeBase
|
3
3
|
|
4
|
+
attr_reader :data_store
|
5
|
+
|
4
6
|
def initialize(opts={})
|
5
7
|
opts = OptionsHash.new(opts)
|
6
|
-
@data_store =
|
8
|
+
@data_store = OpenStruct.new
|
7
9
|
end
|
8
10
|
|
9
11
|
def []=(key, value)
|
10
|
-
@data_store[key] = value
|
12
|
+
@data_store.table[key] = value
|
11
13
|
end
|
12
14
|
|
13
15
|
def [](key)
|
14
|
-
@data_store[key]
|
16
|
+
@data_store.table[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
# This is temporary, but useful for now. After we have the persisted KnowledgeBase,
|
20
|
+
# we'll create explicit accessor methods or a find syntax.
|
21
|
+
def method_missing(sym, *args, &block)
|
22
|
+
if @data_store.table.keys.include?(sym)
|
23
|
+
@data_store.send(sym)
|
24
|
+
else
|
25
|
+
super
|
26
|
+
end
|
15
27
|
end
|
16
28
|
|
17
29
|
end
|
@@ -52,7 +52,11 @@ module Fathom
|
|
52
52
|
|
53
53
|
# Not using specific distributions yet
|
54
54
|
def rand
|
55
|
-
|
55
|
+
value = get_rand
|
56
|
+
until is_bounded?(value) do
|
57
|
+
value= get_rand
|
58
|
+
end
|
59
|
+
value
|
56
60
|
end
|
57
61
|
|
58
62
|
def array_of_random_values(n=10)
|
@@ -66,6 +70,22 @@ module Fathom
|
|
66
70
|
alias :to_v :vector_of_random_values
|
67
71
|
|
68
72
|
protected
|
73
|
+
|
74
|
+
def is_bounded?(value)
|
75
|
+
return true unless hard_lower_bound or hard_upper_bound
|
76
|
+
if hard_lower_bound and hard_upper_bound
|
77
|
+
value >= hard_lower_bound and value <= hard_upper_bound
|
78
|
+
elsif hard_lower_bound
|
79
|
+
value >= hard_lower_bound
|
80
|
+
elsif hard_upper_bound
|
81
|
+
value <= hard_upper_bound
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_rand
|
86
|
+
rng.gaussian(std) + midpoint
|
87
|
+
end
|
88
|
+
|
69
89
|
def rng
|
70
90
|
@rng ||= GSL::Rng.alloc
|
71
91
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
+
class Fathom::Simulation
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Expects a symbol for the callback to define on the simulation.
|
7
|
+
def define_callback_accessor(callback, obj)
|
8
|
+
call_method = callback.to_s.scan(/^on_(\w+)/).flatten.compact.first
|
9
|
+
raise ArgumentError, "Callback doesn't appear to be a callback: #{callback}" unless call_method
|
10
|
+
return true if self.respond_to?(call_method)
|
11
|
+
define_method(call_method) do
|
12
|
+
callbacks[callback].each do |agent|
|
13
|
+
agent.send(callback, obj)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
agent_lookup_method = "agents_using_#{call_method}".to_sym
|
18
|
+
return true if self.respond_to?(agent_lookup_method)
|
19
|
+
define_method(agent_lookup_method) do
|
20
|
+
callbacks[callback]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :agents
|
27
|
+
|
28
|
+
def initialize(*agents)
|
29
|
+
@agents = agents
|
30
|
+
assert_callbacks
|
31
|
+
end
|
32
|
+
|
33
|
+
def callbacks
|
34
|
+
@callbacks ||= {}
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
def assert_callbacks
|
39
|
+
self.agents.each do |agent|
|
40
|
+
assert_agent(agent)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def assert_agent(agent)
|
45
|
+
return false unless agent.respond_to?(:callbacks)
|
46
|
+
agent.callbacks.each do |callback|
|
47
|
+
callback_sym = callback.to_sym
|
48
|
+
self.callbacks[callback_sym] ||= []
|
49
|
+
self.callbacks[callback_sym] << agent
|
50
|
+
self.class.define_callback_accessor(callback_sym, self)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if __FILE__ == $0
|
56
|
+
include Fathom
|
57
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
58
|
+
# Simulation.new
|
59
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
+
module Fathom
|
3
|
+
module TickMethods
|
4
|
+
def initialize(*agents)
|
5
|
+
super(*agents)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :ticks_designed, :ticks_executed
|
9
|
+
|
10
|
+
def process(n)
|
11
|
+
@ticks_designed = n
|
12
|
+
@ticks_executed = 0
|
13
|
+
n.times do
|
14
|
+
self.tick(self)
|
15
|
+
@ticks_executed += 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if __FILE__ == $0
|
22
|
+
include Fathom
|
23
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
24
|
+
# TicksSimulation.new
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
+
module Fathom
|
3
|
+
class TickSimulation < Simulation
|
4
|
+
include TickMethods
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
if __FILE__ == $0
|
9
|
+
include Fathom
|
10
|
+
# TODO: Is there anything you want to do to run this file on its own?
|
11
|
+
# TickSimulator.new
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
include Fathom
|
4
|
+
|
5
|
+
describe AgentCluster do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@agent = double()
|
9
|
+
@agents = [@agent]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should initialize with a set of agents" do
|
13
|
+
@ac = AgentCluster.new @agent
|
14
|
+
@ac.agents.should eql(@agents)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
include Fathom
|
4
|
+
|
5
|
+
describe Agent do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@pr1 = PlausibleRange.new(:min => 1, :max => 2)
|
9
|
+
@pr2 = PlausibleRange.new(:min => 10, :max => 11)
|
10
|
+
@da = DemoAgent.new(:field1 => @pr1, :field2 => @pr2)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be have a list of properties" do
|
14
|
+
DemoAgent.properties.should eql([:field1, :field2])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to set a seed node for each property defined in the class" do
|
18
|
+
@da.node_for_field1.should eql(@pr1)
|
19
|
+
@da.node_for_field2.should eql(@pr2)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not set a seed node for a node that doesn't have a property" do
|
23
|
+
da = DemoAgent.new(:field1 => @pr1, :field2 => @pr2, :field3 => :should_not_be_found)
|
24
|
+
da.should_not be_respond_to(:node_for_field3)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should have a state accessor for each property" do
|
28
|
+
@da.should be_respond_to(:field1)
|
29
|
+
@da.should be_respond_to(:field1=)
|
30
|
+
@da.should be_respond_to(:field2)
|
31
|
+
@da.should be_respond_to(:field2=)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should set the initial state of each property from the seed node, if defined" do
|
35
|
+
@pr1.should_receive(:rand).and_return(1.5)
|
36
|
+
@pr2.should_not_receive(:rand)
|
37
|
+
@da = DemoAgent.new(:field1 => @pr1)
|
38
|
+
@da.field1.should eql(1.5)
|
39
|
+
@da.field2.should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be able to send a hard parameter and save it in a property" do
|
43
|
+
@da = DemoAgent.new(:field1 => 2)
|
44
|
+
@da.field1.should eql(2)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should expose the callbacks, those methods starting with on_" do
|
48
|
+
@da.callbacks.should eql(["on_tick"])
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -33,4 +33,14 @@ describe CSVImport do
|
|
33
33
|
@result[2].values.should eql([3,6,9])
|
34
34
|
end
|
35
35
|
|
36
|
+
it "should store the imported values in the knowledge base" do
|
37
|
+
Fathom.knowledge_base[:this].should be_a(DataNode)
|
38
|
+
Fathom.kb[:this].values.should eql([1,4,7])
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should import from the class level" do
|
42
|
+
CSVImport.import(@opts)
|
43
|
+
Fathom.knowledge_base[:this].should be_a(DataNode)
|
44
|
+
Fathom.kb[:this].values.should eql([1,4,7])
|
45
|
+
end
|
36
46
|
end
|
@@ -37,4 +37,15 @@ describe YAMLImport do
|
|
37
37
|
data_node.values.should eql([10,20,30])
|
38
38
|
end
|
39
39
|
|
40
|
+
it "should store the imported values in the knowledge base" do
|
41
|
+
Fathom.knowledge_base['CO2 Emissions'].should be_a(PlausibleRange)
|
42
|
+
Fathom.kb['CO2 Emissions'].min.should eql(1_000_000)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should import from the class level" do
|
46
|
+
YAMLImport.import(@opts)
|
47
|
+
Fathom.knowledge_base['CO2 Emissions'].should be_a(PlausibleRange)
|
48
|
+
Fathom.kb['CO2 Emissions'].min.should eql(1_000_000)
|
49
|
+
end
|
50
|
+
|
40
51
|
end
|
data/spec/fathom/import_spec.rb
CHANGED
@@ -11,7 +11,7 @@ describe Import do
|
|
11
11
|
@values = [1,2,3,4,5]
|
12
12
|
end
|
13
13
|
|
14
|
-
it "should initialize with
|
14
|
+
it "should initialize with optional content" do
|
15
15
|
@i.content.should eql(@content)
|
16
16
|
end
|
17
17
|
|
@@ -19,4 +19,8 @@ describe Import do
|
|
19
19
|
@i.options.should eql(@options)
|
20
20
|
end
|
21
21
|
|
22
|
+
it "should have a class-level import method" do
|
23
|
+
Import.should be_respond_to(:import)
|
24
|
+
end
|
25
|
+
|
22
26
|
end
|
@@ -127,4 +127,26 @@ describe PlausibleRange do
|
|
127
127
|
pr.name_sym.should eql(:demo_node)
|
128
128
|
end
|
129
129
|
|
130
|
+
it "should not exceed the lower bound if it is set", :slow => true do
|
131
|
+
pr = PlausibleRange.new(:max => 100, :hard_lower_bound => 0)
|
132
|
+
1_000.times do
|
133
|
+
(pr.rand >= 0).should eql(true)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not exceed the upper bound if it is set", :slow => true do
|
138
|
+
pr = PlausibleRange.new(:min => 0, :hard_upper_bound => 100)
|
139
|
+
1_000.times do
|
140
|
+
(pr.rand <= 100).should eql(true)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not exceed the lower bound or upper bound if both are set", :slow => true do
|
145
|
+
pr = PlausibleRange.new(:hard_upper_bound => 100, :hard_lower_bound => 0)
|
146
|
+
1_000.times do
|
147
|
+
r = pr.rand
|
148
|
+
(r >= 0 and r <= 100).should eql(true)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
130
152
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
include Fathom
|
4
|
+
|
5
|
+
describe TickSimulation do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@da = DemoAgent.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should process with n ticks" do
|
12
|
+
@da.should_receive(:on_tick).exactly(3).times.and_return(true)
|
13
|
+
s = TickSimulation.new(@da)
|
14
|
+
s.process(3)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should expose the number of ticks designed and executed after processing" do
|
18
|
+
s = TickSimulation.new(@da)
|
19
|
+
s.process(4)
|
20
|
+
s.ticks_designed.should eql(4)
|
21
|
+
s.ticks_executed.should eql(4)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Any calls coming top down (from the simulator or the agent cluster), will need a standard signature to
|
25
|
+
# make things interchangeable. We use the simulator itself, which is a bit fat, but will work for the short
|
26
|
+
# term.
|
27
|
+
it "should pass the simulator on tick" do
|
28
|
+
s = TickSimulation.new(@da)
|
29
|
+
@da.should_receive(:on_tick).with(s)
|
30
|
+
s.process(1)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
include Fathom
|
4
|
+
|
5
|
+
describe Simulation do
|
6
|
+
before do
|
7
|
+
@da = DemoAgent.new
|
8
|
+
@s = Simulation.new(@da)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should initialize with a list of agents" do
|
12
|
+
s = Simulation.new(1,2,3)
|
13
|
+
s.agents.should eql([1,2,3])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should register agent callbacks for simpler execution" do
|
17
|
+
@da.should_receive(:on_tick).and_return(true)
|
18
|
+
@s.tick
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should publish agent subscription to various callbacks to facilitate agent-to-agent communication" do
|
22
|
+
@s.agents_using_tick.should eql([@da])
|
23
|
+
end
|
24
|
+
end
|
data/spec/fathom_spec.rb
CHANGED
@@ -5,4 +5,12 @@ describe "Fathom" do
|
|
5
5
|
Fathom.included_modules.should_not be_include(GSL)
|
6
6
|
lambda{GSL}.should_not raise_error
|
7
7
|
end
|
8
|
+
|
9
|
+
it "should have a knowledge base" do
|
10
|
+
Fathom.knowledge_base.should be_a(KnowledgeBase)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should alias kb for knowledge_base" do
|
14
|
+
Fathom.kb.should eql(Fathom.knowledge_base)
|
15
|
+
end
|
8
16
|
end
|
data/spec/support/demo.yml
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fathom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-07 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -53,7 +53,11 @@ files:
|
|
53
53
|
- Rakefile
|
54
54
|
- VERSION
|
55
55
|
- autotest/discover.rb
|
56
|
+
- fathom.gemspec
|
56
57
|
- lib/fathom.rb
|
58
|
+
- lib/fathom/agent.rb
|
59
|
+
- lib/fathom/agent/agent_cluster.rb
|
60
|
+
- lib/fathom/agent/properties.rb
|
57
61
|
- lib/fathom/archive/conditional_probability_matrix.rb
|
58
62
|
- lib/fathom/archive/n2.rb
|
59
63
|
- lib/fathom/archive/n3.rb
|
@@ -65,6 +69,8 @@ files:
|
|
65
69
|
- lib/fathom/combined_plausibilities.rb
|
66
70
|
- lib/fathom/concept.rb
|
67
71
|
- lib/fathom/data_node.rb
|
72
|
+
- lib/fathom/ext/faster_csv.rb
|
73
|
+
- lib/fathom/ext/open_struct.rb
|
68
74
|
- lib/fathom/import.rb
|
69
75
|
- lib/fathom/import/csv_import.rb
|
70
76
|
- lib/fathom/import/yaml_import.rb
|
@@ -73,10 +79,15 @@ files:
|
|
73
79
|
- lib/fathom/monte_carlo_set.rb
|
74
80
|
- lib/fathom/node_utilities.rb
|
75
81
|
- lib/fathom/plausible_range.rb
|
82
|
+
- lib/fathom/simulation.rb
|
83
|
+
- lib/fathom/simulation/tick_methods.rb
|
84
|
+
- lib/fathom/simulation/tick_simulation.rb
|
76
85
|
- lib/fathom/value_aggregator.rb
|
77
86
|
- lib/fathom/value_description.rb
|
78
87
|
- lib/fathom/value_multiplier.rb
|
79
88
|
- lib/options_hash.rb
|
89
|
+
- spec/fathom/agent/agent_cluster_spec.rb
|
90
|
+
- spec/fathom/agent_spec.rb
|
80
91
|
- spec/fathom/data_node_spec.rb
|
81
92
|
- spec/fathom/import/csv_import_spec.rb
|
82
93
|
- spec/fathom/import/yaml_import_spec.rb
|
@@ -84,10 +95,13 @@ files:
|
|
84
95
|
- spec/fathom/knowledge_base_spec.rb
|
85
96
|
- spec/fathom/monte_carlo_set_spec.rb
|
86
97
|
- spec/fathom/plausible_range_spec.rb
|
98
|
+
- spec/fathom/simulation/tick_simulation_spec.rb
|
99
|
+
- spec/fathom/simulation_spec.rb
|
87
100
|
- spec/fathom/value_description_spec.rb
|
88
101
|
- spec/fathom_spec.rb
|
89
102
|
- spec/spec_helper.rb
|
90
103
|
- spec/support/demo.yml
|
104
|
+
- spec/support/demo_agent.rb
|
91
105
|
has_rdoc: true
|
92
106
|
homepage: http://github.com/davidrichards/fathom
|
93
107
|
licenses: []
|
@@ -123,6 +137,8 @@ signing_key:
|
|
123
137
|
specification_version: 3
|
124
138
|
summary: Decision Support in Ruby
|
125
139
|
test_files:
|
140
|
+
- spec/fathom/agent/agent_cluster_spec.rb
|
141
|
+
- spec/fathom/agent_spec.rb
|
126
142
|
- spec/fathom/data_node_spec.rb
|
127
143
|
- spec/fathom/import/csv_import_spec.rb
|
128
144
|
- spec/fathom/import/yaml_import_spec.rb
|
@@ -130,6 +146,9 @@ test_files:
|
|
130
146
|
- spec/fathom/knowledge_base_spec.rb
|
131
147
|
- spec/fathom/monte_carlo_set_spec.rb
|
132
148
|
- spec/fathom/plausible_range_spec.rb
|
149
|
+
- spec/fathom/simulation/tick_simulation_spec.rb
|
150
|
+
- spec/fathom/simulation_spec.rb
|
133
151
|
- spec/fathom/value_description_spec.rb
|
134
152
|
- spec/fathom_spec.rb
|
135
153
|
- spec/spec_helper.rb
|
154
|
+
- spec/support/demo_agent.rb
|