automatthew-stevedore 0.1.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/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+
3
+ Version = '0.1.0'
4
+
5
+ task :default => [ :test ]
6
+
7
+ begin
8
+ gem 'echoe', '~>3.0'
9
+ require 'echoe'
10
+ Echoe.new('stevedore', Version) do |p|
11
+ p.project = 'stevedore'
12
+ p.summary = "Benchmarking with a whiff of statistical awareness"
13
+ p.author = "Matthew King"
14
+ p.email = "automatthew@gmail.com"
15
+ p.ignore_pattern = /^(\.git).+/
16
+ p.test_pattern = "test/*.rb"
17
+ end
18
+ rescue
19
+ "(ignored echoe gemification, as you don't have the Right Stuff)"
20
+ end
data/examples/data.yml ADDED
@@ -0,0 +1,51 @@
1
+ ---
2
+ - 0.00554585456848145
3
+ - 0.010728120803833
4
+ - 0.00568890571594238
5
+ - 0.00575709342956543
6
+ - 0.00926589965820312
7
+ - 0.00586318969726562
8
+ - 0.00583505630493164
9
+ - 0.00585389137268066
10
+ - 0.00891590118408203
11
+ - 0.00550603866577148
12
+ - 0.00578689575195312
13
+ - 0.00865912437438965
14
+ - 0.00515890121459961
15
+ - 0.00583219528198242
16
+ - 0.00541400909423828
17
+ - 0.00829195976257324
18
+ - 0.00518512725830078
19
+ - 0.005615234375
20
+ - 0.00883793830871582
21
+ - 0.00561618804931641
22
+ - 0.00561308860778809
23
+ - 0.00577306747436523
24
+ - 0.00857686996459961
25
+ - 0.0057990550994873
26
+ - 0.00524306297302246
27
+ - 0.00851821899414062
28
+ - 0.00578618049621582
29
+ - 0.00547695159912109
30
+ - 0.00515198707580566
31
+ - 0.00598001480102539
32
+ - 0.00586414337158203
33
+ - 0.00577092170715332
34
+ - 0.0083918571472168
35
+ - 0.00514411926269531
36
+ - 0.0051429271697998
37
+ - 0.00795292854309082
38
+ - 0.00558185577392578
39
+ - 0.00593113899230957
40
+ - 0.00522780418395996
41
+ - 0.00866293907165527
42
+ - 0.00590395927429199
43
+ - 0.00517797470092773
44
+ - 0.00850200653076172
45
+ - 0.0058290958404541
46
+ - 0.00525999069213867
47
+ - 0.00512909889221191
48
+ - 0.00773906707763672
49
+ - 0.00583696365356445
50
+ - 0.00583600997924805
51
+ - 0.00795888900756836
@@ -0,0 +1,31 @@
1
+ %w{ rubygems }.each { |dep| require dep }
2
+
3
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
4
+ require 'stevedore'
5
+
6
+ thing = lambda { true }
7
+ n = 10000
8
+
9
+ one_eval = Stevedore.new "One instance eval with several block.call" do
10
+
11
+ measure do
12
+ instance_eval do
13
+ n.times { thing.call }
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ multi_eval = Stevedore.new "instance_eval &block multiple times" do
20
+
21
+ measure do
22
+ n.times { instance_eval &thing }
23
+ end
24
+
25
+ end
26
+
27
+ Stevedore.compare_instances(5, 10)
28
+ puts
29
+ puts
30
+ Stevedore.recommend_test_size(2, 4)
31
+
@@ -0,0 +1,41 @@
1
+ %w{ rubygems }.each { |dep| require dep }
2
+ require 'mathstats'
3
+ require 'rsruby'
4
+
5
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
6
+ require 'stevedore'
7
+
8
+ array = YAML.load_file("data.yml")
9
+
10
+ # rstats_sd = Stevedore.new "rstats standard deviation" do
11
+ #
12
+ # measure do
13
+ # array.standard_deviation
14
+ # end
15
+ #
16
+ # end
17
+
18
+ mathstats = Stevedore.new "mathstats standard deviation" do
19
+
20
+ measure do
21
+ Mathstats::Lib.standard_deviation(array)
22
+ end
23
+
24
+ end
25
+
26
+ rsruby = Stevedore.new "rsruby standard deviation" do
27
+
28
+ before do
29
+ @r = RSRuby.instance
30
+ end
31
+
32
+ measure do
33
+ @r.sd(array)
34
+ end
35
+
36
+ end
37
+
38
+
39
+ Stevedore.compare_instances(5, 10)
40
+
41
+
data/lib/stevedore.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'benchmark'
2
+ require 'stevedore/stats'
3
+ require 'stevedore/shell_r'
4
+ require 'stevedore/class'
5
+ require 'stevedore/instance'
6
+
7
+ class Stevedore
8
+
9
+ end
10
+
11
+ Steve = Stevedore
@@ -0,0 +1,86 @@
1
+ class Stevedore
2
+
3
+ def self.instances; @instances ||= []; end
4
+
5
+ def self.reset; @instances = []; end
6
+
7
+
8
+ # Moderately stringent defaults for power analysis
9
+
10
+ def self.power(val=nil)
11
+ val ? @power = val : @power ||= 0.9
12
+ end
13
+ def self.sig_level(val=nil)
14
+ val ? @sig_level = val : @sig_level ||= 0.01
15
+ end
16
+ def self.delta(val=nil)
17
+ val ? @delta = val : @delta ||= 0.001
18
+ end
19
+
20
+
21
+ def self.before(&block)
22
+ block ? @before = block : @before
23
+ end
24
+
25
+ def self.after(&block)
26
+ block ? @after = block : @after
27
+ end
28
+
29
+ def self.before_sample(&block)
30
+ block ? @before_sample = block : @before_sample
31
+ end
32
+
33
+ def self.after_sample(&block)
34
+ block ? @after_sample = block : @after_sample
35
+ end
36
+
37
+ def self.before_measure(&block)
38
+ block ? @before_measure = block : @before_measure
39
+ end
40
+
41
+ def self.after_measure(&block)
42
+ block ? @after_measure = block : @after_measure
43
+ end
44
+
45
+ def self.compare_instances(run_count, sample_size)
46
+ puts "Measuring #{run_count} runs of #{sample_size} for each instance.\n\n"
47
+ @instances.each do |instance|
48
+ puts "'#{instance.name}'"
49
+ instance.go(run_count, sample_size)
50
+ end
51
+ name_size = @instances.map { |i| i.name.size }.max
52
+ puts "\n%-#{name_size}s %12s %12s %12s %12s %12s" % %w{ Name Mean Stddev Minimum Median Max }
53
+ puts "-" * (name_size + 5 * 13)
54
+ @instances.each do |instance|
55
+ puts "%-#{name_size}s %12f %12f %12f %12f %12f" %
56
+ [ instance.name, instance.mean, instance.standard_deviation, instance.min, instance.median, instance.max]
57
+ end
58
+ puts
59
+ end
60
+
61
+ # Run a small set of samples and use a power test to determine
62
+ # the optimal run count and sample size.
63
+ def self.recommend_test_size(run_count, sample_size)
64
+ puts "\nRunning trials (#{run_count} runs of #{sample_size}) for each instance.\n\n"
65
+ @instances.each do |instance|
66
+ print "'#{instance.name}'"
67
+ instance.go(run_count, sample_size)
68
+ puts " Mean: %6f" % instance.mean
69
+ puts " Stddev: %6f" % instance.standard_deviation
70
+ end
71
+ puts
72
+ worst = @instances.sort_by { |i| i.standard_deviation }.last
73
+ puts "'#{worst.name}' has the greatest standard deviation,"
74
+ puts "so we'll use it in the power test to determine optimal run size"
75
+ rec_size = optimal_n(worst.standard_deviation).to_i
76
+ rec_runs = optimal_n(worst.sample_means.standard_deviation).to_i
77
+ puts "Recommendation: #{rec_runs} sample runs of #{rec_size} measurements.\n\n"
78
+ [rec_runs, rec_size]
79
+ end
80
+
81
+ def self.optimal_n(stddev);
82
+ args = { :power => power, :delta => delta, :sig_level => sig_level, :sd => stddev }
83
+ Stevedore::Stats.power_test(args)["n"].to_i
84
+ end
85
+
86
+ end
@@ -0,0 +1,98 @@
1
+ class Stevedore
2
+
3
+ attr_accessor :name, :description, :samples
4
+
5
+ def initialize(name, description='', &block)
6
+ klass = self.class
7
+ klass.instances << self
8
+ @before, @after = klass.before, klass.after
9
+ @before_measure, @after_measure = klass.before_measure, klass.after_measure
10
+ @before_sample, @after_sample = klass.before_sample, klass.after_sample
11
+ @name, @description = name, description
12
+ @samples = []
13
+ instance_eval( &block ) if block
14
+ end
15
+
16
+ def flattened_samples
17
+ @flat ||= @samples.flatten
18
+ end
19
+
20
+ def reset
21
+ @samples = []
22
+ @flattened_samples = []
23
+ end
24
+
25
+ # Blocks for setup and measurement
26
+
27
+ def before(&block); @before = block; end
28
+
29
+ def after(&block); @after = block; end
30
+
31
+ def before_sample(&block); @before_sample = block; end
32
+
33
+ def after_sample(&block); @after_sample = block; end
34
+
35
+ def before_measure(&block); @before_measure = block; end
36
+
37
+ def after_measure(&block); @after_measure = block; end
38
+
39
+ def measure(&block); @measure = block; end
40
+
41
+ def go(run_count, sample_size)
42
+ reset
43
+ instance_eval( &@before ) if @before
44
+
45
+ run_count.times do |i|
46
+ sample = []
47
+ instance_eval( &@before_sample ) if @before_sample
48
+
49
+ sample_size.times do
50
+ instance_eval( &@before_measure ) if @before_measure
51
+ sample << Benchmark.realtime do
52
+ instance_eval( &@measure )
53
+ end
54
+ instance_eval( &@after_measure ) if @after_measure
55
+ end
56
+
57
+ instance_eval( &@after_sample ) if @after_sample
58
+ @samples << sample
59
+ end
60
+
61
+ instance_eval( &@after ) if @after
62
+ end
63
+
64
+ def report
65
+ puts self.name
66
+ puts "#{run_count} sample runs, #{sample_size} measurements each"
67
+ puts " Mean: #{self.mean}"
68
+ puts " Standard deviation: #{self.standard_deviation}"
69
+ puts
70
+ end
71
+
72
+ def mean
73
+ self.flattened_samples.mean
74
+ end
75
+
76
+ def median
77
+ self.flattened_samples.median
78
+ end
79
+
80
+ def min
81
+ self.flattened_samples.min
82
+ end
83
+
84
+ def max
85
+ self.flattened_samples.max
86
+ end
87
+
88
+ def standard_deviation
89
+ self.flattened_samples.standard_deviation
90
+ end
91
+
92
+ def sample_means
93
+ @samples.map { |s| s.mean }
94
+ end
95
+
96
+
97
+
98
+ end
@@ -0,0 +1,37 @@
1
+ require 'rsruby'
2
+ class Stevedore
3
+
4
+ module RSRuby
5
+
6
+ def rsruby
7
+ @rsruby ||= ::RSRuby.instance
8
+ end
9
+
10
+ def mean
11
+ rsruby.mean(self)
12
+ end
13
+
14
+ def standard_deviation
15
+ rsruby.sd(self)
16
+ end
17
+
18
+ def median
19
+ rsruby.median(self)
20
+ end
21
+
22
+ def self.rsruby
23
+ @rsruby ||= ::RSRuby.instance
24
+ end
25
+
26
+ def self.power_test(args)
27
+ delta, power, sig_level, sd = args[:delta], args[:power], args[:sig_level], args[:sd]
28
+ if sd < 0.00007
29
+ warn "Stddev is very small, which makes power.t.test sad. \nSetting stddev to 0.00007 so we can get this done."
30
+ sd = 0.00007
31
+ end
32
+ rsruby.power_t_test( :delta => delta, :power => power, :sig_level => sig_level, :sd => sd)
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,40 @@
1
+ class Stevedore
2
+ class ShellR
3
+
4
+ def self.path(val=nil)
5
+ val ? @path = val : @path ||= `which R`.chomp
6
+ end
7
+
8
+ def path
9
+ self.class.path
10
+ end
11
+
12
+ def command(expression)
13
+ %Q{#{path} --slave -e '#{expression}'}
14
+ end
15
+
16
+ def execute(expression)
17
+ command = command(expression)
18
+ r = `#{command}`
19
+ end
20
+
21
+ def power_test(options)
22
+ power, delta, sig_level, sd = options[:power], options[:delta], options[:sig_level], options[:sd]
23
+ if options[:sd] < 0.00007
24
+ warn "Stddev is very small, which makes power.t.test sad. \nSetting stddev to 0.00007 so we can get this done."
25
+ options[:sd] = 0.00007
26
+ end
27
+ expression = %Q{power.t.test(power=#{power}, delta=#{delta}, sd=#{sd}, sig.level=#{sig_level})[]}
28
+ parse(execute(expression))
29
+ end
30
+
31
+ def parse(r_output)
32
+ attrs = r_output.scan( /\$([\w\-\.]+)\s+\[\d+\]\s+([\d\.\-e\+]+)/m )
33
+ r = attrs.map { |k,v| [k, v.to_f] }.flatten
34
+ Hash[*r]
35
+ end
36
+
37
+
38
+
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ class Stevedore
2
+
3
+ begin
4
+ require 'stevedore/rsruby'
5
+ Stats = Stevedore::RSRuby
6
+ puts "Stevedore will use RSRuby"
7
+ rescue
8
+ require 'mathstats'
9
+ Stats = Mathstats
10
+ module Stats
11
+ unless defined?(median)
12
+ def median
13
+ sorted = self.sort; i = sorted.size % 2
14
+ case i
15
+ when 0 then sorted[i/2 - 1, 2].mean
16
+ when 1 then sorted[i/2].to_f
17
+ end if sorted.size > 0
18
+ end
19
+ end
20
+ def self.power_test(*args)
21
+ Stevedore::ShellR.new.power_test(*args)
22
+ end
23
+ end
24
+ puts "Stevedore will use Mathstats"
25
+ end
26
+
27
+ Array.send :include, Stats
28
+
29
+ end
30
+
data/stevedore.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{stevedore}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Matthew King"]
9
+ s.date = %q{2009-01-01}
10
+ s.description = %q{Benchmarking with a whiff of statistical awareness}
11
+ s.email = %q{automatthew@gmail.com}
12
+ s.extra_rdoc_files = ["lib/stevedore/class.rb", "lib/stevedore/instance.rb", "lib/stevedore/rsruby.rb", "lib/stevedore/shell_r.rb", "lib/stevedore/stats.rb", "lib/stevedore.rb", "README"]
13
+ s.files = ["examples/data.yml", "examples/instance_eval.rb", "examples/stats_libs.rb", "lib/stevedore/class.rb", "lib/stevedore/instance.rb", "lib/stevedore/rsruby.rb", "lib/stevedore/shell_r.rb", "lib/stevedore/stats.rb", "lib/stevedore.rb", "Manifest", "Rakefile", "README", "stevedore.gemspec", "test/helper.rb", "test/test_R.rb", "test/test_sample.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Stevedore", "--main", "README"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{stevedore}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Benchmarking with a whiff of statistical awareness}
21
+ s.test_files = ["test/helper.rb", "test/test_R.rb", "test/test_sample.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<echoe>, [">= 0"])
29
+ else
30
+ s.add_dependency(%q<echoe>, [">= 0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<echoe>, [">= 0"])
34
+ end
35
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ %w{ rubygems bacon facon }.each { |dep| require dep }
2
+
3
+ Bacon.extend Bacon::TestUnitOutput
4
+ Bacon.summary_on_exit
5
+
6
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
7
+ require 'stevedore'
8
+
data/test/test_R.rb ADDED
@@ -0,0 +1,62 @@
1
+ require "#{File.dirname(__FILE__)}/helper.rb"
2
+
3
+ R = Stevedore::ShellR
4
+
5
+
6
+
7
+
8
+ describe "ShellR class" do
9
+
10
+ it "tries to find the path to R using `which`" do
11
+ File.exist?(R.path).should == true
12
+ end
13
+
14
+ it "allows you to set the path to R" do
15
+ R.path "/monkey"
16
+ R.path.should == "/monkey"
17
+ end
18
+
19
+ end
20
+
21
+ describe "An instance of ShellR" do
22
+
23
+ before do
24
+ @r = R.new
25
+ end
26
+
27
+ it "gets the path to R from the class" do
28
+ R.path "/junkie"
29
+ @r.path.should == "/junkie"
30
+ end
31
+
32
+ it "properly constructs the shell command" do
33
+ @r.command("shines").should == "/junkie --slave -e 'shines'"
34
+ end
35
+
36
+ it "can shell out to call R" do
37
+ R.path `which R`.chomp
38
+ expression = %Q{power.t.test(power=0.9, delta=0.0001, sd=0.001133, sig.level=0.01)["n"]}
39
+ res = @r.execute(expression)
40
+ res.should == "$n\n[1] 3821.76\n\n"
41
+ end
42
+
43
+ it "can scan the R result when printed as list of attrs" do
44
+ output = <<-TXT
45
+ $n
46
+ [1] 3821.76
47
+
48
+ $delta
49
+ [1] 1e-04
50
+
51
+ TXT
52
+ @r.parse(output).should == { "n" => 3821.76, "delta" => 1e-04 }
53
+ end
54
+
55
+ it "has a power_test method" do
56
+ options = {:power => 0.9, :delta => 0.003, :sig_level => 0.01, :sd => 0.02}
57
+ res = @r.power_test(options)
58
+ res.keys.sort.should == ["delta", "n", "power", "sd", "sig.level"]
59
+ end
60
+
61
+
62
+ end
@@ -0,0 +1,27 @@
1
+ require "#{File.dirname(__FILE__)}/helper.rb"
2
+
3
+ Sample = Stevedore::Sample
4
+
5
+ describe "Stevedore::Sample" do
6
+
7
+ before do
8
+ @sample = Sample.new((1..40).to_a)
9
+ @nested_sample = Sample.new [@sample, @sample, @sample ]
10
+ end
11
+
12
+ it "a flattened Sample is still a Sample" do
13
+ @nested_sample.flatten.class.should == Sample
14
+ [@nested_sample].flatten.class.should == Array
15
+ end
16
+
17
+ it "has a mean" do
18
+ @sample.mean.should == 20.5
19
+ @nested_sample.mean.should == 20.5
20
+ end
21
+
22
+ it "has a standard deviation" do
23
+ @sample.standard_deviation.to_i.should == 11
24
+ @nested_sample.standard_deviation.to_i.should == 11
25
+ end
26
+
27
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: automatthew-stevedore
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew King
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-01 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: echoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description: Benchmarking with a whiff of statistical awareness
25
+ email: automatthew@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - lib/stevedore/class.rb
32
+ - lib/stevedore/instance.rb
33
+ - lib/stevedore/rsruby.rb
34
+ - lib/stevedore/shell_r.rb
35
+ - lib/stevedore/stats.rb
36
+ - lib/stevedore.rb
37
+ - README
38
+ files:
39
+ - examples/data.yml
40
+ - examples/instance_eval.rb
41
+ - examples/stats_libs.rb
42
+ - lib/stevedore/class.rb
43
+ - lib/stevedore/instance.rb
44
+ - lib/stevedore/rsruby.rb
45
+ - lib/stevedore/shell_r.rb
46
+ - lib/stevedore/stats.rb
47
+ - lib/stevedore.rb
48
+ - Manifest
49
+ - Rakefile
50
+ - README
51
+ - stevedore.gemspec
52
+ - test/helper.rb
53
+ - test/test_R.rb
54
+ - test/test_sample.rb
55
+ has_rdoc: true
56
+ homepage: ""
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --line-numbers
60
+ - --inline-source
61
+ - --title
62
+ - Stevedore
63
+ - --main
64
+ - README
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "1.2"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project: stevedore
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: Benchmarking with a whiff of statistical awareness
86
+ test_files:
87
+ - test/helper.rb
88
+ - test/test_R.rb
89
+ - test/test_sample.rb