sooth 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.
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: []