fathom 0.3.7 → 0.5.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/.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
|