fathom 0.3.0 → 0.3.1
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/.autotest +10 -0
- data/Gemfile +10 -2
- data/Gemfile.lock +8 -0
- data/TODO.md +12 -25
- data/VERSION +1 -1
- data/lib/{fathom/ext → ext}/array.rb +0 -0
- data/lib/{fathom/ext → ext}/faster_csv.rb +0 -0
- data/lib/{fathom/ext → ext}/open_struct.rb +0 -0
- data/lib/{fathom/ext → ext}/string.rb +0 -0
- data/lib/fathom.rb +16 -13
- data/lib/fathom/agent.rb +8 -9
- data/lib/fathom/{causal_graph.rb → archive/causal_graph.rb} +0 -0
- data/lib/fathom/{concept.rb → archive/concept.rb} +0 -0
- data/lib/fathom/archive/conditional_probability_matrix.rb +3 -0
- data/lib/fathom/{inverter.rb → archive/inverter.rb} +0 -0
- data/lib/fathom/archive/node.rb +24 -1
- data/lib/fathom/distributions/discrete_uniform.rb +11 -32
- data/lib/fathom/import.rb +37 -34
- data/lib/fathom/import/yaml_import.rb +22 -1
- data/lib/fathom/knowledge_base.rb +34 -23
- data/lib/fathom/knowledge_base/search.rb +19 -0
- data/lib/fathom/node.rb +32 -1
- data/lib/fathom/node/belief_node.rb +121 -0
- data/lib/fathom/node/cpm_node.rb +100 -0
- data/lib/fathom/node/data_collection.rb +97 -0
- data/lib/fathom/{data_node.rb → node/data_node.rb} +1 -1
- data/lib/fathom/{value_aggregator.rb → node/decision.rb} +5 -5
- data/lib/fathom/node/discrete_node.rb +41 -0
- data/lib/fathom/node/fact.rb +24 -0
- data/lib/fathom/{mc_node.rb → node/mc_node.rb} +1 -1
- data/lib/fathom/{enforced_name.rb → node/node_extensions/enforced_name.rb} +1 -1
- data/lib/fathom/{numeric_methods.rb → node/node_extensions/numeric_methods.rb} +19 -1
- data/lib/fathom/{plausible_range.rb → node/plausible_range.rb} +1 -1
- data/spec/ext/array_spec.rb +10 -0
- data/spec/ext/faster_csv_spec.rb +10 -0
- data/spec/ext/open_struct_spec.rb +20 -0
- data/spec/ext/string_spec.rb +7 -0
- data/spec/fathom/import/csv_import_spec.rb +11 -9
- data/spec/fathom/import/yaml_import_spec.rb +27 -7
- data/spec/fathom/knowledge_base_spec.rb +8 -4
- data/spec/fathom/node/belief_node_spec.rb +180 -0
- data/spec/fathom/node/cpm_node_spec.rb +144 -0
- data/spec/fathom/node/data_collection_spec.rb +26 -0
- data/spec/fathom/{data_node_spec.rb → node/data_node_spec.rb} +1 -1
- data/spec/fathom/node/decision_spec.rb +15 -0
- data/spec/fathom/node/discrete_node_spec.rb +56 -0
- data/spec/fathom/node/fact_spec.rb +33 -0
- data/spec/fathom/{mc_node_spec.rb → node/mc_node_spec.rb} +1 -1
- data/spec/fathom/{enforced_name_spec.rb → node/node_extensions/enforced_name_spec.rb} +1 -1
- data/spec/fathom/{numeric_methods_spec.rb → node/node_extensions/numeric_methods_spec.rb} +53 -11
- data/spec/fathom/{plausible_range_spec.rb → node/plausible_range_spec.rb} +1 -1
- data/spec/fathom/node_spec.rb +17 -0
- data/spec/fathom_spec.rb +40 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/fact.yml +11 -0
- metadata +57 -30
- data/lib/fathom/value_multiplier.rb +0 -18
data/.autotest
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# require 'autotest/fsevent'
|
2
|
+
# require 'autotest/growl'
|
3
|
+
|
4
|
+
Autotest.add_hook :initialize do |autotest|
|
5
|
+
# Keeps me from calling something document_spec.rb
|
6
|
+
# %w{.git .svn .hg .DS_Store ._* vendor tmp log doc}.each do |exception|
|
7
|
+
%w{.git .svn .hg .DS_Store ._* vendor tmp log}.each do |exception|
|
8
|
+
autotest.add_exception(exception)
|
9
|
+
end
|
10
|
+
end
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
ZenTest (4.4.0)
|
5
|
+
addressable (2.2.2)
|
4
6
|
columnize (0.3.1)
|
5
7
|
diff-lcs (1.1.2)
|
6
8
|
fastercsv (1.5.3)
|
7
9
|
linecache (0.43)
|
8
10
|
macaddr (1.0.0)
|
11
|
+
rdf (0.3.0.pre)
|
12
|
+
addressable (>= 2.2)
|
9
13
|
rspec (2.0.1)
|
10
14
|
rspec-core (~> 2.0.1)
|
11
15
|
rspec-expectations (~> 2.0.1)
|
@@ -21,6 +25,8 @@ GEM
|
|
21
25
|
ruby-debug-base (~> 0.10.3.0)
|
22
26
|
ruby-debug-base (0.10.3)
|
23
27
|
linecache (>= 0.3)
|
28
|
+
sparql-algebra (0.0.1)
|
29
|
+
rdf (= 0.3.0.pre)
|
24
30
|
uuid (2.3.1)
|
25
31
|
macaddr (~> 1.0)
|
26
32
|
|
@@ -28,7 +34,9 @@ PLATFORMS
|
|
28
34
|
ruby
|
29
35
|
|
30
36
|
DEPENDENCIES
|
37
|
+
ZenTest
|
31
38
|
fastercsv
|
32
39
|
rspec
|
33
40
|
ruby-debug
|
41
|
+
sparql-algebra
|
34
42
|
uuid
|
data/TODO.md
CHANGED
@@ -1,30 +1,7 @@
|
|
1
1
|
TODO
|
2
2
|
====
|
3
3
|
|
4
|
-
|
5
|
-
------------
|
6
|
-
|
7
|
-
I've just made some big refactoring steps regarding the organization of the system and the distributions. To make sure we're there:
|
8
|
-
|
9
|
-
* Go back and test the 4 distributions I decided on
|
10
|
-
* Finish the discrete ideas, adding size to the node and automatically using that for stats
|
11
|
-
* Create the idea of a labeled, multinomial node
|
12
|
-
* Add SQLite3 for in-memory set operations for a labeled, multinomial node
|
13
|
-
* Make sure we are not defining methods on all objects in a class when they should only be set for a single object.
|
14
|
-
|
15
|
-
Also, the general organization of the system could be broken down better:
|
16
|
-
|
17
|
-
* agent
|
18
|
-
* distributions
|
19
|
-
* node
|
20
|
-
* import
|
21
|
-
* causal_graph
|
22
|
-
* belief_network
|
23
|
-
* knowledge_base
|
24
|
-
* apophenia
|
25
|
-
* simulation
|
26
|
-
|
27
|
-
Belief Networks (0.3)
|
4
|
+
Belief Networks (0.3.1)
|
28
5
|
---------------
|
29
6
|
|
30
7
|
To get these delivered, I need to revisit the edge logic, to make sure it's easy to extend each edge with an object.
|
@@ -35,11 +12,21 @@ Then:
|
|
35
12
|
* Network propagation
|
36
13
|
* Network testing (polytree)
|
37
14
|
|
38
|
-
|
15
|
+
Reorganizing (0.3.2)
|
16
|
+
------------
|
17
|
+
|
18
|
+
I've just made some big refactoring steps regarding the organization of the system and the distributions. To make sure we're there:
|
19
|
+
|
20
|
+
* Fix the inheritance structure
|
21
|
+
* Go back and test the 4 distributions I decided on
|
22
|
+
* Add SQLite3 for in-memory set operations for a labeled, multinomial node
|
23
|
+
|
24
|
+
Agent Based Modeling (0.3.3)
|
39
25
|
--------------------
|
40
26
|
|
41
27
|
* Add parameter-passing standards for callbacks
|
42
28
|
* Add EventMachine and async capabilities (Including the cluster idea)
|
29
|
+
* Make sure the scope of dynamic methods defined are correct (class, object, singleton) (on properties and simulation)
|
43
30
|
|
44
31
|
Knowledge Base (0.4)
|
45
32
|
--------------
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/lib/fathom.rb
CHANGED
@@ -21,24 +21,27 @@ module Fathom
|
|
21
21
|
|
22
22
|
# Autoload classes and modules so that we only load as much of the library as we're using.
|
23
23
|
# This allows us to have a fairly large library without taking up a lot of memory unless we need it.
|
24
|
-
autoload :Inverter, "inverter"
|
25
24
|
autoload :Node, "node"
|
26
|
-
autoload :
|
25
|
+
autoload :BeliefNode, "node/belief_node"
|
26
|
+
autoload :DataCollection, "node/data_collection"
|
27
|
+
autoload :DataNode, "node/data_node"
|
28
|
+
autoload :DiscreteNode, "node/discrete_node"
|
29
|
+
autoload :MCNode, "node/mc_node"
|
30
|
+
autoload :PlausibleRange, "node/plausible_range"
|
31
|
+
autoload :Fact, "node/fact"
|
32
|
+
autoload :Decision, "node/decision"
|
33
|
+
autoload :CPMNode, 'node/cpm_node'
|
34
|
+
|
27
35
|
autoload :ValueDescription, "value_description"
|
28
|
-
autoload :ValueAggregator, "value_aggregator"
|
29
|
-
autoload :ValueMultiplier, "value_multiplier"
|
30
36
|
autoload :MonteCarloSet, "monte_carlo_set"
|
31
|
-
autoload :MCNode, "mc_node"
|
32
|
-
autoload :CausalGraph, "causal_graph"
|
33
|
-
autoload :DataNode, "data_node"
|
34
37
|
autoload :KnowledgeBase, "knowledge_base"
|
35
38
|
|
36
39
|
autoload :Import, "import"
|
37
40
|
autoload :ImportNode, "import/import_node"
|
38
41
|
autoload :YAMLImport, 'import/yaml_import'
|
39
42
|
autoload :CSVImport, 'import/csv_import'
|
40
|
-
autoload :RDFImport, 'import/rdf_import'
|
41
|
-
autoload :SQLiteImport, 'import/sqlite_import'
|
43
|
+
# autoload :RDFImport, 'import/rdf_import'
|
44
|
+
# autoload :SQLiteImport, 'import/sqlite_import'
|
42
45
|
|
43
46
|
autoload :Simulation, 'simulation'
|
44
47
|
autoload :TickMethods, 'simulation/tick_methods'
|
@@ -48,10 +51,10 @@ module Fathom
|
|
48
51
|
autoload :Properties, 'agent/properties'
|
49
52
|
autoload :AgentCluster, 'agent/agent_cluster'
|
50
53
|
|
51
|
-
autoload :
|
52
|
-
autoload :
|
54
|
+
autoload :EnforcedName, 'node/node_extensions/enforced_name'
|
55
|
+
autoload :NumericMethods, 'node/node_extensions/numeric_methods'
|
53
56
|
|
54
|
-
|
57
|
+
require 'distributions'
|
55
58
|
module Distributions
|
56
59
|
autoload :Gaussian, 'distributions/gaussian'
|
57
60
|
autoload :Uniform, 'distributions/uniform'
|
@@ -66,4 +69,4 @@ module Fathom
|
|
66
69
|
end
|
67
70
|
|
68
71
|
# Temporary
|
69
|
-
include Fathom
|
72
|
+
# include Fathom
|
data/lib/fathom/agent.rb
CHANGED
@@ -4,14 +4,6 @@ class Fathom::Agent
|
|
4
4
|
# =================
|
5
5
|
# = Class Methods =
|
6
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
7
|
|
16
8
|
include Properties
|
17
9
|
|
@@ -36,7 +28,14 @@ class Fathom::Agent
|
|
36
28
|
nodes.each do |name, node|
|
37
29
|
next unless self.class.properties.include?(name)
|
38
30
|
states[name] = node.respond_to?(:rand) ? node.rand : node
|
39
|
-
|
31
|
+
|
32
|
+
method_name = ("node_for_" + name.to_s.downcase.gsub(/\s+/, '_')).to_sym
|
33
|
+
(class << self; self; end).module_eval do
|
34
|
+
define_method method_name do
|
35
|
+
node
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
File without changes
|
File without changes
|
File without changes
|
data/lib/fathom/archive/node.rb
CHANGED
@@ -23,7 +23,10 @@ class Node
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def inspect
|
26
|
-
|
26
|
+
matched_array = []
|
27
|
+
self.labels.each_with_index {|e, i| matched_array << e; matched_array << self.probabilities[i]}
|
28
|
+
"Node: #{self.name.to_s} #{self.labels.inspect} #{self.probabilities.to_a.inspect}"
|
29
|
+
"Node: #{self.name.to_s} #{matched_array.inspect}"
|
27
30
|
end
|
28
31
|
|
29
32
|
def belief
|
@@ -34,7 +37,27 @@ class Node
|
|
34
37
|
alias :l :likelihood
|
35
38
|
alias :p :probabilities
|
36
39
|
|
40
|
+
def probability(label)
|
41
|
+
probabilities[index_for(label)]
|
42
|
+
end
|
43
|
+
|
44
|
+
def inverse_probability(label)
|
45
|
+
1 - probability(label)
|
46
|
+
end
|
47
|
+
|
48
|
+
def odds(label)
|
49
|
+
probability(label) / inverse_probability(label)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_a
|
53
|
+
self.probabilities.to_a
|
54
|
+
end
|
55
|
+
|
37
56
|
protected
|
57
|
+
|
58
|
+
def index_for(label)
|
59
|
+
labels.index(label)
|
60
|
+
end
|
38
61
|
|
39
62
|
def assert_likelihood
|
40
63
|
@likelihood = Vector.ary_to_gv(Array.new(@probabilities.size, 1))
|
@@ -6,40 +6,19 @@ class Fathom::Distributions::DiscreteUniform
|
|
6
6
|
@rng ||= GSL::Rng.alloc(GSL::Rng::MT19937_1999, Kernel.rand(100_000))
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
sd ||= opts[:std]
|
17
|
-
sd ||= opts[:standard_deviation]
|
18
|
-
lower = opts.fetch(:lower, true)
|
19
|
-
lower = false if opts[:upper]
|
20
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.05)
|
21
|
-
value = lower ? GSL::Cdf.ugaussian_Pinv(confidence_interval) : GSL::Cdf.ugaussian_Qinv(confidence_interval)
|
22
|
-
value + mean
|
23
|
-
end
|
24
|
-
alias :lower_bound :inverse_cdf
|
25
|
-
|
26
|
-
def upper_bound(opts={})
|
27
|
-
inverse_cdf(opts.merge(:lower => false))
|
28
|
-
end
|
29
|
-
|
30
|
-
def interval_values(opts={})
|
31
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.9)
|
32
|
-
bound = (1 - confidence_interval) / 2.0
|
33
|
-
[lower_bound(opts.merge(:confidence_interval => bound)), upper_bound(opts.merge(:confidence_interval => bound))]
|
34
|
-
end
|
35
|
-
|
36
|
-
# If only I had the background to explain what this is....
|
37
|
-
# I want to know how many standard deviations are expressed by the confidence interval
|
38
|
-
# I can then divide the range by this number to get the standard deviation
|
39
|
-
def standard_deviations_under(confidence_interval)
|
40
|
-
GSL::Cdf.ugaussian_Qinv((1 - confidence_interval) / 2) * 2
|
9
|
+
# Bounded from 0 to size - 1
|
10
|
+
def rand(size)
|
11
|
+
value = get_rand(size)
|
12
|
+
while value < 0 or value >= size
|
13
|
+
value = get_rand(size)
|
14
|
+
end
|
15
|
+
value
|
41
16
|
end
|
42
17
|
|
18
|
+
protected
|
19
|
+
def get_rand(size)
|
20
|
+
(rng.ugaussian / size).floor + 1
|
21
|
+
end
|
43
22
|
|
44
23
|
end
|
45
24
|
end
|
data/lib/fathom/import.rb
CHANGED
@@ -33,50 +33,53 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
|
33
33
|
This way data from spreadsheets or YAML files can easily be added to the knowledge base.
|
34
34
|
|
35
35
|
=end
|
36
|
-
|
36
|
+
|
37
|
+
module Fathom
|
38
|
+
class Import
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
class << self
|
41
|
+
def import(opts={})
|
42
|
+
importer = new(opts)
|
43
|
+
importer.import
|
44
|
+
end
|
42
45
|
end
|
43
|
-
end
|
44
46
|
|
45
|
-
|
47
|
+
attr_reader :content, :options, :import_node
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
def initialize(opts={})
|
50
|
+
@options = OptionsHash.new(opts)
|
51
|
+
@content = @options[:content]
|
52
|
+
@import_node = ImportNode.new(opts)
|
53
|
+
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
def import
|
56
|
+
import_methods.each do |method|
|
57
|
+
klass, initialization_data = self.send(method.to_sym)
|
58
|
+
initialization_data.each do |values|
|
59
|
+
extract_nodes(klass, values)
|
60
|
+
end
|
58
61
|
end
|
62
|
+
self.import_node
|
59
63
|
end
|
60
|
-
self.import_node
|
61
|
-
end
|
62
64
|
|
63
|
-
|
65
|
+
protected
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
# Just blankly try to initiate a node. If it fails, silently fail for now.
|
68
|
+
def extract_nodes(klass, values)
|
69
|
+
begin
|
70
|
+
node = klass.new(values)
|
71
|
+
if node
|
72
|
+
self.import_node.add_child(node)
|
73
|
+
Fathom.knowledge_base[node.name] = node
|
74
|
+
end
|
75
|
+
rescue
|
76
|
+
nil
|
72
77
|
end
|
73
|
-
rescue
|
74
|
-
nil
|
75
78
|
end
|
76
|
-
end
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
def import_methods
|
81
|
+
(self.methods - self.class.superclass.instance_methods).map {|m| m if m =~ /import_\w+/}.compact
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
82
85
|
end
|
@@ -2,7 +2,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom')
|
|
2
2
|
require 'open-uri'
|
3
3
|
require 'yaml'
|
4
4
|
|
5
|
-
class Fathom::YAMLImport < Import
|
5
|
+
class Fathom::YAMLImport < Fathom::Import
|
6
6
|
def import_plausible_ranges
|
7
7
|
assert_yaml_content
|
8
8
|
plausible_ranges = extract_plausible_ranges
|
@@ -15,6 +15,12 @@ class Fathom::YAMLImport < Import
|
|
15
15
|
[DataNode, data_nodes]
|
16
16
|
end
|
17
17
|
|
18
|
+
def import_facts
|
19
|
+
assert_yaml_content
|
20
|
+
facts = extract_facts
|
21
|
+
[Fact, facts]
|
22
|
+
end
|
23
|
+
|
18
24
|
protected
|
19
25
|
def assert_yaml_content
|
20
26
|
return @yaml_content if @yaml_content
|
@@ -27,7 +33,21 @@ class Fathom::YAMLImport < Import
|
|
27
33
|
@yaml_content = YAML.load(file_contents)
|
28
34
|
end
|
29
35
|
|
36
|
+
def extract_facts
|
37
|
+
return [] unless @yaml_content
|
38
|
+
output = []
|
39
|
+
@yaml_content.each do |e|
|
40
|
+
next unless e.is_a?(Array)
|
41
|
+
next unless e.first.to_s.match(/fact/i)
|
42
|
+
obj = e[1]
|
43
|
+
next unless obj.is_a?(Hash)
|
44
|
+
output << obj
|
45
|
+
end
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
30
49
|
def extract_plausible_ranges
|
50
|
+
return [] unless @yaml_content
|
31
51
|
@yaml_content.inject([]) do |list, array|
|
32
52
|
name, value = array.first, array.last
|
33
53
|
if value.is_a?(Hash)
|
@@ -40,6 +60,7 @@ class Fathom::YAMLImport < Import
|
|
40
60
|
end
|
41
61
|
|
42
62
|
def extract_data_nodes
|
63
|
+
return [] unless @yaml_content
|
43
64
|
@yaml_content.inject([]) do |list, array|
|
44
65
|
name, value = array.first, array.last
|
45
66
|
list << {:name => name, :values => value} if value.is_a?(Array)
|