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
@@ -1,25 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
class Fathom::Distributions::DiscreteUniform
|
3
|
-
extend Fathom::Distributions::SharedMethods
|
4
|
-
class << self
|
5
|
-
def rng
|
6
|
-
@rng ||= GSL::Rng.alloc(GSL::Rng::MT19937_1999, Kernel.rand(100_000))
|
7
|
-
end
|
8
|
-
|
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
|
16
|
-
end
|
17
|
-
|
18
|
-
protected
|
19
|
-
def get_rand(size)
|
20
|
-
(rng.ugaussian / size).floor + 1
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
class Fathom::Distributions::Gaussian
|
3
|
-
extend Fathom::Distributions::SharedMethods
|
4
|
-
class << self
|
5
|
-
def rng
|
6
|
-
@rng ||= GSL::Rng.alloc(GSL::Rng::MT19937_1999, Kernel.rand(100_000))
|
7
|
-
end
|
8
|
-
|
9
|
-
def rand(sd)
|
10
|
-
rng.gaussian(sd)
|
11
|
-
end
|
12
|
-
|
13
|
-
def inverse_cdf(opts={})
|
14
|
-
mean = opts[:mean]
|
15
|
-
sd = opts[:sd]
|
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.gaussian_Pinv(confidence_interval, sd) : GSL::Cdf.gaussian_Qinv(confidence_interval, sd)
|
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.gaussian_Qinv((1 - confidence_interval) / 2) * 2
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
class Fathom::Distributions::Uniform
|
3
|
-
extend Fathom::Distributions::SharedMethods
|
4
|
-
class << self
|
5
|
-
def rng
|
6
|
-
@rng ||= GSL::Rng.alloc(GSL::Rng::MT19937_1999, Kernel.rand(100_000))
|
7
|
-
end
|
8
|
-
|
9
|
-
def rand
|
10
|
-
rng.ugaussian
|
11
|
-
end
|
12
|
-
|
13
|
-
def inverse_cdf(opts={})
|
14
|
-
mean = opts[:mean]
|
15
|
-
lower = opts.fetch(:lower, true)
|
16
|
-
lower = false if opts[:upper]
|
17
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.05)
|
18
|
-
value = lower ? GSL::Cdf.ugaussian_Pinv(confidence_interval) : GSL::Cdf.ugaussian_Qinv(confidence_interval)
|
19
|
-
value + mean
|
20
|
-
end
|
21
|
-
alias :lower_bound :inverse_cdf
|
22
|
-
|
23
|
-
def upper_bound(opts={})
|
24
|
-
inverse_cdf(opts.merge(:lower => false))
|
25
|
-
end
|
26
|
-
|
27
|
-
def interval_values(opts={})
|
28
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.9)
|
29
|
-
bound = (1 - confidence_interval) / 2.0
|
30
|
-
[lower_bound(opts.merge(:confidence_interval => bound)), upper_bound(opts.merge(:confidence_interval => bound))]
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
data/lib/fathom/import.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
-
|
3
|
-
=begin
|
4
|
-
|
5
|
-
The import scripts are meant to make it easier to build up a knowledge base from
|
6
|
-
real data. There are a lot of ways we could get our data: YAML files, spreadsheets,
|
7
|
-
web crawlers, relational databases, RDF data. The Import class creates a regular
|
8
|
-
way to create nodes in the knowledge base. The following example would be a
|
9
|
-
simple way to import some data about weekend trips:
|
10
|
-
|
11
|
-
class WeekendPlanningImport < Import
|
12
|
-
def import_plausible_data
|
13
|
-
values = [
|
14
|
-
{:name => 'Chance of Rain', :min => 0.2, :max => 0.3, :confidence_interval => 0.8},
|
15
|
-
{:name => 'Would Go to the Beach Despite the Rain', :min => 0, :max => 0.2},
|
16
|
-
{:name => 'Would Go to the Movies if Something Good Was Playing', :min => 0.8, :max => 1.0},
|
17
|
-
{:name => 'Would Go to the Movies Despite the Rain', :min => 0.9, :max => 1.0}
|
18
|
-
]
|
19
|
-
return [PlausibleRange, values]
|
20
|
-
end
|
21
|
-
|
22
|
-
def import_destination_data
|
23
|
-
value_hash = FasterCSV...
|
24
|
-
return [DataNode, value_hash]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Each import method is starts with 'import_' and returns an array of [NodeClass, values_hash].
|
29
|
-
The Import class will then create a series of nodes and insert them into the active knowledge
|
30
|
-
base.
|
31
|
-
|
32
|
-
There are a number of useful Import classes that make most data imports fairly straight forward.
|
33
|
-
This way data from spreadsheets or YAML files can easily be added to the knowledge base.
|
34
|
-
|
35
|
-
=end
|
36
|
-
|
37
|
-
module Fathom
|
38
|
-
class Import
|
39
|
-
|
40
|
-
class << self
|
41
|
-
def import(opts={})
|
42
|
-
importer = new(opts)
|
43
|
-
importer.import
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
attr_reader :content, :options, :import_node
|
48
|
-
|
49
|
-
def initialize(opts={})
|
50
|
-
@options = OptionsHash.new(opts)
|
51
|
-
@content = @options[:content]
|
52
|
-
@import_node = ImportNode.new(opts)
|
53
|
-
end
|
54
|
-
|
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
|
61
|
-
end
|
62
|
-
self.import_node
|
63
|
-
end
|
64
|
-
|
65
|
-
protected
|
66
|
-
|
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
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
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
|
85
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
require 'import'
|
3
|
-
require 'open-uri'
|
4
|
-
|
5
|
-
# TODO: Work this out with Ruby 1.9. We don't need to load this for all Rubies.
|
6
|
-
require 'fastercsv'
|
7
|
-
require 'ext/faster_csv'
|
8
|
-
|
9
|
-
module Fathom
|
10
|
-
class CSVImport < Import
|
11
|
-
|
12
|
-
# @content could be a filename, URI, or actual file contents. We figure out which
|
13
|
-
# it is and then parse the contents with FasterCSV. We assume that there are column
|
14
|
-
# headers that are the names of each node, and that the values in the node are
|
15
|
-
# values for a DataNode.
|
16
|
-
def import_csv
|
17
|
-
parsed = parse_contents
|
18
|
-
extracted = extract_columns(parsed)
|
19
|
-
[DataNode, extracted]
|
20
|
-
end
|
21
|
-
|
22
|
-
# These are the options we use to parse the file. They can be overriden
|
23
|
-
# by calling CSVImport.new(:parse_options => {...}, ...)
|
24
|
-
def parse_options
|
25
|
-
return @parse_options if @parse_options
|
26
|
-
@parse_options = @options[:parse_options]
|
27
|
-
@parse_options ||= {:converters => [:all], :headers => true, :skip_blanks => true, :header_converters => [:strip, :symbol]}
|
28
|
-
@parse_options
|
29
|
-
end
|
30
|
-
|
31
|
-
protected
|
32
|
-
def parse_contents
|
33
|
-
arr_of_arrs = FasterCSV.parse(get_contents, parse_options)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Tries to read a file or URL. That failing, assumes the contents are CSV contents.
|
37
|
-
def get_contents
|
38
|
-
begin
|
39
|
-
content = open(@content).read
|
40
|
-
rescue
|
41
|
-
content = @content
|
42
|
-
end
|
43
|
-
return content
|
44
|
-
end
|
45
|
-
|
46
|
-
# Returns an array of hashes with :name => row header, :values => values
|
47
|
-
def extract_columns(parsed)
|
48
|
-
transposed = parsed.to_a.transpose
|
49
|
-
transposed.inject([]) do |list, column|
|
50
|
-
list << {:name => column.shift, :values => column}
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
if __FILE__ == $0
|
58
|
-
Fathom::CSVImport.import(:content => ARGV.first)
|
59
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
class Fathom::ImportNode < Fathom::Node
|
3
|
-
|
4
|
-
attr_reader :imported_at
|
5
|
-
|
6
|
-
def initialize(opts={})
|
7
|
-
super(opts)
|
8
|
-
@imported_at = Time.now
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
if __FILE__ == $0
|
14
|
-
include Fathom
|
15
|
-
# TODO: Is there anything you want to do to run this file on its own?
|
16
|
-
# ImportNode.new
|
17
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'fathom'))
|
2
|
-
require 'open-uri'
|
3
|
-
require 'yaml'
|
4
|
-
|
5
|
-
class Fathom::YAMLImport < Fathom::Import
|
6
|
-
def import_plausible_ranges
|
7
|
-
assert_yaml_content
|
8
|
-
plausible_ranges = extract_plausible_ranges
|
9
|
-
[PlausibleRange, plausible_ranges]
|
10
|
-
end
|
11
|
-
|
12
|
-
def import_data_nodes
|
13
|
-
assert_yaml_content
|
14
|
-
data_nodes = extract_data_nodes
|
15
|
-
[DataNode, data_nodes]
|
16
|
-
end
|
17
|
-
|
18
|
-
def import_facts
|
19
|
-
assert_yaml_content
|
20
|
-
facts = extract_facts
|
21
|
-
[Fact, facts]
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
def assert_yaml_content
|
26
|
-
return @yaml_content if @yaml_content
|
27
|
-
begin
|
28
|
-
file_contents = open(self.content).read
|
29
|
-
raise ArgumentError, "Unable to extract YAML data out of the contents." unless file_contents
|
30
|
-
rescue
|
31
|
-
file_contents = self.content
|
32
|
-
end
|
33
|
-
@yaml_content = YAML.load(file_contents)
|
34
|
-
end
|
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
|
-
|
49
|
-
def extract_plausible_ranges
|
50
|
-
return [] unless @yaml_content
|
51
|
-
@yaml_content.inject([]) do |list, array|
|
52
|
-
name, value = array.first, array.last
|
53
|
-
if value.is_a?(Hash)
|
54
|
-
value = OptionsHash.new(value)
|
55
|
-
# list << value.merge(:name => name) if value[:min] and value[:max]
|
56
|
-
list << value.merge(:name => name)
|
57
|
-
end
|
58
|
-
list
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def extract_data_nodes
|
63
|
-
return [] unless @yaml_content
|
64
|
-
@yaml_content.inject([]) do |list, array|
|
65
|
-
name, value = array.first, array.last
|
66
|
-
list << {:name => name, :values => value} if value.is_a?(Array)
|
67
|
-
list
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
if __FILE__ == $0
|
73
|
-
Fathom::YAMLImport.import(:content => ARGV.first)
|
74
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require File.expand_path("../../fathom", __FILE__)
|
2
|
-
|
3
|
-
require 'rdf'
|
4
|
-
require 'knowledge_base/search'
|
5
|
-
|
6
|
-
module Fathom
|
7
|
-
class KnowledgeBase
|
8
|
-
|
9
|
-
# =====================
|
10
|
-
# = Module Extensions =
|
11
|
-
# =====================
|
12
|
-
include Search
|
13
|
-
|
14
|
-
# attr_reader :data_store
|
15
|
-
|
16
|
-
def initialize(opts={})
|
17
|
-
# opts = OptionsHash.new(opts)
|
18
|
-
# @data_store = OpenStruct.new
|
19
|
-
end
|
20
|
-
|
21
|
-
# def []=(key, value)
|
22
|
-
# @data_store.table[key] = value
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# def [](key)
|
26
|
-
# @data_store.table[key]
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# # This is temporary, but useful for now. After we have the persisted KnowledgeBase,
|
30
|
-
# # we'll create explicit accessor methods or a find syntax.
|
31
|
-
# def method_missing(sym, *args, &block)
|
32
|
-
# if @data_store.table.keys.include?(sym)
|
33
|
-
# @data_store.send(sym)
|
34
|
-
# else
|
35
|
-
# super
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
if __FILE__ == $0
|
43
|
-
include Fathom
|
44
|
-
# TODO: Is there anything you want to do to run this file on its own?
|
45
|
-
# KnowledgeBase.new
|
46
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'sparql/algebra'
|
2
|
-
|
3
|
-
module Fathom
|
4
|
-
module Search
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.send(:extend, ClassMethods)
|
8
|
-
base.send(:include, InstanceMethods)
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def find(opts={})
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
module InstanceMethods
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'fathom'))
|
2
|
-
class Fathom::MonteCarloSet
|
3
|
-
|
4
|
-
class << self
|
5
|
-
def define_key(key)
|
6
|
-
define_method(key.to_sym) do
|
7
|
-
self.samples[key.to_sym]
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def define_summary_method(field)
|
12
|
-
define_method("#{field}_summary".to_sym) do
|
13
|
-
self.summary(field.to_sym)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
attr_reader :value_description, :samples_taken, :samples
|
19
|
-
|
20
|
-
def initialize(value_description)
|
21
|
-
@value_description = value_description
|
22
|
-
@samples = {}
|
23
|
-
end
|
24
|
-
|
25
|
-
def process(n=10_000)
|
26
|
-
@samples_taken = n
|
27
|
-
@samples_taken.times do
|
28
|
-
result = value_description.process
|
29
|
-
store(result)
|
30
|
-
end
|
31
|
-
assert_sample_vectors
|
32
|
-
end
|
33
|
-
|
34
|
-
def reset!
|
35
|
-
@samples = {}
|
36
|
-
@keys_asserted = nil
|
37
|
-
end
|
38
|
-
|
39
|
-
def fields
|
40
|
-
@samples.keys
|
41
|
-
end
|
42
|
-
|
43
|
-
def summary(field=nil)
|
44
|
-
return summarize_field(field) if field
|
45
|
-
fields.inject({}) do |h, field|
|
46
|
-
h[field] = summarize_field(field)
|
47
|
-
h
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def print_summary
|
52
|
-
print_hash(self.summary)
|
53
|
-
end
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
def print_hash(hash, indent=0)
|
58
|
-
hash.each do |key, value|
|
59
|
-
if value.is_a?(Hash)
|
60
|
-
puts "#{' ' * indent}#{key} => {"
|
61
|
-
print_hash(value, indent + 2)
|
62
|
-
puts "#{' ' * indent}}"
|
63
|
-
else
|
64
|
-
puts "#{' ' * indent}#{key} => #{value}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def summarize_field(field)
|
70
|
-
raise "No fields are defined. Have you processed this model yet?" if fields.empty?
|
71
|
-
raise ArgumentError, "#{field} is not a field in this set." unless fields.include?(field)
|
72
|
-
vector = self.send(field)
|
73
|
-
return vector unless vector.is_a?(GSL::Vector)
|
74
|
-
lb = lower_bound(:mean => vector.mean, :sd => vector.sd)
|
75
|
-
lb = vector.min if vector.min > lb
|
76
|
-
ub = upper_bound(:mean => vector.mean, :sd => vector.sd)
|
77
|
-
ub = vector.max if vector.max < ub
|
78
|
-
|
79
|
-
{
|
80
|
-
:coefficient_of_variation => (vector.sd / vector.mean),
|
81
|
-
:max => vector.max,
|
82
|
-
:mean => vector.mean,
|
83
|
-
:min => vector.min,
|
84
|
-
:sd => vector.sd,
|
85
|
-
:upper_bound => ub,
|
86
|
-
:lower_bound => lb
|
87
|
-
}
|
88
|
-
end
|
89
|
-
|
90
|
-
def inverse_cdf(opts={})
|
91
|
-
mean = opts[:mean]
|
92
|
-
sd = opts[:sd]
|
93
|
-
lower = opts.fetch(:lower, true)
|
94
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.05)
|
95
|
-
value = lower ? GSL::Cdf.gaussian_Pinv(confidence_interval, sd) : GSL::Cdf.gaussian_Qinv(confidence_interval, sd)
|
96
|
-
value + mean
|
97
|
-
end
|
98
|
-
alias :lower_bound :inverse_cdf
|
99
|
-
|
100
|
-
def upper_bound(opts={})
|
101
|
-
inverse_cdf(opts.merge(:lower => false))
|
102
|
-
end
|
103
|
-
|
104
|
-
def interval_values(opts={})
|
105
|
-
confidence_interval = opts.fetch(:confidence_interval, 0.9)
|
106
|
-
bound = (1 - confidence_interval) / 2.0
|
107
|
-
[lower_bound(opts.merge(:confidence_interval, bound)), upper_bound(opts.merge(:confidence_interval, bound))]
|
108
|
-
end
|
109
|
-
|
110
|
-
def assert_sample_vectors
|
111
|
-
vectors = @samples.inject({}) do |h, o|
|
112
|
-
key, obj = o.first, o.last
|
113
|
-
h[key] = (obj.is_a?(Array) and obj.first.is_a?(Numeric)) ? GSL::Vector.ary_to_gv(obj) : obj
|
114
|
-
h
|
115
|
-
end
|
116
|
-
@samples = vectors
|
117
|
-
end
|
118
|
-
|
119
|
-
def store(result)
|
120
|
-
result = assert_result_hash(result)
|
121
|
-
assert_keys(result)
|
122
|
-
result.each do |key, value|
|
123
|
-
@samples[key.to_sym] << value
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def assert_result_hash(result)
|
128
|
-
result.is_a?(Hash) ? result : {:result => result}
|
129
|
-
end
|
130
|
-
|
131
|
-
# Assumes the same value description for all samples taken
|
132
|
-
def assert_keys(result)
|
133
|
-
return true if @keys_asserted
|
134
|
-
result.keys.each do |key|
|
135
|
-
assert_key(key)
|
136
|
-
self.class.define_summary_method(key)
|
137
|
-
end
|
138
|
-
@keys_asserted = true
|
139
|
-
end
|
140
|
-
|
141
|
-
def assert_key(key)
|
142
|
-
self.class.define_key(key)
|
143
|
-
@samples[key.to_sym] ||= []
|
144
|
-
end
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
if __FILE__ == $0
|
149
|
-
include Fathom
|
150
|
-
# TODO: Is there anything you want to do to run this file on its own?
|
151
|
-
# MonteCarloSet.new
|
152
|
-
end
|