dates 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,6 +21,30 @@ To run it, the simplest way is just to provide it with an ideas file and nothing
21
21
  $ dates ideas.rb
22
22
  watch _serenity_: (intellectual: 5, athletic: 0, adventure: 2, romantic: 4)
23
23
 
24
+ ### Ideas
25
+
26
+ Dates need an ideas file to work. An ideas file looks like this:
27
+
28
+ DateIdeas.new do
29
+
30
+ date "watch _movie title_" do
31
+ kind :adventure => 2, :romantic => 4, :intellectual => 6, :athletic => 0
32
+ requires :weather => 0, :hours => 2
33
+ outcome 6
34
+ end
35
+
36
+ date "read a book" do
37
+ kind :romantic => 3, :adventure => 6, :athletic => 3, :intellectual => 5
38
+ requires :weather => 5, :hours => 2
39
+ end
40
+
41
+ date "go adventuring" do
42
+ kind :adventure => 5, :romantic => 7, :intellectual => 5, :athletic => 1
43
+ requires :weather => 8, :hours => 3
44
+ end
45
+
46
+ end
47
+
24
48
  ### Commands
25
49
 
26
50
  The `choose` command picks a date, and it takes two options:
data/bin/dates CHANGED
@@ -3,7 +3,7 @@
3
3
  require File.dirname(__FILE__) + '/../lib/dates'
4
4
 
5
5
  SUB_COMMANDS = %w(list choose)
6
- VERSION_STR = "dates 1.0.0-beta, max & daphne."
6
+ VERSION_STR = "dates #{Dates::VERSION}-beta, max & daphne."
7
7
  global_opts = Trollop::options do
8
8
  version VERSION_STR
9
9
  banner <<-EOS
@@ -42,7 +42,7 @@ class DateIdeas
42
42
  elsif f.complete? and f.score < 6.0
43
43
  str << " #{f.to_s}".red
44
44
  else
45
- raise Exception("We should never reach this.")
45
+ raise "We should never reach this."
46
46
  end
47
47
  end
48
48
  str
@@ -60,10 +60,12 @@ class DateIdeas
60
60
  @date_ideas.reject { |idea| idea.stub? or idea.complete? }
61
61
  end
62
62
 
63
- def extract_features(idea_list)
64
- keys = idea_list.reduce([]) { |acc, idea|
65
- acc << idea.attributes.keys
66
- }.flatten.uniq
63
+ def extract_features(idea_list, keys = [])
64
+ if keys.empty?
65
+ keys = idea_list.reduce([]) { |acc, idea|
66
+ acc << idea.attributes.keys
67
+ }.flatten.uniq
68
+ end
67
69
  features = idea_list.map { |idea|
68
70
  attributes = idea.attributes.map { |key, val|
69
71
  [keys.index(key), val]
@@ -73,24 +75,55 @@ class DateIdeas
73
75
  [keys, features]
74
76
  end
75
77
 
76
- def fitted_model
77
- dimensions, examples = complete_features
78
- terms = examples.map { |examples|
79
- examples[0] + examples[0].permutation(2).to_a.map { |term| term.reduce(1) {|acc,k| acc*k } }
78
+ def fitted_model(keys = [])
79
+ dimensions, examples = complete_features(keys)
80
+ # need regularization (elastic net?) before adding these terms
81
+ #terms = Matrix.rows examples.map { |example|
82
+ # example[0] + example[0].permutation(2).to_a.map { |term| term.reduce(1) {|acc,k| acc*k } }
83
+ #}
84
+ terms = Matrix.rows examples.map { |example| example[0] }
85
+ outcomes = Matrix.column_vector(examples.map { |example| example[1] })
86
+ if (terms.t * terms).det == 0
87
+ raise "The determinant is zero. There's likely no useful information here."
88
+ end
89
+ betas = ((terms.t * terms).inv * terms.t * outcomes).t.to_a.flatten.map { |e|
90
+ e.to_f.round(4)
91
+ }
92
+ [keys, betas]
93
+ end
94
+
95
+ def estimate_outcomes(model = nil)
96
+ if model.nil?
97
+ keys, betas = fitted_model
98
+ else
99
+ keys, betas = model
100
+ end
101
+ keys, features = incomplete_features(keys)
102
+ features.map { |idea|
103
+ val = 0
104
+ idea[0].each_with_index { |attribute, i|
105
+ val += betas[i] * attribute
106
+ }
107
+ val
80
108
  }
81
109
  end
82
110
 
83
- def complete_features
84
- extract_features(complete)
111
+ def complete_features(keys = [])
112
+ extract_features(complete, keys)
85
113
  end
86
114
 
87
- def incomplete_features
88
- extract_features(incomplete)
115
+ def incomplete_features(keys = [])
116
+ extract_features(incomplete, keys)
89
117
  end
90
118
 
91
119
  def choose(weather, time)
92
- fitted_model
93
- incomplete.first
120
+ keys, betas = fitted_model
121
+ jitter = betas.inject{|sum,x| sum + x }
122
+ outcomes = estimate_outcomes([keys, betas]).each_with_index.map {|k,i|
123
+ [k,i]
124
+ }.sort_by {|k| -k[0] + rand(jitter)}
125
+ best = outcomes.first[1]
126
+ incomplete[best]
94
127
  end
95
128
 
96
129
  end
@@ -5,5 +5,7 @@ require 'statsample'
5
5
  require 'trollop'
6
6
  require 'date_ideas'
7
7
  require 'date_idea'
8
+ require 'mathn'
9
+ require 'version'
8
10
 
9
11
  $LOAD_PATH.shift
@@ -1,3 +1,3 @@
1
1
  module Dates
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dates
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-02-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: statsample
16
- requirement: &70210141108340 !ruby/object:Gem::Requirement
16
+ requirement: &70180995201540 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70210141108340
24
+ version_requirements: *70180995201540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: colorize
27
- requirement: &70210141103020 !ruby/object:Gem::Requirement
27
+ requirement: &70180995201020 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70210141103020
35
+ version_requirements: *70180995201020
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: trollop
38
- requirement: &70210141102340 !ruby/object:Gem::Requirement
38
+ requirement: &70180995200600 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70210141102340
46
+ version_requirements: *70180995200600
47
47
  description: Dates keeps track of things you two have been meaning to do, and learns
48
48
  to make good suggestions as you teach it.
49
49
  email: maxhodak@gmail.com