fathom 0.3.7 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +7 -5
- data/.document +2 -2
- data/Gemfile +9 -10
- data/{LICENSE → LICENSE.txt} +1 -1
- data/README.md +29 -90
- data/Rakefile +34 -32
- data/VERSION +1 -1
- data/fathom.gemspec +105 -0
- data/features/fathom.feature +26 -0
- data/features/step_definitions/fathom_steps.rb +23 -0
- data/features/support/env.rb +13 -0
- data/lib/ext/array.rb +6 -2
- data/lib/ext/string.rb +86 -7
- data/lib/fathom.rb +51 -88
- data/lib/fathom/behaviors/attribute_system.rb +91 -0
- data/lib/fathom/behaviors/context_behavior.rb +28 -0
- data/lib/fathom/behaviors/plugins.rb +16 -0
- data/lib/fathom/contexts/network_population.rb +47 -0
- data/lib/fathom/contexts/network_traversal.rb +4 -0
- data/lib/fathom/data/adjacency_matrix.rb +27 -0
- data/lib/fathom/data/definition.rb +22 -0
- data/lib/fathom/data/edge.rb +58 -0
- data/lib/fathom/data/network.rb +35 -0
- data/lib/fathom/data/outcome.rb +30 -0
- data/lib/fathom/data/property.rb +31 -0
- data/lib/fathom/data/variable.rb +59 -0
- data/lib/fathom/roles/general_graph_tools.rb +87 -0
- data/lib/fathom/roles/network_builder.rb +61 -0
- data/spec/fathom/behaviors/attribute_system_spec.rb +141 -0
- data/spec/fathom/behaviors/context_behavior_spec.rb +15 -0
- data/spec/fathom/behaviors/plugins_spec.rb +80 -0
- data/spec/fathom/contexts/network_population_spec.rb +55 -0
- data/spec/fathom/contexts/network_traversal_spec.rb +11 -0
- data/spec/fathom/data/adjacency_matrix_spec.rb +42 -0
- data/spec/fathom/data/definition_spec.rb +19 -0
- data/spec/fathom/data/edge_spec.rb +77 -0
- data/spec/fathom/data/network_spec.rb +72 -0
- data/spec/fathom/data/outcome_spec.rb +17 -0
- data/spec/fathom/data/property_spec.rb +17 -0
- data/spec/fathom/data/variable_spec.rb +101 -0
- data/spec/fathom/ext/array_spec.rb +17 -0
- data/spec/fathom/ext/string_spec.rb +90 -0
- data/spec/fathom/roles/general_graph_tools_spec.rb +95 -0
- data/spec/fathom/roles/network_builder_spec.rb +90 -0
- data/spec/fathom_spec.rb +28 -49
- data/spec/spec_helper.rb +7 -11
- data/spec/support/context_behavior.rb +14 -0
- data/spec/support/custom_matchers.rb +12 -0
- data/spec/support/files.rb +8 -0
- data/spec/support/network.yml +42 -0
- metadata +133 -174
- data/.bundle/config +0 -2
- data/.gitignore +0 -6
- data/Gemfile.lock +0 -42
- data/TODO.md +0 -127
- data/autotest/discover.rb +0 -1
- data/lib/ext/faster_csv.rb +0 -1
- data/lib/ext/open_struct.rb +0 -17
- data/lib/fathom/agent.rb +0 -48
- data/lib/fathom/agent/agent_cluster.rb +0 -23
- data/lib/fathom/agent/properties.rb +0 -48
- data/lib/fathom/archive/causal_graph.rb +0 -12
- data/lib/fathom/archive/concept.rb +0 -83
- data/lib/fathom/archive/conditional_probability_matrix.rb +0 -119
- data/lib/fathom/archive/inverter.rb +0 -20
- data/lib/fathom/archive/n2.rb +0 -198
- data/lib/fathom/archive/n3.rb +0 -119
- data/lib/fathom/archive/node.rb +0 -97
- data/lib/fathom/archive/noodle.rb +0 -136
- data/lib/fathom/archive/scratch.rb +0 -45
- data/lib/fathom/distributions.rb +0 -8
- data/lib/fathom/distributions/discrete_gaussian.rb +0 -44
- data/lib/fathom/distributions/discrete_uniform.rb +0 -25
- data/lib/fathom/distributions/gaussian.rb +0 -46
- data/lib/fathom/distributions/uniform.rb +0 -35
- data/lib/fathom/import.rb +0 -85
- data/lib/fathom/import/csv_import.rb +0 -59
- data/lib/fathom/import/import_node.rb +0 -17
- data/lib/fathom/import/yaml_import.rb +0 -74
- data/lib/fathom/knowledge_base.rb +0 -46
- data/lib/fathom/knowledge_base/search.rb +0 -19
- data/lib/fathom/monte_carlo_set.rb +0 -152
- data/lib/fathom/node.rb +0 -139
- data/lib/fathom/node/belief_node.rb +0 -121
- data/lib/fathom/node/cpm_node.rb +0 -100
- data/lib/fathom/node/data_collection.rb +0 -97
- data/lib/fathom/node/data_node.rb +0 -22
- data/lib/fathom/node/decision.rb +0 -11
- data/lib/fathom/node/discrete_node.rb +0 -41
- data/lib/fathom/node/fact.rb +0 -24
- data/lib/fathom/node/mc_node.rb +0 -70
- data/lib/fathom/node/node_extensions/enforced_name.rb +0 -12
- data/lib/fathom/node/node_extensions/numeric_methods.rb +0 -68
- data/lib/fathom/node/plausible_range.rb +0 -98
- data/lib/fathom/simulation.rb +0 -59
- data/lib/fathom/simulation/tick_methods.rb +0 -25
- data/lib/fathom/simulation/tick_simulation.rb +0 -12
- data/lib/fathom/value_description.rb +0 -79
- data/lib/options_hash.rb +0 -186
- data/spec/ext/array_spec.rb +0 -10
- data/spec/ext/faster_csv_spec.rb +0 -10
- data/spec/ext/open_struct_spec.rb +0 -20
- data/spec/ext/string_spec.rb +0 -7
- data/spec/fathom/agent/agent_cluster_spec.rb +0 -17
- data/spec/fathom/agent_spec.rb +0 -51
- data/spec/fathom/distributions/discrete_gaussian_spec.rb +0 -64
- data/spec/fathom/distributions/discrete_uniform_spec.rb +0 -0
- data/spec/fathom/distributions/gaussian_spec.rb +0 -64
- data/spec/fathom/distributions/uniform_spec.rb +0 -0
- data/spec/fathom/import/csv_import_spec.rb +0 -52
- data/spec/fathom/import/import_node_spec.rb +0 -10
- data/spec/fathom/import/yaml_import_spec.rb +0 -73
- data/spec/fathom/import_spec.rb +0 -36
- data/spec/fathom/knowledge_base_spec.rb +0 -20
- data/spec/fathom/monte_carlo_set_spec.rb +0 -149
- data/spec/fathom/node/belief_node_spec.rb +0 -180
- data/spec/fathom/node/cpm_node_spec.rb +0 -144
- data/spec/fathom/node/data_collection_spec.rb +0 -26
- data/spec/fathom/node/data_node_spec.rb +0 -102
- data/spec/fathom/node/decision_spec.rb +0 -15
- data/spec/fathom/node/discrete_node_spec.rb +0 -56
- data/spec/fathom/node/fact_spec.rb +0 -33
- data/spec/fathom/node/mc_node_spec.rb +0 -66
- data/spec/fathom/node/node_extensions/enforced_name_spec.rb +0 -15
- data/spec/fathom/node/node_extensions/numeric_methods_spec.rb +0 -124
- data/spec/fathom/node/plausible_range_spec.rb +0 -151
- data/spec/fathom/node_spec.rb +0 -172
- data/spec/fathom/simulation/tick_simulation_spec.rb +0 -32
- data/spec/fathom/simulation_spec.rb +0 -24
- data/spec/fathom/value_description_spec.rb +0 -70
- data/spec/support/demo.yml +0 -17
- data/spec/support/demo_agent.rb +0 -8
- data/spec/support/dummy_numeric_node.rb +0 -8
- data/spec/support/fact.yml +0 -11
data/lib/fathom/node.rb
DELETED
@@ -1,139 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
-
# TODO: Move this into a proper configuration module
|
3
|
-
# require 'spira'
|
4
|
-
# @repository = RDF::Repository.new
|
5
|
-
# Spira.add_repository(:default, @repository)
|
6
|
-
|
7
|
-
class Fathom::Node
|
8
|
-
|
9
|
-
# See notes in the spec about this.
|
10
|
-
# include Spira::Resource
|
11
|
-
|
12
|
-
attr_reader :name, :distribution, :description, :values
|
13
|
-
|
14
|
-
def initialize(opts={})
|
15
|
-
symbolize_keys!(opts)
|
16
|
-
@name = opts[:name]
|
17
|
-
assert_distribution(opts)
|
18
|
-
@description = opts[:description]
|
19
|
-
@values = opts[:values]
|
20
|
-
assert_links(opts)
|
21
|
-
end
|
22
|
-
|
23
|
-
def name_sym
|
24
|
-
return nil unless self.name
|
25
|
-
@name_sym ||= self.name.to_s.downcase.gsub(/\s+|-+/, '_').to_sym
|
26
|
-
end
|
27
|
-
|
28
|
-
def parents
|
29
|
-
@parents ||= []
|
30
|
-
end
|
31
|
-
|
32
|
-
def add_parent(parent)
|
33
|
-
self.parents << parent
|
34
|
-
self.add_accessor_for_node(parent)
|
35
|
-
parent.register_child(self)
|
36
|
-
end
|
37
|
-
|
38
|
-
def register_child(child)
|
39
|
-
raise "Cannot register a child if this node is not a parent already. Use add_parent to the other node or add_child to this node." unless
|
40
|
-
child.parents.include?(self)
|
41
|
-
unless children.include?(child)
|
42
|
-
self.add_accessor_for_node(child)
|
43
|
-
children << child
|
44
|
-
end
|
45
|
-
true
|
46
|
-
end
|
47
|
-
|
48
|
-
def children
|
49
|
-
@children ||= []
|
50
|
-
end
|
51
|
-
|
52
|
-
def add_child(child)
|
53
|
-
self.children << child
|
54
|
-
self.add_accessor_for_node(child)
|
55
|
-
child.register_parent(self)
|
56
|
-
end
|
57
|
-
|
58
|
-
def register_parent(parent)
|
59
|
-
raise "Cannot register a parent if this node is not a child already. Use add_child to the other node or add_parent to this node." unless
|
60
|
-
parent.children.include?(self)
|
61
|
-
unless parents.include?(parent)
|
62
|
-
self.add_accessor_for_node(parent)
|
63
|
-
parents << parent
|
64
|
-
end
|
65
|
-
true
|
66
|
-
end
|
67
|
-
|
68
|
-
def simple_inspect
|
69
|
-
self.name ? "#{self.name} (#{self.class.to_s})" : self.class.to_s
|
70
|
-
end
|
71
|
-
|
72
|
-
def inspect
|
73
|
-
"#{self.class.to_s}: " + [
|
74
|
-
self.name,
|
75
|
-
self.description,
|
76
|
-
"children:",
|
77
|
-
self.children.map {|e| e.simple_inspect }.inspect,
|
78
|
-
"parents: ",
|
79
|
-
self.parents.map {|e| e.simple_inspect }.inspect,
|
80
|
-
].compact.join(", ")
|
81
|
-
end
|
82
|
-
|
83
|
-
protected
|
84
|
-
|
85
|
-
# Quick and dirty extract from ActiveSupport's same method
|
86
|
-
def symbolize_keys!(h)
|
87
|
-
h.keys.each do |key|
|
88
|
-
h[(key.to_sym rescue key) || key] = h.delete(key)
|
89
|
-
end
|
90
|
-
h
|
91
|
-
end
|
92
|
-
|
93
|
-
def add_accessor_for_node(node)
|
94
|
-
return false unless node.respond_to?(:name_sym) and node.name_sym
|
95
|
-
return false if self.respond_to?(node.name_sym)
|
96
|
-
(class << self; self; end).module_eval do
|
97
|
-
define_method node.name_sym do
|
98
|
-
node
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def assert_links(opts)
|
104
|
-
found = opts[:parents]
|
105
|
-
found ||= opts[:parent]
|
106
|
-
found ||= []
|
107
|
-
found = [found] unless found.is_a?(Array)
|
108
|
-
found.each do |parent|
|
109
|
-
add_parent(parent)
|
110
|
-
end
|
111
|
-
|
112
|
-
found = opts[:children]
|
113
|
-
found ||= opts[:child]
|
114
|
-
found ||= []
|
115
|
-
found = [found] unless found.is_a?(Array)
|
116
|
-
found.each do |child|
|
117
|
-
add_child(child)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def assert_distribution(opts)
|
122
|
-
case opts[:distribution]
|
123
|
-
when Class
|
124
|
-
@distribution = opts[:distribution]
|
125
|
-
when Symbol
|
126
|
-
class_name = opts[:distribution].to_s.downcase.split(/_+/).map {|t| t[0].chr.upcase + t[1..-1]}.join
|
127
|
-
if Fathom::Distributions.constants.include?(class_name)
|
128
|
-
@distribution = "Fathom::Distributions::#{class_name}".constantize
|
129
|
-
end
|
130
|
-
end
|
131
|
-
@distribution ||= Fathom::Distributions::Gaussian
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
if __FILE__ == $0
|
136
|
-
include Fathom
|
137
|
-
# TODO: Is there anything you want to do to run this file on its own?
|
138
|
-
# Node.new
|
139
|
-
end
|
@@ -1,121 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
class Fathom::BeliefNode < DiscreteNode
|
3
|
-
|
4
|
-
attr_reader :probabilities, :likelihoods, :precision_threshold
|
5
|
-
|
6
|
-
def initialize(opts={})
|
7
|
-
super(opts)
|
8
|
-
assert_probabilities(opts)
|
9
|
-
assert_liklihoods(opts)
|
10
|
-
@precision_threshold = opts.fetch(:precision_threshold, 0.00001)
|
11
|
-
end
|
12
|
-
|
13
|
-
def add_child(child)
|
14
|
-
if child.is_a?(BeliefNode)
|
15
|
-
cpm = CPMNode.new(:parent => self, :child => child)
|
16
|
-
# self.children << cpm
|
17
|
-
self.add_accessor_for_cpm(cpm, child)
|
18
|
-
self.add_accessor_for_node(child)
|
19
|
-
# cpm.register_parent(self)
|
20
|
-
self.children << child
|
21
|
-
child.register_parent(self)
|
22
|
-
child.add_accessor_for_cpm(cpm, self)
|
23
|
-
else
|
24
|
-
super(child)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def add_parent(parent)
|
29
|
-
if parent.is_a?(BeliefNode)
|
30
|
-
cpm = CPMNode.new(:parent => parent, :child => self)
|
31
|
-
# self.parents << cpm
|
32
|
-
self.add_accessor_for_cpm(cpm, parent)
|
33
|
-
self.add_accessor_for_node(parent)
|
34
|
-
# cpm.register_child(self)
|
35
|
-
self.parents << parent
|
36
|
-
parent.register_child(self)
|
37
|
-
parent.add_accessor_for_cpm(cpm, self)
|
38
|
-
else
|
39
|
-
super(parent)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def inspect
|
44
|
-
"#{self.class.to_s}: " + [
|
45
|
-
self.name,
|
46
|
-
self.description,
|
47
|
-
"children:",
|
48
|
-
self.children.map {|e| e.is_a?(CPMNode) ? e.child.simple_inspect : e.simple_inspect }.inspect,
|
49
|
-
"parents: ",
|
50
|
-
self.parents.map {|e| e.is_a?(CPMNode) ? e.parent.simple_inspect : e.simple_inspect }.inspect,
|
51
|
-
].compact.join(", ")
|
52
|
-
end
|
53
|
-
|
54
|
-
def add_accessor_for_cpm(cpm, node)
|
55
|
-
return false unless cpm.is_a?(CPMNode) and cpm.name_sym
|
56
|
-
method_name = ("cpm_for_" + node.name_sym.to_s).to_sym
|
57
|
-
return false if self.respond_to?(method_name)
|
58
|
-
(class << self; self; end).module_eval do
|
59
|
-
define_method method_name do
|
60
|
-
cpm
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def likelihood(label)
|
66
|
-
OpenStruct.new
|
67
|
-
end
|
68
|
-
|
69
|
-
protected
|
70
|
-
|
71
|
-
|
72
|
-
def assert_probabilities(opts)
|
73
|
-
return assert_probabilities_and_labels_from_values_hash(opts[:values]) if
|
74
|
-
opts[:values] and opts[:values].is_a?(Hash)
|
75
|
-
|
76
|
-
unnormalized_obj = opts.fetch(:probabilities, Array.new(self.size, 1.0))
|
77
|
-
unnormalized_vector = case unnormalized_obj
|
78
|
-
when Array
|
79
|
-
GSL::Vector.ary_to_gv(unnormalized_obj)
|
80
|
-
when GSL::Vector
|
81
|
-
unnormalized_obj
|
82
|
-
else
|
83
|
-
GSL::Vector[unnormalized_obj]
|
84
|
-
end
|
85
|
-
|
86
|
-
raise ArgumentError, "Probabilities must be #{self.size} items long" unless
|
87
|
-
unnormalized_vector.size == self.size
|
88
|
-
|
89
|
-
sum = unnormalized_vector.sum
|
90
|
-
@probabilities = unnormalized_vector.map {|e| e / sum }
|
91
|
-
end
|
92
|
-
|
93
|
-
def assert_probabilities_and_labels_from_values_hash(values)
|
94
|
-
@labels, probabilities = values.inject([[], []]) do |list, e|
|
95
|
-
list.first << e.first
|
96
|
-
list.last << e.last
|
97
|
-
list
|
98
|
-
end
|
99
|
-
@probabilities = GSL::Vector.ary_to_gv(probabilities)
|
100
|
-
end
|
101
|
-
|
102
|
-
def assert_liklihoods(opts)
|
103
|
-
likelihoods = opts.fetch(:likelihoods, Array.new(self.size, 1.0))
|
104
|
-
@likelihoods = case likelihoods
|
105
|
-
when Array
|
106
|
-
GSL::Vector.ary_to_gv(likelihoods)
|
107
|
-
when GSL::Vector
|
108
|
-
likelihoods
|
109
|
-
else
|
110
|
-
GSL::Vector[likelihoods]
|
111
|
-
end
|
112
|
-
raise ArgumentError, "Likelihoods must be #{self.size} items long" unless
|
113
|
-
likelihoods.size == self.size
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
if __FILE__ == $0
|
118
|
-
include Fathom
|
119
|
-
# TODO: Is there anything you want to do to run this file on its own?
|
120
|
-
# BeliefNode.new
|
121
|
-
end
|
data/lib/fathom/node/cpm_node.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
|
3
|
-
# Conditional Probability Matrix to join two nodes
|
4
|
-
class Fathom::CPMNode < Fathom::Node
|
5
|
-
|
6
|
-
def initialize(opts={})
|
7
|
-
ensure_belief_nodes(opts)
|
8
|
-
super(opts)
|
9
|
-
assert_name
|
10
|
-
assert_description
|
11
|
-
assert_cpm
|
12
|
-
end
|
13
|
-
|
14
|
-
def parent
|
15
|
-
parents.first
|
16
|
-
end
|
17
|
-
|
18
|
-
def child
|
19
|
-
children.first
|
20
|
-
end
|
21
|
-
|
22
|
-
alias :matrix :values
|
23
|
-
|
24
|
-
# Filter values from the matrix. Allows us to grab multiple rows and columns if desired.
|
25
|
-
# If the rows or columns aren't filtered, all values are assumed to be desired.
|
26
|
-
#
|
27
|
-
# @cpm.probability :child_node_name => [:desired, :values], :parent_node_name => :value
|
28
|
-
# This filters both the child columns and the parent rows
|
29
|
-
#
|
30
|
-
# @cpm.probability :child_node_name => [:desired, :values]
|
31
|
-
# This only filters the child columns
|
32
|
-
def probability(opts={})
|
33
|
-
# Are we using long descriptions for the return value?
|
34
|
-
# If so, we'll use a hash to describe it without having to parse the value out of a string later.
|
35
|
-
describe = opts.delete(:describe) || false
|
36
|
-
|
37
|
-
# Is something unknown being asked for?
|
38
|
-
allowed = [parent.name_sym, child.name_sym]
|
39
|
-
unknown_keys = opts.reject {|k, v| allowed.include?(k)}
|
40
|
-
raise ArgumentError, "Unknown node: #{unknown_keys.inspect}" unless unknown_keys.empty?
|
41
|
-
|
42
|
-
# Values for the desired child and parent values
|
43
|
-
child_values = Array(opts[self.child.name_sym] || self.child.labels)
|
44
|
-
parent_values = Array(opts[self.parent.name_sym] || self.parent.labels)
|
45
|
-
|
46
|
-
# Indices in the matrix for the desired values
|
47
|
-
child_indices = child_values.map {|c| self.child.labels.index(c)}
|
48
|
-
parent_indices = parent_values.map {|c| self.parent.labels.index(c)}
|
49
|
-
|
50
|
-
# Collect the filtered values from the matrix
|
51
|
-
value = parent_indices.inject(0.0) do |sum, row|
|
52
|
-
sum += child_indices.inject(0.0) do |s, col|
|
53
|
-
s += matrix.get(row, col)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
return value unless describe
|
58
|
-
|
59
|
-
label = "P(" +
|
60
|
-
child_values.map(&:to_s).join(" or ") +
|
61
|
-
" | " +
|
62
|
-
parent_values.map(&:to_s).join(" or ") +
|
63
|
-
")"
|
64
|
-
{ label => value }
|
65
|
-
|
66
|
-
end
|
67
|
-
alias :p :probability
|
68
|
-
|
69
|
-
def odds(opts={})
|
70
|
-
p = probability(opts)
|
71
|
-
return p / (1 - p)
|
72
|
-
end
|
73
|
-
alias :o :odds
|
74
|
-
|
75
|
-
# Returns a vector of likelihoods for each parent value, given the child value
|
76
|
-
def likelihood(value)
|
77
|
-
GSL::Vector.alloc(
|
78
|
-
*parent.labels.map {|parent_label| probability(parent.name_sym => parent_label, child.name_sym => value)}
|
79
|
-
)
|
80
|
-
end
|
81
|
-
alias :l :likelihood
|
82
|
-
|
83
|
-
protected
|
84
|
-
def assert_name
|
85
|
-
@name ||= :cpm
|
86
|
-
end
|
87
|
-
|
88
|
-
def assert_description
|
89
|
-
@description ||= "Conditional Probability Matrix from #{parent.name.to_s} to #{child.name.to_s}."
|
90
|
-
end
|
91
|
-
|
92
|
-
def ensure_belief_nodes(opts)
|
93
|
-
raise ArgumentError, "The child must be a BeliefNode" unless opts[:child].is_a?(BeliefNode)
|
94
|
-
raise ArgumentError, "The parent must be a BeliefNode" unless opts[:parent].is_a?(BeliefNode)
|
95
|
-
end
|
96
|
-
|
97
|
-
def assert_cpm
|
98
|
-
@values = self.parent.probabilities.col * self.child.probabilities
|
99
|
-
end
|
100
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
|
3
|
-
=begin
|
4
|
-
This class uses SQLite for in-memory set operations. It is based on a discrete variable
|
5
|
-
which can be translated into fields in a table. For now, I am just using float data
|
6
|
-
types for the fields. This will evolve as needs drive it into a more robust data set.
|
7
|
-
|
8
|
-
It turns out that SQLite set operations are quite fast and speed things up pretty well.
|
9
|
-
So, to use this class, you'll need to have sqlite3-ruby SQLite3 bindings installed.
|
10
|
-
|
11
|
-
This also uses uuid to enforce a node name, an additional dependency.
|
12
|
-
=end
|
13
|
-
|
14
|
-
require 'uuid'
|
15
|
-
|
16
|
-
class Fathom::DataCollection < DiscreteNode
|
17
|
-
|
18
|
-
def initialize(opts={})
|
19
|
-
opts = extract_labels(opts)
|
20
|
-
opts[:name] ||= UUID.generate
|
21
|
-
super(opts)
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
protected
|
26
|
-
|
27
|
-
# Looking for labels.
|
28
|
-
# Using :labels, then :parents, then :parent, looking for the first node with labels defined
|
29
|
-
def extract_labels(opts)
|
30
|
-
return opts if opts[:labels]
|
31
|
-
parents = opts[:parents]
|
32
|
-
parents ||= opts[:parent]
|
33
|
-
parents = Array[parents] if parents and not parents.is_a?(Array)
|
34
|
-
parents.each do |parent|
|
35
|
-
if parent.respond_to?(:labels)
|
36
|
-
opts[:labels] = parent.labels
|
37
|
-
return opts
|
38
|
-
end
|
39
|
-
end
|
40
|
-
opts
|
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
|
-
# DataCollection.new
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
# J2: Some bare-minimum sqlite3 stuff
|
53
|
-
# See: http://sqlite-ruby.rubyforge.org/
|
54
|
-
# require 'rubygems'
|
55
|
-
# require 'sqlite3'
|
56
|
-
#
|
57
|
-
# def prepare_database(table_name)
|
58
|
-
# @db = SQLite3::Database.new(":memory:")
|
59
|
-
# # @db = SQLite3::Database.new("/tmp/j2.db")
|
60
|
-
#
|
61
|
-
# create_sql = <<-SQL
|
62
|
-
#
|
63
|
-
# CREATE TABLE "#{table_name}" (
|
64
|
-
# "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
65
|
-
# "field1" FLOAT);
|
66
|
-
# SQL
|
67
|
-
# @db.execute_batch(create_sql)
|
68
|
-
#
|
69
|
-
# insert_sql = <<-SQL
|
70
|
-
# INSERT INTO #{table_name}
|
71
|
-
# ("field1")
|
72
|
-
# VALUES
|
73
|
-
# (:field1);
|
74
|
-
# SQL
|
75
|
-
# @insert_record = @db.prepare(insert_sql)
|
76
|
-
#
|
77
|
-
# # select_sql = <<-SQL
|
78
|
-
# # "select * from 'asdf';"
|
79
|
-
# # SQL
|
80
|
-
# # @select_record = @db.prepare(select_sql)
|
81
|
-
# @select_record = @db.prepare( "select * from asdf" )
|
82
|
-
# end
|
83
|
-
#
|
84
|
-
# def insert_record(opts)
|
85
|
-
# @insert_record.bind_params(:field1 => opts[:field1])
|
86
|
-
# @insert_record.execute
|
87
|
-
# end
|
88
|
-
#
|
89
|
-
# def select_record(opts={})
|
90
|
-
# # @db.execute( "select * from 'asdf'" )
|
91
|
-
# @select_record.execute.entries
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# prepare_database('asdf')
|
95
|
-
# insert_record :field1 => 123.1
|
96
|
-
# insert_record :field1 => 122.2
|
97
|
-
# @a = select_record
|