sooth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35b7050c2c66e43c65ee1afc05bb4534267d01e3
4
+ data.tar.gz: 79302a0867744f4cd86d4090adcc3b1c792f22c5
5
+ SHA512:
6
+ metadata.gz: ae6731afecca1a16085d65601c7f01ff8157d9e5a2d2f9fff987b6bd74dec00efd1de9a8f51402327669101e6646dee2d9971e6b267240453247d2443efae39b
7
+ data.tar.gz: 44b75b169a0c4ffed66eb873d92c93f6ddb305dc037c6dc14e8411d39d50f1ee3bd8a0f16723cadbcd14d5cea2041bb403d5613003bd9ab7cfe573a8322d085b
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'rspec', '~> 3.1'
5
+ gem 'yard', '~> 0.8'
6
+ gem 'rdoc', '~> 4.1'
7
+ gem 'bundler', '~> 1.7'
8
+ gem 'jeweler', '~> 2.0'
9
+ gem 'simplecov', '~> 0.9'
10
+ gem 'byebug', '~> 3.5'
11
+ gem 'rake-compiler', '~> 0.9'
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,90 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.3.6)
5
+ builder (3.2.2)
6
+ byebug (3.5.1)
7
+ columnize (~> 0.8)
8
+ debugger-linecache (~> 1.2)
9
+ slop (~> 3.6)
10
+ columnize (0.9.0)
11
+ debugger-linecache (1.2.0)
12
+ descendants_tracker (0.0.4)
13
+ thread_safe (~> 0.3, >= 0.3.1)
14
+ diff-lcs (1.2.5)
15
+ docile (1.1.5)
16
+ faraday (0.9.0)
17
+ multipart-post (>= 1.2, < 3)
18
+ git (1.2.8)
19
+ github_api (0.12.2)
20
+ addressable (~> 2.3)
21
+ descendants_tracker (~> 0.0.4)
22
+ faraday (~> 0.8, < 0.10)
23
+ hashie (>= 3.3)
24
+ multi_json (>= 1.7.5, < 2.0)
25
+ nokogiri (~> 1.6.3)
26
+ oauth2
27
+ hashie (3.3.2)
28
+ highline (1.6.21)
29
+ jeweler (2.0.1)
30
+ builder
31
+ bundler (>= 1.0)
32
+ git (>= 1.2.5)
33
+ github_api
34
+ highline (>= 1.6.15)
35
+ nokogiri (>= 1.5.10)
36
+ rake
37
+ rdoc
38
+ json (1.8.1)
39
+ jwt (1.2.0)
40
+ mini_portile (0.6.1)
41
+ multi_json (1.10.1)
42
+ multi_xml (0.5.5)
43
+ multipart-post (2.0.0)
44
+ nokogiri (1.6.5)
45
+ mini_portile (~> 0.6.0)
46
+ oauth2 (1.0.0)
47
+ faraday (>= 0.8, < 0.10)
48
+ jwt (~> 1.0)
49
+ multi_json (~> 1.3)
50
+ multi_xml (~> 0.5)
51
+ rack (~> 1.2)
52
+ rack (1.5.2)
53
+ rake (10.4.2)
54
+ rake-compiler (0.9.3)
55
+ rake
56
+ rdoc (4.2.0)
57
+ json (~> 1.4)
58
+ rspec (3.1.0)
59
+ rspec-core (~> 3.1.0)
60
+ rspec-expectations (~> 3.1.0)
61
+ rspec-mocks (~> 3.1.0)
62
+ rspec-core (3.1.7)
63
+ rspec-support (~> 3.1.0)
64
+ rspec-expectations (3.1.2)
65
+ diff-lcs (>= 1.2.0, < 2.0)
66
+ rspec-support (~> 3.1.0)
67
+ rspec-mocks (3.1.3)
68
+ rspec-support (~> 3.1.0)
69
+ rspec-support (3.1.2)
70
+ simplecov (0.9.1)
71
+ docile (~> 1.1.0)
72
+ multi_json (~> 1.0)
73
+ simplecov-html (~> 0.8.0)
74
+ simplecov-html (0.8.0)
75
+ slop (3.6.0)
76
+ thread_safe (0.3.4)
77
+ yard (0.8.7.6)
78
+
79
+ PLATFORMS
80
+ ruby
81
+
82
+ DEPENDENCIES
83
+ bundler (~> 1.7)
84
+ byebug (~> 3.5)
85
+ jeweler (~> 2.0)
86
+ rake-compiler (~> 0.9)
87
+ rdoc (~> 4.1)
88
+ rspec (~> 3.1)
89
+ simplecov (~> 0.9)
90
+ yard (~> 0.8)
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ [![Gem Version](https://badge.fury.io/rb/sooth.svg)](http://badge.fury.io/rb/sooth)
2
+ [![Dependency Status](https://gemnasium.com/jasonhutchens/sooth.png)](https://gemnasium.com/jasonhutchens/sooth)
3
+ [![Build Status](https://secure.travis-ci.org/jasonhutchens/sooth.png)](http://travis-ci.org/#!/jasonhutchens/sooth)
4
+ [![Code Climate](https://codeclimate.com/github/jasonhutchens/sooth.png)](https://codeclimate.com/github/jasonhutchens/sooth)
5
+
6
+ Sooth
7
+ =====
8
+
9
+ Sooth is a simple stochastic predictive model.
10
+
11
+ Getting Started
12
+ ---------------
13
+
14
+ Apart from the specs, look at the [API docs](http://rubydoc.info/github/jasonhutchens/sooth/master/frames) to get up to speed.
15
+
16
+ Next
17
+ ----
18
+
19
+ * Implement save and load (with specs)
20
+ * Version 0.9
21
+ * Hook up to all services
22
+ * Version 1
23
+ * MegaHAL that uses it
24
+
25
+ Copyright
26
+ ---------
27
+
28
+ Copyright (c) 2014 Jason Hutchens. See UNLICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "sooth"
18
+ gem.homepage = "http://github.com/jasonhutchens/sooth"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A small thing for generating codes for users to type into places}
21
+ gem.description = %Q{Does what it says on the box}
22
+ gem.email = "jasonhutchens@gmail.com"
23
+ gem.authors = ["Jason Hutchens"]
24
+ gem.required_ruby_version = "~> 2.1"
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/extensiontask'
30
+ Rake::ExtensionTask.new('sooth_native')
31
+
32
+ require 'rspec/core'
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |spec|
35
+ spec.pattern = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ desc "Code coverage detail"
39
+ task :simplecov do
40
+ ENV['COVERAGE'] = "true"
41
+ Rake::Task['spec'].execute
42
+ end
43
+
44
+ task :default => :spec
45
+
46
+ require 'yard'
47
+ YARD::Rake::YardocTask.new
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('sooth_native')
@@ -0,0 +1,190 @@
1
+ //==============================================================================
2
+
3
+ #include <ruby.h>
4
+
5
+ #include "sooth_predictor.h"
6
+
7
+ //------------------------------------------------------------------------------
8
+
9
+ VALUE Sooth = Qnil;
10
+ VALUE SoothNative = Qnil;
11
+
12
+ VALUE method_sooth_native_allocate(VALUE klass);
13
+ void method_sooth_native_deallocate(void * predictor);
14
+
15
+ /* @!parse [ruby]
16
+ * module Sooth
17
+ * # A very simple stochastic predictor. Implemented in C for efficiency.
18
+ * # The idea here is to build up more complicated learning algorithms using
19
+ * # a trivial Markovian predictor.
20
+ * class Predictor
21
+ * def initialize(error_symbol)
22
+ * end
23
+ * def observe(bigram, symbol)
24
+ * # (native code)
25
+ * end
26
+ * def count(bigram)
27
+ * # (native code)
28
+ * end
29
+ * def select(bigram, limit)
30
+ * # (native code)
31
+ * end
32
+ * end
33
+ * end
34
+ *
35
+ * Returns a new Sooth::Predictor instance.
36
+ *
37
+ * @param [Fixnum] error_symbol The symbol to be returned by #select when no
38
+ * prediction can be made.
39
+ */
40
+ VALUE method_sooth_native_initialize(VALUE self, VALUE error_symbol);
41
+
42
+ /*
43
+ * Add an observation of the given symbol in the context of the bigram.
44
+ *
45
+ * @param [Array] bigram A pair of symbols that provide context, allowing the
46
+ * predictor to maintain observation statistics for
47
+ * different contexts.
48
+ * @param [Fixnum] symbol The symbol that has been observed.
49
+ * @return [Fixnum] A count of the number of times the symbol has been
50
+ * observed in the context of the bigram.
51
+ */
52
+ VALUE method_sooth_native_observe(VALUE self, VALUE bigram, VALUE symbol);
53
+
54
+ /*
55
+ * Return a count of the number of times the bigram has been observed.
56
+ *
57
+ * @param [Array] bigram A pair of symbols.
58
+ * @return [Fixnum] A count of the number of times the bigram has been
59
+ * observed. This is guaranteed to be equal to the sum
60
+ * of the counts of observations of all symbols in the
61
+ * context of the bigram.
62
+ */
63
+ VALUE method_sooth_native_count(VALUE self, VALUE bigram);
64
+
65
+ /*
66
+ * Return a symbol that may occur in the context of the bigram. The
67
+ * limit is used to select a symbol. This is done by iterating through
68
+ * all of the symbols that have been observed in the context of the
69
+ * bigram, subtracting the observation count of each symbol from the
70
+ * supplied limit. For this reason, limit should be between 1 and the
71
+ * observation count of the bigram itself, as returned by #count.
72
+ *
73
+ * @param [Array] bigram A pair of symbols.
74
+ * @param [Fixnum] limit The total numbe of symbol observations to be
75
+ * analysed before returning a symbol.
76
+ * @return [Fixnum] A symbol that has been observed previously in the
77
+ * context of the bigram, or the error_symbol if no
78
+ * such symbol exists, or if the supplied limit was
79
+ * too large.
80
+ */
81
+ VALUE method_sooth_native_select(VALUE self, VALUE bigram, VALUE limit);
82
+
83
+ //------------------------------------------------------------------------------
84
+
85
+ void Init_sooth_native()
86
+ {
87
+ Sooth = rb_define_module("Sooth");
88
+ SoothNative = rb_define_class_under(Sooth, "Predictor", rb_cObject);
89
+
90
+ rb_define_alloc_func(SoothNative, method_sooth_native_allocate);
91
+ rb_define_method(SoothNative, "initialize", method_sooth_native_initialize, 1);
92
+
93
+ rb_define_method(SoothNative, "observe", method_sooth_native_observe, 2);
94
+ rb_define_method(SoothNative, "count", method_sooth_native_count, 1);
95
+ rb_define_method(SoothNative, "select", method_sooth_native_select, 2);
96
+ }
97
+
98
+ //------------------------------------------------------------------------------
99
+
100
+ VALUE
101
+ method_sooth_native_allocate(VALUE klass)
102
+ {
103
+ SoothPredictor * predictor = sooth_predictor_init();
104
+ if (predictor == NULL)
105
+ {
106
+ return Qnil;
107
+ }
108
+ return Data_Wrap_Struct(klass, NULL, method_sooth_native_deallocate, predictor);
109
+ }
110
+
111
+ //------------------------------------------------------------------------------
112
+
113
+ void
114
+ method_sooth_native_deallocate(void * predictor)
115
+ {
116
+ sooth_predictor_free((SoothPredictor *)predictor);
117
+ }
118
+
119
+ //------------------------------------------------------------------------------
120
+
121
+ VALUE
122
+ method_sooth_native_initialize(VALUE self, VALUE error_symbol)
123
+ {
124
+ SoothPredictor * predictor = NULL;
125
+ Check_Type(error_symbol, T_FIXNUM);
126
+ Data_Get_Struct(self, SoothPredictor, predictor);
127
+ predictor->error_symbol = NUM2UINT(error_symbol);
128
+ return self;
129
+ }
130
+
131
+ //------------------------------------------------------------------------------
132
+
133
+ VALUE
134
+ method_sooth_native_observe(VALUE self, VALUE bigram, VALUE symbol)
135
+ {
136
+ SoothPredictor * predictor = NULL;
137
+ Check_Type(symbol, T_FIXNUM);
138
+ Check_Type(bigram, T_ARRAY);
139
+ if (RARRAY_LEN(bigram) != 2)
140
+ {
141
+ rb_raise(rb_eTypeError, "bigram must be an array of exactly two symbols");
142
+ }
143
+ Check_Type(RARRAY_PTR(bigram)[0], T_FIXNUM);
144
+ Check_Type(RARRAY_PTR(bigram)[1], T_FIXNUM);
145
+ Data_Get_Struct(self, SoothPredictor, predictor);
146
+ uint32_t c_bigram[2] = {NUM2UINT(RARRAY_PTR(bigram)[0]), NUM2UINT(RARRAY_PTR(bigram)[1])};
147
+ uint32_t count = sooth_predictor_observe(predictor, c_bigram, NUM2UINT(symbol));
148
+ return UINT2NUM(count);
149
+ }
150
+
151
+ //------------------------------------------------------------------------------
152
+
153
+ VALUE
154
+ method_sooth_native_count(VALUE self, VALUE bigram)
155
+ {
156
+ SoothPredictor * predictor = NULL;
157
+ Check_Type(bigram, T_ARRAY);
158
+ if (RARRAY_LEN(bigram) != 2)
159
+ {
160
+ rb_raise(rb_eTypeError, "bigram must be an array of exactly two symbols");
161
+ }
162
+ Check_Type(RARRAY_PTR(bigram)[0], T_FIXNUM);
163
+ Check_Type(RARRAY_PTR(bigram)[1], T_FIXNUM);
164
+ Data_Get_Struct(self, SoothPredictor, predictor);
165
+ uint32_t c_bigram[2] = {NUM2UINT(RARRAY_PTR(bigram)[0]), NUM2UINT(RARRAY_PTR(bigram)[1])};
166
+ uint64_t count = sooth_predictor_count(predictor, c_bigram);
167
+ return UINT2NUM(count);
168
+ }
169
+
170
+ //------------------------------------------------------------------------------
171
+
172
+ VALUE
173
+ method_sooth_native_select(VALUE self, VALUE bigram, VALUE limit)
174
+ {
175
+ SoothPredictor * predictor = NULL;
176
+ Check_Type(limit, T_FIXNUM);
177
+ Check_Type(bigram, T_ARRAY);
178
+ if (RARRAY_LEN(bigram) != 2)
179
+ {
180
+ rb_raise(rb_eTypeError, "bigram must be an array of exactly two symbols");
181
+ }
182
+ Check_Type(RARRAY_PTR(bigram)[0], T_FIXNUM);
183
+ Check_Type(RARRAY_PTR(bigram)[1], T_FIXNUM);
184
+ Data_Get_Struct(self, SoothPredictor, predictor);
185
+ uint32_t c_bigram[2] = {NUM2UINT(RARRAY_PTR(bigram)[0]), NUM2UINT(RARRAY_PTR(bigram)[1])};
186
+ uint32_t symbol = sooth_predictor_select(predictor, c_bigram, NUM2UINT(limit));
187
+ return UINT2NUM(symbol);
188
+ }
189
+
190
+ //==============================================================================
@@ -0,0 +1,21 @@
1
+ #ifndef SOOTH_CONTEXT_H
2
+ #define SOOTH_CONTEXT_H
3
+
4
+ //==============================================================================
5
+
6
+ #include <stdint.h>
7
+
8
+ typedef struct
9
+ {
10
+ uint32_t bigram[2];
11
+ uint64_t count;
12
+ uint32_t statistics_size;
13
+ uint64_t statistics_offset;
14
+ }
15
+ SoothContext;
16
+
17
+ //------------------------------------------------------------------------------
18
+
19
+ //==============================================================================
20
+
21
+ #endif
@@ -0,0 +1,257 @@
1
+ //==============================================================================
2
+
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+
6
+ #include "sooth_predictor.h"
7
+
8
+ //------------------------------------------------------------------------------
9
+
10
+ SoothPredictor *
11
+ sooth_predictor_init()
12
+ {
13
+ SoothPredictor * predictor = malloc(sizeof(SoothPredictor));
14
+
15
+ if (predictor == NULL)
16
+ {
17
+ return NULL;
18
+ }
19
+
20
+ predictor->error_symbol = 0;
21
+
22
+ predictor->contexts = NULL;
23
+ predictor->contexts_size = 0;
24
+
25
+ predictor->statistics = NULL;
26
+ predictor->statistics_size = 0;
27
+
28
+ return predictor;
29
+ }
30
+
31
+ //------------------------------------------------------------------------------
32
+
33
+ void
34
+ sooth_predictor_free(SoothPredictor * predictor)
35
+ {
36
+ free(predictor->contexts);
37
+ free(predictor->statistics);
38
+
39
+ predictor->contexts = NULL;
40
+ predictor->contexts_size = 0;
41
+
42
+ predictor->statistics = NULL;
43
+ predictor->statistics_size = 0;
44
+
45
+ free(predictor);
46
+ }
47
+
48
+ //------------------------------------------------------------------------------
49
+
50
+ void
51
+ sooth_predictor_save(const char * const filename, SoothPredictor * predictor)
52
+ {
53
+ }
54
+
55
+ //------------------------------------------------------------------------------
56
+
57
+ SoothPredictor *
58
+ sooth_predictor_load(const char * const filename)
59
+ {
60
+ return NULL;
61
+ }
62
+
63
+ //------------------------------------------------------------------------------
64
+ SoothContext *
65
+ sooth_predictor_find_context(SoothPredictor * predictor, uint32_t bigram[2])
66
+ {
67
+ SoothContext * context = NULL;
68
+ uint64_t mid = 0;
69
+
70
+ if (predictor->contexts_size > 0)
71
+ {
72
+ uint64_t low = 0;
73
+ uint64_t high = predictor->contexts_size - 1;
74
+
75
+ while (low <= high)
76
+ {
77
+ mid = low + (high - low) / 2;
78
+ context = &(predictor->contexts[mid]);
79
+ if (context->bigram[0] < bigram[0] || context->bigram[0] == bigram[0] && context->bigram[1] < bigram[1])
80
+ {
81
+ low = mid + 1;
82
+ }
83
+ else if (context->bigram[0] > bigram[0] || context->bigram[0] == bigram[0] && context->bigram[1] > bigram[1])
84
+ {
85
+ if (mid == 0)
86
+ {
87
+ break;
88
+ }
89
+ high = mid - 1;
90
+ }
91
+ else
92
+ {
93
+ return context;
94
+ }
95
+ }
96
+
97
+ mid = low;
98
+ }
99
+
100
+ predictor->contexts_size += 1;
101
+ SoothContext * new_memory = realloc(predictor->contexts, sizeof(SoothContext) * predictor->contexts_size);
102
+ if (new_memory == NULL)
103
+ {
104
+ return NULL;
105
+ }
106
+ predictor->contexts = new_memory;
107
+
108
+ if ((mid + 1) < predictor->contexts_size)
109
+ {
110
+ SoothContext * src = &(predictor->contexts[mid]);
111
+ SoothContext * dest = &(predictor->contexts[mid+1]);
112
+ (void)memmove(dest, src, sizeof(SoothContext) * (predictor->contexts_size - mid - 1));
113
+ }
114
+
115
+ context = &(predictor->contexts[mid]);
116
+ context->bigram[0] = bigram[0];
117
+ context->bigram[1] = bigram[1];
118
+ context->count = 0;
119
+ context->statistics_size = 0;
120
+
121
+ return context;
122
+ }
123
+
124
+ //------------------------------------------------------------------------------
125
+
126
+ SoothStatistic *
127
+ sooth_predictor_find_statistic(SoothPredictor * predictor, SoothContext * context, uint32_t symbol)
128
+ {
129
+ SoothStatistic * statistic = NULL;
130
+ uint64_t mid = 0;
131
+
132
+ if (context->statistics_size > 0)
133
+ {
134
+ uint64_t low = 0;
135
+ uint64_t high = context->statistics_size - 1;
136
+
137
+ while (low <= high)
138
+ {
139
+ mid = low + (high - low) / 2;
140
+ statistic = &(predictor->statistics[mid + context->statistics_offset]);
141
+ if (statistic->symbol < symbol)
142
+ {
143
+ low = mid + 1;
144
+ }
145
+ else if (statistic->symbol > symbol)
146
+ {
147
+ if (mid == 0)
148
+ {
149
+ break;
150
+ }
151
+ high = mid - 1;
152
+ }
153
+ else
154
+ {
155
+ return statistic;
156
+ }
157
+ }
158
+
159
+ mid = low;
160
+ }
161
+
162
+ if (context->statistics_size == 0)
163
+ {
164
+ context->statistics_offset = predictor->statistics_size;
165
+ }
166
+ context->statistics_size += 1;
167
+ mid += context -> statistics_offset;
168
+
169
+ predictor->statistics_size += 1;
170
+ SoothStatistic * new_memory = realloc(predictor->statistics, sizeof(SoothStatistic) * predictor->statistics_size);
171
+ if (new_memory == NULL)
172
+ {
173
+ return NULL;
174
+ }
175
+ predictor->statistics = new_memory;
176
+
177
+ if ((mid + 1) < predictor->statistics_size)
178
+ {
179
+ SoothStatistic * src = &(predictor->statistics[mid]);
180
+ SoothStatistic * dest = &(predictor->statistics[mid+1]);
181
+ (void)memmove(dest, src, sizeof(SoothStatistic) * (predictor->statistics_size - mid - 1));
182
+ }
183
+
184
+ statistic = &(predictor->statistics[mid]);
185
+ statistic->symbol = symbol;
186
+ statistic->count = 0;
187
+
188
+ return statistic;
189
+ }
190
+
191
+ //------------------------------------------------------------------------------
192
+
193
+ uint32_t
194
+ sooth_predictor_observe(SoothPredictor * predictor, uint32_t bigram[2], uint32_t symbol)
195
+ {
196
+ SoothContext * context = sooth_predictor_find_context(predictor, bigram);
197
+
198
+ if (context == NULL)
199
+ {
200
+ return 0;
201
+ }
202
+
203
+ SoothStatistic * statistic = sooth_predictor_find_statistic(predictor, context, symbol);
204
+
205
+ if (statistic == NULL)
206
+ {
207
+ return 0;
208
+ }
209
+
210
+ statistic->count += 1;
211
+ context->count += 1;
212
+
213
+ return statistic->count;
214
+ }
215
+
216
+ //------------------------------------------------------------------------------
217
+
218
+ uint64_t
219
+ sooth_predictor_count(SoothPredictor * predictor, uint32_t bigram[2])
220
+ {
221
+ SoothContext * context = sooth_predictor_find_context(predictor, bigram);
222
+
223
+ if (context == NULL)
224
+ {
225
+ return 0;
226
+ }
227
+
228
+ return context->count;
229
+ }
230
+
231
+ //------------------------------------------------------------------------------
232
+
233
+ uint32_t
234
+ sooth_predictor_select(SoothPredictor * predictor, uint32_t bigram[2], uint64_t limit)
235
+ {
236
+ SoothContext * context = sooth_predictor_find_context(predictor, bigram);
237
+
238
+ if (context == NULL || limit == 0)
239
+ {
240
+ return predictor->error_symbol;
241
+ }
242
+
243
+ for (uint64_t i = 0; i < context->statistics_size; ++i)
244
+ {
245
+ SoothStatistic statistic = predictor->statistics[context->statistics_offset + i];
246
+ if (limit > statistic.count)
247
+ {
248
+ limit -= statistic.count;
249
+ continue;
250
+ }
251
+ return statistic.symbol;
252
+ }
253
+
254
+ return predictor->error_symbol;
255
+ }
256
+
257
+ //==============================================================================
@@ -0,0 +1,33 @@
1
+ #ifndef SOOTH_PREDICTOR_H
2
+ #define SOOTH_PREDICTOR_H
3
+
4
+ //==============================================================================
5
+
6
+ #include <stdint.h>
7
+
8
+ #include "sooth_context.h"
9
+ #include "sooth_statistic.h"
10
+
11
+ typedef struct
12
+ {
13
+ uint32_t error_symbol;
14
+ uint64_t contexts_size;
15
+ SoothContext * contexts;
16
+ uint64_t statistics_size;
17
+ SoothStatistic * statistics;
18
+ }
19
+ SoothPredictor;
20
+
21
+ //------------------------------------------------------------------------------
22
+
23
+ SoothPredictor * sooth_predictor_init();
24
+ void sooth_predictor_free(SoothPredictor * predictor);
25
+ void sooth_predictor_save(const char * const filename, SoothPredictor * predictor);
26
+ SoothPredictor * sooth_predictor_load(const char * const filename);
27
+ uint32_t sooth_predictor_observe(SoothPredictor * predictor, uint32_t bigram[2], uint32_t symbol);
28
+ uint64_t sooth_predictor_count(SoothPredictor * predictor, uint32_t bigram[2]);
29
+ uint32_t sooth_predictor_select(SoothPredictor * predictor, uint32_t bigram[2], uint64_t limit);
30
+
31
+ //==============================================================================
32
+
33
+ #endif
@@ -0,0 +1,19 @@
1
+ #ifndef SOOTH_STATISTIC_H
2
+ #define SOOTH_STATISTIC_H
3
+
4
+ //==============================================================================
5
+
6
+ #include <stdint.h>
7
+
8
+ typedef struct
9
+ {
10
+ uint32_t symbol;
11
+ uint32_t count;
12
+ }
13
+ SoothStatistic;
14
+
15
+ //------------------------------------------------------------------------------
16
+
17
+ //==============================================================================
18
+
19
+ #endif
data/lib/sooth.rb ADDED
@@ -0,0 +1 @@
1
+ require 'sooth_native'
data/sooth.gemspec ADDED
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: sooth 0.1.0 ruby lib
6
+ # stub: ext/sooth_native/extconf.rb
7
+
8
+ Gem::Specification.new do |s|
9
+ s.name = "sooth"
10
+ s.version = "0.1.0"
11
+
12
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
13
+ s.require_paths = ["lib"]
14
+ s.authors = ["Jason Hutchens"]
15
+ s.date = "2014-12-10"
16
+ s.description = "Does what it says on the box"
17
+ s.email = "jasonhutchens@gmail.com"
18
+ s.extensions = ["ext/sooth_native/extconf.rb"]
19
+ s.extra_rdoc_files = [
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "README.md",
26
+ "Rakefile",
27
+ "UNLICENSE",
28
+ "VERSION",
29
+ "ext/sooth_native/extconf.rb",
30
+ "ext/sooth_native/native.c",
31
+ "ext/sooth_native/sooth_context.h",
32
+ "ext/sooth_native/sooth_predictor.c",
33
+ "ext/sooth_native/sooth_predictor.h",
34
+ "ext/sooth_native/sooth_statistic.h",
35
+ "lib/sooth.rb",
36
+ "sooth.gemspec",
37
+ "spec/memory_spec.rb",
38
+ "spec/predictor_spec.rb",
39
+ "spec/spec_helper.rb"
40
+ ]
41
+ s.homepage = "http://github.com/jasonhutchens/sooth"
42
+ s.licenses = ["MIT"]
43
+ s.required_ruby_version = Gem::Requirement.new("~> 2.1")
44
+ s.rubygems_version = "2.4.4"
45
+ s.summary = "A small thing for generating codes for users to type into places"
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 4
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_development_dependency(%q<rspec>, ["~> 3.1"])
52
+ s.add_development_dependency(%q<yard>, ["~> 0.8"])
53
+ s.add_development_dependency(%q<rdoc>, ["~> 4.1"])
54
+ s.add_development_dependency(%q<bundler>, ["~> 1.7"])
55
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0"])
56
+ s.add_development_dependency(%q<simplecov>, ["~> 0.9"])
57
+ s.add_development_dependency(%q<byebug>, ["~> 3.5"])
58
+ s.add_development_dependency(%q<rake-compiler>, ["~> 0.9"])
59
+ else
60
+ s.add_dependency(%q<rspec>, ["~> 3.1"])
61
+ s.add_dependency(%q<yard>, ["~> 0.8"])
62
+ s.add_dependency(%q<rdoc>, ["~> 4.1"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.7"])
64
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
65
+ s.add_dependency(%q<simplecov>, ["~> 0.9"])
66
+ s.add_dependency(%q<byebug>, ["~> 3.5"])
67
+ s.add_dependency(%q<rake-compiler>, ["~> 0.9"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<rspec>, ["~> 3.1"])
71
+ s.add_dependency(%q<yard>, ["~> 0.8"])
72
+ s.add_dependency(%q<rdoc>, ["~> 4.1"])
73
+ s.add_dependency(%q<bundler>, ["~> 1.7"])
74
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
75
+ s.add_dependency(%q<simplecov>, ["~> 0.9"])
76
+ s.add_dependency(%q<byebug>, ["~> 3.5"])
77
+ s.add_dependency(%q<rake-compiler>, ["~> 0.9"])
78
+ end
79
+ end
80
+
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Sooth::Predictor do
4
+ let(:predictor) { Sooth::Predictor.new(42) }
5
+
6
+ describe "#observe" do
7
+ it "does not segfault when sorting bigrams" do
8
+ expect(predictor.observe([3,3], 1)).to eq(1)
9
+ expect(predictor.observe([5,5], 1)).to eq(1)
10
+ expect(predictor.observe([4,4], 1)).to eq(1)
11
+ expect(predictor.observe([5,5], 1)).to eq(2)
12
+ expect(predictor.observe([3,3], 1)).to eq(2)
13
+ expect(predictor.observe([4,4], 1)).to eq(2)
14
+ expect(predictor.observe([2,2], 1)).to eq(1)
15
+ expect(predictor.observe([4,4], 1)).to eq(3)
16
+ expect(predictor.observe([2,2], 1)).to eq(2)
17
+ expect(predictor.observe([3,3], 1)).to eq(3)
18
+ expect(predictor.observe([5,5], 1)).to eq(3)
19
+ end
20
+
21
+ it "does not segfault when sorting symbols" do
22
+ expect(predictor.observe([1,2], 3)).to eq(1)
23
+ expect(predictor.observe([1,2], 5)).to eq(1)
24
+ expect(predictor.observe([1,2], 4)).to eq(1)
25
+ expect(predictor.observe([1,2], 5)).to eq(2)
26
+ expect(predictor.observe([1,2], 3)).to eq(2)
27
+ expect(predictor.observe([1,2], 4)).to eq(2)
28
+ expect(predictor.observe([1,2], 2)).to eq(1)
29
+ expect(predictor.observe([1,2], 4)).to eq(3)
30
+ expect(predictor.observe([1,2], 2)).to eq(2)
31
+ expect(predictor.observe([1,2], 3)).to eq(3)
32
+ expect(predictor.observe([1,2], 5)).to eq(3)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Sooth::Predictor do
4
+ let(:predictor) { Sooth::Predictor.new(42) }
5
+
6
+ describe "#observe" do
7
+ it "increments observation counts" do
8
+ expect(predictor.observe([1,2], 3)).to eq(1)
9
+ expect(predictor.observe([1,2], 3)).to eq(2)
10
+ expect(predictor.observe([1,2], 3)).to eq(3)
11
+ end
12
+
13
+ it "properly sorts and finds bigrams" do
14
+ expect(predictor.observe([2,1], 3)).to eq(1)
15
+ expect(predictor.observe([1,3], 2)).to eq(1)
16
+ expect(predictor.observe([3,2], 1)).to eq(1)
17
+ expect(predictor.observe([1,3], 2)).to eq(2)
18
+ expect(predictor.observe([2,1], 3)).to eq(2)
19
+ expect(predictor.observe([3,2], 1)).to eq(2)
20
+ end
21
+ end
22
+
23
+ describe "#count" do
24
+ it "returns a zero count for an unobserved bigram" do
25
+ expect(predictor.count([1,2])).to eq(0)
26
+ end
27
+
28
+ it "returns the total count for an observed bigram" do
29
+ predictor.observe([1,2], 2)
30
+ predictor.observe([1,2], 1)
31
+ predictor.observe([1,2], 4)
32
+ predictor.observe([1,2], 3)
33
+ predictor.observe([1,2], 0)
34
+ predictor.observe([1,2], 1)
35
+ predictor.observe([1,2], 4)
36
+ expect(predictor.count([1,2])).to eq(7)
37
+ end
38
+ end
39
+
40
+ describe "#select" do
41
+ it "returns the error symbol for an unobserved bigram" do
42
+ expect(predictor.select([1,2], 1)).to eq(42)
43
+ end
44
+
45
+ it "returns the correct symbol for an observed bigram" do
46
+ predictor.observe([1,2], 4)
47
+ predictor.observe([1,2], 3)
48
+ predictor.observe([1,2], 4)
49
+ predictor.observe([1,2], 5)
50
+ expect(predictor.select([1,2], 1)).to eq(3)
51
+ expect(predictor.select([1,2], 2)).to eq(4)
52
+ expect(predictor.select([1,2], 3)).to eq(4)
53
+ expect(predictor.select([1,2], 4)).to eq(5)
54
+ end
55
+
56
+ it "returns the error symbol for a limit that is out of range" do
57
+ predictor.observe([1,2], 4)
58
+ predictor.observe([1,2], 3)
59
+ predictor.observe([1,2], 5)
60
+ expect(predictor.select([1,2], 0)).to eq(42)
61
+ expect(predictor.select([1,2], 4)).to eq(42)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,30 @@
1
+ require 'simplecov'
2
+
3
+ module SimpleCov::Configuration
4
+ def clean_filters
5
+ @filters = []
6
+ end
7
+ end
8
+
9
+ SimpleCov.configure do
10
+ clean_filters
11
+ load_profile 'test_frameworks'
12
+ end
13
+
14
+ ENV["COVERAGE"] && SimpleCov.start do
15
+ add_filter "/.rvm/"
16
+ end
17
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
18
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
19
+
20
+ require 'rspec'
21
+
22
+ require 'sooth'
23
+
24
+ # Requires supporting files with custom matchers and macros, etc,
25
+ # in ./support/ and its subdirectories.
26
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
27
+
28
+ RSpec.configure do |config|
29
+
30
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sooth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jason Hutchens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jeweler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake-compiler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.9'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.9'
125
+ description: Does what it says on the box
126
+ email: jasonhutchens@gmail.com
127
+ executables: []
128
+ extensions:
129
+ - ext/sooth_native/extconf.rb
130
+ extra_rdoc_files:
131
+ - README.md
132
+ files:
133
+ - Gemfile
134
+ - Gemfile.lock
135
+ - README.md
136
+ - Rakefile
137
+ - UNLICENSE
138
+ - VERSION
139
+ - ext/sooth_native/extconf.rb
140
+ - ext/sooth_native/native.c
141
+ - ext/sooth_native/sooth_context.h
142
+ - ext/sooth_native/sooth_predictor.c
143
+ - ext/sooth_native/sooth_predictor.h
144
+ - ext/sooth_native/sooth_statistic.h
145
+ - lib/sooth.rb
146
+ - sooth.gemspec
147
+ - spec/memory_spec.rb
148
+ - spec/predictor_spec.rb
149
+ - spec/spec_helper.rb
150
+ homepage: http://github.com/jasonhutchens/sooth
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: '2.1'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.4.4
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: A small thing for generating codes for users to type into places
174
+ test_files: []