fathom 0.1.0 → 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.
- 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
|