planout 0.0.4 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5c5c1dd6ff42017cf545c0907f6787ea1f4d5a3
4
- data.tar.gz: 1f07fd26a0d23f8bb5a168d72b7ae6ce719c4887
3
+ metadata.gz: de6ac7ac834d56d050fdc5d7a354f963e7fbef99
4
+ data.tar.gz: 5a28a98c04bf3560be6d2ce89662f083ed249ba5
5
5
  SHA512:
6
- metadata.gz: 9811923bb113830dc50b5513e218b927bc4ca300ab8442c68e8ea14855b51f6086f52dc94d235b71da651dadf7dfff9be35978b3dc04d323049e519e5a2fbe9a
7
- data.tar.gz: 0f86286b2428c19b46ac4f3bdcbff75cff14da944ab96d33dc76214ec7ce91e7a2ba32b62eba72603b23b4ba113cceec3c0cde67b2639bcd52c573c831b9f3ca
6
+ metadata.gz: 41b8aac76573def514e18e6676af436340f9f86a7e9cfb2c7295c46e8a10620a8ed53ffed8b883503de7eb84d391d96917cb437145bc4351e185da56d015a1df
7
+ data.tar.gz: c2b98270f2d422568adc7d12b3c6fad917a36c0ef744a3aa7312fa2c71acc0a1c6ee006a2cc33d8bfdbd510d6ff52d0891186cd0e7a8ed0fb9163b4d3738d870
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in planout.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rake'
8
+ gem 'minitest', '~> 5.5'
9
+ end
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ # PlanOut
2
+ [![Gem Version](https://badge.fury.io/rb/planout.svg)](http://badge.fury.io/rb/planout)
3
+ [![Build Status](https://travis-ci.org/facebook/planout.svg)](https://travis-ci.org/facebook/planout)
4
+
1
5
  ## Overview
2
6
  This is a rough implementation of the Experiment / logging infrasture for running PlanOut experiments, with all the random assignment operators available in Python. This port is nearly a line-by-line port, and produces assignments that are completely consistent with those produced by the Python reference implementation.
3
7
 
@@ -24,7 +28,7 @@ This defines a simple experiment that randomly assigns three variables, foo, bar
24
28
  `foo` and `baz` use `userid` as input, while `bar` uses a pair, namely `userid` combined with the value of `foo` from the prior step.
25
29
 
26
30
  ```ruby
27
- module Planout
31
+ module PlanOut
28
32
  class VotingExperiment < SimpleExperiment
29
33
  # Experiment#assign takes params and an input array
30
34
  def assign(params, **inputs)
@@ -48,7 +52,7 @@ end
48
52
  Then, we can examine the assignments produced for a few input userids. Note that since exposure logging is enabled by default, all of the experiments' inputs, configuration information, timestamp, and parameter assignments are pooped out via the Logger class.
49
53
 
50
54
  ```ruby
51
- my_exp = Planout::VotingExperiment.new(userid: 14)
55
+ my_exp = PlanOut::VotingExperiment.new(userid: 14)
52
56
  my_button_color = my_exp.get(:button_color)
53
57
  button_text = my_exp.get(:button_text)
54
58
  puts "button color is #{my_button_color} and button text is #{button_text}."
@@ -57,7 +61,7 @@ puts "button color is #{my_button_color} and button text is #{button_text}."
57
61
  The output of the Ruby script looks something like this:
58
62
 
59
63
  ```ruby
60
- logged data: {"name":"Planout::VotingExperiment","time":1404944726,"salt":"Planout::VotingExperiment","inputs":{"userid":14},"params":{"button_color":"ff0000","button_text":"I'm a voter"},"event":"exposure"}
64
+ logged data: {"name":"PlanOut::VotingExperiment","time":1404944726,"salt":"PlanOut::VotingExperiment","inputs":{"userid":14},"params":{"button_color":"ff0000","button_text":"I'm a voter"},"event":"exposure"}
61
65
 
62
66
  button color is ff0000 and button text is I'm a voter.
63
67
  ```
@@ -1,6 +1,6 @@
1
- require_relative '../../lib/planout/simple_experiment'
1
+ require_relative '../../lib/plan_out/simple_experiment'
2
2
 
3
- module Planout
3
+ module PlanOut
4
4
  class VotingExperiment < SimpleExperiment
5
5
  def setup; end
6
6
 
@@ -0,0 +1,8 @@
1
+ require_relative 'plan_out/op_random'
2
+ require_relative 'plan_out/assignment'
3
+ require_relative 'plan_out/simple_experiment'
4
+ require_relative 'plan_out/version'
5
+
6
+ module PlanOut
7
+
8
+ end
@@ -1,4 +1,4 @@
1
- module Planout
1
+ module PlanOut
2
2
  class Assignment
3
3
  attr_accessor :experiment_salt, :data
4
4
 
@@ -1,7 +1,7 @@
1
1
  require 'logger'
2
2
  require 'json'
3
3
 
4
- module Planout
4
+ module PlanOut
5
5
  class Experiment
6
6
  attr_accessor :auto_exposure_log
7
7
 
@@ -0,0 +1,84 @@
1
+ require_relative 'operator'
2
+
3
+ module PlanOut
4
+ class OpRandom < OpSimple
5
+ LONG_SCALE = Float(0xFFFFFFFFFFFFFFF)
6
+
7
+ def get_unit(appended_unit = nil)
8
+ unit = @parameters[:unit]
9
+ unit = [unit] if !unit.is_a? Array
10
+ unit += appended_unit if appended_unit != nil
11
+ unit
12
+ end
13
+
14
+ def get_hash(appended_unit = nil)
15
+ salt = @parameters[:salt]
16
+ salty = "#{@mapper.experiment_salt}.#{salt}"
17
+ unit_str = get_unit(appended_unit).join('.')
18
+ x = "#{salty}.#{unit_str}"
19
+ last_hex = (Digest::SHA1.hexdigest(x))[0..14]
20
+ last_hex.to_i(16)
21
+ end
22
+
23
+ def get_uniform(min_val = 0.0, max_val = 1.0, appended_unit = nil)
24
+ zero_to_one = self.get_hash(appended_unit)/LONG_SCALE
25
+ min_val + (max_val-min_val) * zero_to_one
26
+ end
27
+ end
28
+
29
+ class RandomFloat < OpRandom
30
+ def simple_execute
31
+ min_val = @parameters.fetch(:min, 0)
32
+ max_val = @parameters.fetch(:max, 1)
33
+ get_uniform(min_val, max_val)
34
+ end
35
+ end
36
+
37
+ class RandomInteger < OpRandom
38
+ def simple_execute
39
+ min_val = @parameters.fetch(:min, 0)
40
+ max_val = @parameters.fetch(:max, 1)
41
+ min_val + get_hash() % (max_val - min_val + 1)
42
+ end
43
+ end
44
+
45
+ class BernoulliTrial < OpRandom
46
+ def simple_execute
47
+ p = @parameters[:p]
48
+ rand_val = get_uniform(0.0, 1.0)
49
+ (rand_val <= p) ? 1 : 0
50
+ end
51
+ end
52
+
53
+ class WeightedChoice < OpRandom
54
+ def simple_execute
55
+ choices = @parameters[:choices]
56
+ weights = @parameters[:weights]
57
+
58
+ return [] if choices.length() == 0
59
+
60
+ cum_weights = choices.zip(weights)
61
+ cum_sum = 0.0
62
+
63
+ cum_weights.each do |choice, weight|
64
+ cum_sum += weight
65
+ cum_weights[choice] = cum_sum
66
+ end
67
+
68
+ stop_value = get_uniform(0.0, cum_sum)
69
+
70
+ cum_weights.each do |choice, cum_weight|
71
+ choice if stop_value <= cum_weight
72
+ end
73
+ end
74
+ end
75
+
76
+ class UniformChoice < OpRandom
77
+ def simple_execute
78
+ choices = @parameters[:choices]
79
+ return [] if choices.length() == 0
80
+ rand_index = get_hash() % choices.length()
81
+ choices[rand_index]
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,18 @@
1
- require_relative 'operator'
1
+ require 'digest/sha1'
2
+
3
+ module PlanOut
4
+ class Operator
5
+ attr_accessor :args
6
+
7
+ def initialize(parameters)
8
+ @args = parameters
9
+ end
10
+
11
+ def execute(mapper)
12
+ mapper.experiment_salt
13
+ end
14
+ end
2
15
 
3
- module Planout
4
16
  class OpSimple < Operator
5
17
  def execute(mapper)
6
18
  @mapper = mapper
@@ -1,6 +1,6 @@
1
1
  require_relative 'experiment'
2
2
 
3
- module Planout
3
+ module PlanOut
4
4
  class SimpleExperiment < Experiment
5
5
  def configure_logger
6
6
  @logger = Logger.new(STDOUT)
@@ -0,0 +1,3 @@
1
+ module PlanOut
2
+ VERSION = '0.1.1'
3
+ end
@@ -1,11 +1,11 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'planout/version'
4
+ require 'plan_out/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "planout"
8
- spec.version = Planout::VERSION
8
+ spec.version = PlanOut::VERSION
9
9
  spec.authors = ["Eytan Bakshy", "Mohnish Thallavajhula"]
10
10
  spec.email = ["ebakshy@gmail.com", "i@mohni.sh"]
11
11
  spec.summary = %q{PlanOut is a framework and programming language for online field experimentation.}
@@ -1,6 +1,6 @@
1
1
  require_relative '../test_helper'
2
2
 
3
- module Planout
3
+ module PlanOut
4
4
  class AssignmentTest < Minitest::Test
5
5
  def setup
6
6
  @assignment = Assignment.new('mtsalt')
@@ -1,7 +1,7 @@
1
1
  require_relative '../test_helper'
2
- require_relative '../../examples/planout/voting_experiment'
2
+ require_relative '../../examples/plan_out/voting_experiment'
3
3
 
4
- module Planout
4
+ module PlanOut
5
5
  class ExperimentTest < Minitest::Test
6
6
  def setup
7
7
  @voting_experiment = VotingExperiment.new(userid: 14)
@@ -15,18 +15,18 @@ module Planout
15
15
  assert_equal(1, @voting_experiment.get(:missing_key, 1))
16
16
  assert_equal('ff0000', @voting_experiment2.get(:button_color))
17
17
  assert_equal("I'm voting", @voting_experiment.get(:button_text))
18
- assert_equal("I'm a voter", @voting_experiment2.get(:button_text))
18
+ assert_equal("I'm voting", @voting_experiment2.get(:button_text))
19
19
  end
20
20
 
21
21
  def test_get_params
22
22
  assert_equal({ button_color: 'ff0000', button_text: "I'm voting" }, @voting_experiment.get_params)
23
- assert_equal({ button_color: 'ff0000', button_text: "I'm a voter" }, @voting_experiment2.get_params)
23
+ assert_equal({ button_color: 'ff0000', button_text: "I'm voting" }, @voting_experiment2.get_params)
24
24
  end
25
25
 
26
26
  def test_as_blob
27
27
  result = @voting_experiment.as_blob
28
- assert_equal('Planout::VotingExperiment', result[:name])
29
- assert_equal('Planout::VotingExperiment', result[:salt])
28
+ assert_equal('PlanOut::VotingExperiment', result[:name])
29
+ assert_equal('PlanOut::VotingExperiment', result[:salt])
30
30
  assert_equal({ userid: 14 }, result[:inputs])
31
31
  end
32
32
  end
@@ -1,6 +1,6 @@
1
1
  require_relative '../test_helper'
2
2
 
3
- module Planout
3
+ module PlanOut
4
4
  class OperatorTest < Minitest::Test
5
5
  def setup
6
6
  @operator = Operator.new({ foo: 'bar' })
@@ -1,2 +1,2 @@
1
1
  require 'minitest/autorun'
2
- require_relative '../lib/planout'
2
+ require_relative '../lib/plan_out'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: planout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eytan Bakshy
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-12-21 00:00:00.000000000 Z
12
+ date: 2015-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -67,24 +67,18 @@ files:
67
67
  - LICENSE
68
68
  - README.md
69
69
  - Rakefile
70
- - examples/planout/voting_experiment.rb
71
- - lib/planout.rb
72
- - lib/planout/assignment.rb
73
- - lib/planout/bernoulli_trial.rb
74
- - lib/planout/experiment.rb
75
- - lib/planout/op_random.rb
76
- - lib/planout/op_simple.rb
77
- - lib/planout/operator.rb
78
- - lib/planout/random_float.rb
79
- - lib/planout/random_integer.rb
80
- - lib/planout/simple_experiment.rb
81
- - lib/planout/uniform_choice.rb
82
- - lib/planout/version.rb
83
- - lib/planout/weighted_choice.rb
70
+ - examples/plan_out/voting_experiment.rb
71
+ - lib/plan_out.rb
72
+ - lib/plan_out/assignment.rb
73
+ - lib/plan_out/experiment.rb
74
+ - lib/plan_out/op_random.rb
75
+ - lib/plan_out/operator.rb
76
+ - lib/plan_out/simple_experiment.rb
77
+ - lib/plan_out/version.rb
84
78
  - planout.gemspec
85
- - test/planout/assignment_test.rb
86
- - test/planout/experiment_test.rb
87
- - test/planout/operator_test.rb
79
+ - test/plan_out/assignment_test.rb
80
+ - test/plan_out/experiment_test.rb
81
+ - test/plan_out/operator_test.rb
88
82
  - test/test_helper.rb
89
83
  homepage: https://facebook.github.io/planout
90
84
  licenses:
@@ -106,12 +100,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
100
  version: '0'
107
101
  requirements: []
108
102
  rubyforge_project:
109
- rubygems_version: 2.2.2
103
+ rubygems_version: 2.4.5
110
104
  signing_key:
111
105
  specification_version: 4
112
106
  summary: PlanOut is a framework and programming language for online field experimentation.
113
107
  test_files:
114
- - test/planout/assignment_test.rb
115
- - test/planout/experiment_test.rb
116
- - test/planout/operator_test.rb
108
+ - test/plan_out/assignment_test.rb
109
+ - test/plan_out/experiment_test.rb
110
+ - test/plan_out/operator_test.rb
117
111
  - test/test_helper.rb
@@ -1,16 +0,0 @@
1
- require_relative 'planout/operator'
2
- require_relative 'planout/op_simple'
3
- require_relative 'planout/op_random'
4
- require_relative 'planout/random_float'
5
- require_relative 'planout/random_integer'
6
- require_relative 'planout/bernoulli_trial'
7
- require_relative 'planout/weighted_choice'
8
- require_relative 'planout/uniform_choice'
9
- require_relative 'planout/assignment'
10
- require_relative 'planout/experiment'
11
- require_relative 'planout/simple_experiment'
12
- require_relative 'planout/version'
13
-
14
- module Planout
15
-
16
- end
@@ -1,11 +0,0 @@
1
- require_relative 'op_random'
2
-
3
- module Planout
4
- class BernoulliTrial < OpRandom
5
- def simple_execute
6
- p = @parameters[:p]
7
- rand_val = get_uniform(0.0, 1.0)
8
- (rand_val <= p) ? 1 : 0
9
- end
10
- end
11
- end
@@ -1,28 +0,0 @@
1
- require_relative 'op_simple'
2
-
3
- module Planout
4
- class OpRandom < OpSimple
5
- LongScale = Float(0xFFFFFFFFFFFFFFF)
6
-
7
- def get_unit(appended_unit = nil)
8
- unit = @parameters[:unit]
9
- unit = [unit] if !unit.is_a? Array
10
- unit += appended_unit if appended_unit != nil
11
- unit
12
- end
13
-
14
- def get_hash(appended_unit = nil)
15
- salt = @parameters[:salt]
16
- salty = "#{@mapper.experiment_salt}.#{salt}"
17
- unit_str = get_unit(appended_unit).join('.')
18
- x = "#{salty}.#{unit_str}"
19
- last_hex = (Digest::SHA1.hexdigest(x))[0..14]
20
- last_hex.to_i(16)
21
- end
22
-
23
- def get_uniform(min_val = 0.0, max_val = 1.0, appended_unit = nil)
24
- zero_to_one = self.get_hash(appended_unit)/LongScale
25
- min_val + (max_val-min_val) * zero_to_one
26
- end
27
- end
28
- end
@@ -1,14 +0,0 @@
1
- require 'digest/sha1'
2
-
3
- module Planout
4
- class Operator
5
- attr_accessor :args
6
- def initialize(parameters)
7
- @args = parameters
8
- end
9
-
10
- def execute(mapper)
11
- mapper.experiment_salt
12
- end
13
- end
14
- end
@@ -1,11 +0,0 @@
1
- require_relative 'op_random'
2
-
3
- module Planout
4
- class RandomFloat < OpRandom
5
- def simple_execute
6
- min_val = @parameters.fetch(:min, 0)
7
- max_val = @parameters.fetch(:max, 1)
8
- get_uniform(min_val, max_val)
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- require_relative 'op_random'
2
-
3
- module Planout
4
- class RandomInteger < OpRandom
5
- def simple_execute
6
- min_val = @parameters.fetch(:min, 0)
7
- max_val = @parameters.fetch(:max, 1)
8
- min_val + get_hash() % (max_val - min_val + 1)
9
- end
10
- end
11
- end
@@ -1,12 +0,0 @@
1
- require_relative 'op_random'
2
-
3
- module Planout
4
- class UniformChoice < OpRandom
5
- def simple_execute
6
- choices = @parameters[:choices]
7
- return [] if choices.length() == 0
8
- rand_index = get_hash() % choices.length()
9
- choices[rand_index]
10
- end
11
- end
12
- end
@@ -1,3 +0,0 @@
1
- module Planout
2
- VERSION = '0.0.4'
3
- end
@@ -1,26 +0,0 @@
1
- require_relative 'op_random'
2
-
3
- module Planout
4
- class WeightedChoice < OpRandom
5
- def simple_execute
6
- choices = @parameters[:choices]
7
- weights = @parameters[:weights]
8
-
9
- return [] if choices.length() == 0
10
-
11
- cum_weights = choices.zip(weights)
12
- cum_sum = 0.0
13
-
14
- cum_weights.each do |choice, weight|
15
- cum_sum += weight
16
- cum_weights[choice] = cum_sum
17
- end
18
-
19
- stop_value = get_uniform(0.0, cum_sum)
20
-
21
- cum_weights.each do |choice, cum_weight|
22
- choice if stop_value <= cum_weight
23
- end
24
- end
25
- end
26
- end