ryeppp 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ *.so
4
+ *.swp
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
20
+ ext/ryeppp/ryeppp.c
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ryeppp.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
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
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Ryeppp
2
+
3
+ This gem provides bindings to the [Yeppp!](http://www.yeppp.info/) library.
4
+ According to the documentation, "Yeppp! is a high-performance SIMD-optimized
5
+ mathematical library for x86, ARM, and MIPS processors on Windows, Android, Mac
6
+ OS X, and GNU/Linux systems."
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'ryeppp'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install ryeppp
21
+
22
+ You'll also need to [download](http://www.yeppp.info/downloads.html) the Yeppp!
23
+ library and unpack it in $HOME.
24
+
25
+ ## Usage
26
+
27
+ The Ryeppp gem provides a single class `Ryeppp` with the following methods:
28
+
29
+ * `add_v64fv64f_v64f` - pairwise add 2 vectors of floats
30
+ * `add_v64sv64s_v64s` - pairwise add 2 vectors of integers
31
+
32
+ * `subtract_v64fv64f_v64f` - pairwise subtract 2 vectors of floats
33
+ * `subtract_v64sv64s_v64s` - pairwise subtract 2 vectors of integers
34
+
35
+ * `multiply_v64fs64f_v64f` - multiply a vector of floats by a float
36
+ * `multiply_v64sv64s_v64s` - multiply a vector of integers by an integer
37
+ * `multiply_v64fv64f_v64f` - pairwise multiply 2 vectors of floats
38
+ * `multiply_v64ss64s_v64s` - pairwise multiply 2 vectors of integers
39
+
40
+ * `dotproduct_v64fv64f_s64f` - compute the dot product of 2 vectors of floats
41
+
42
+ * `min_v64f_s64f` - find the minimum in a vector of floats
43
+ * `min_v64s_s64s` - find the minimum in a vector of integers
44
+
45
+ * `max_v64f_s64f` - find the maximum in a vector of floats
46
+ * `max_v64s_s64s` - find the maximum in a vector of integers
47
+
48
+ * `min_v64fv64f_v64f` - find the pairwise minimum in 2 vectors of floats
49
+
50
+ * `max_v64fv64f_v64f` - find the pairwise maximum in 2 vectors of floats
51
+
52
+ * `min_v64fs64f_v64f` - find the pairwise minimum of a vector of floats and a
53
+ constant
54
+
55
+ * `max_v64fs64f_v64f` - find the pairwise maximum of a vector of floats and a
56
+ constant
57
+
58
+ * `negate_v64f_s64f` - negate a vector of floats
59
+ * `negate_v64s_s64s` - negate a vector of integers
60
+
61
+ * `sum_v64f_s64f` - compute the sum of a vector of floats
62
+ * `sumabs_v64f_s64f` - compute the sum of the absolute values of a vector of
63
+ floats
64
+ * `sumsquares_v64f_s64f` - compute the sum of the squares of the values of a
65
+ vector of floats
66
+
67
+ * `log_v64f_v64f` - compute the natural logarithm of the values of a vector of
68
+ floats
69
+ * `exp_v64f_v64f` - compute the base-_e_ exponent of the values of a vector of
70
+ floats
71
+ * `sin_v64f_v64f` - compute the sine of the values of a vector of floats
72
+ * `cos_v64f_v64f` - compute the cosine of the values of a vector of floats
73
+ * `tan_v64f_v64f` - compute the tangent of the values of a vector of floats
74
+
75
+ * `evaluatepolynomial_v64fv64f_v64f` - evaluate the polynomial with the given
76
+ float coefficients in standard form at the given _x_-values
77
+
78
+ ## Benchmarks
79
+
80
+ Since Yeppp! depends on your processor, using the library may or may not
81
+ provide performance improvements, so it's important to benchmark your code on
82
+ your own processor. A few [benchmarks](http://www.yeppp.info/benchmarks.html)
83
+ are provided, and the [examples](http://docs.yeppp.info/c/examples.html) also
84
+ provide performance comparisons.
85
+
86
+ To run the benchmarks, simply run
87
+
88
+ $ ruby lib/ryeppp/bench.rb
89
+
90
+ ## TODO
91
+
92
+ Add more benchmarks.
93
+
94
+ ## Contributing
95
+
96
+ 1. Fork it
97
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
98
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
99
+ 4. Push to the branch (`git push origin my-new-feature`)
100
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/extensiontask"
3
+ require "rspec/core/rake_task"
4
+
5
+ spec = Gem::Specification.load('ryeppp.gemspec')
6
+ Rake::ExtensionTask.new('ryeppp', spec)
7
+
8
+ desc "Ryeppp unit tests"
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.pattern = "spec/*_spec.rb"
11
+ t.verbose = true
12
+ end
13
+
14
+ desc "Ryeppp c generation"
15
+ task :c_generation do
16
+ current_dir = __FILE__.split(/\//)[0..-2].join('/')
17
+ require File.join(current_dir, 'ext/templates/ryeppp.c.rb')
18
+ c_code = [
19
+ HEADERS,
20
+ PRIMARY,
21
+ FUNCS.call('Add'),
22
+ FUNCS.call('Subtract'),
23
+ FUNCS.call('Multiply'),
24
+ DOT_PRODUCT,
25
+ MIN_MAX,
26
+ PAIRWISE_MIN_MAX,
27
+ CONSTANT_MIN_MAX,
28
+ NEGATE,
29
+ SUMS,
30
+ MATHS,
31
+ POLYNOMIAL,
32
+ INITIALIZER
33
+ ].join("\n\n")
34
+ File.open(File.join(current_dir, 'ext/ryeppp/ryeppp.c'), 'w') do |f|
35
+ f.write(c_code)
36
+ end
37
+ end
38
+
39
+ task :default => [:c_generation, :compile, :spec]
@@ -0,0 +1,518 @@
1
+ MAX_SIGNED_INTEGER = 2**63 - 1
2
+ MIN_SIGNED_INTEGER = -1 * MAX_SIGNED_INTEGER
3
+
4
+ class String
5
+ def pluralize
6
+ "#{self}#{self.size > 0 && self[-1] == 'e' ? 's' : 'es'}"
7
+ end
8
+ end
9
+
10
+ def allocate_yep64_typed_array_and_assert(var_names, len_var_name, opts={})
11
+ var_names = Array(var_names)
12
+ type = opts[:type] || '{{type}}'
13
+ assert = opts[:assert].nil? ? true : opts[:assert]
14
+ %{#{var_names.map{|vn| %{Yep64#{type} *yep_#{vn} = (Yep64#{type}*)calloc(#{len_var_name}, sizeof(Yep64#{type}));}}.join("\n")}
15
+ #{assert ? var_names.map{|vn| %{assert(yep_#{vn} != NULL);}}.join("\n") : nil}}
16
+ end
17
+
18
+ def deinitialize_yeppp
19
+ %{/* Deinitialize the Yeppp! library */
20
+ status = yepLibrary_Release();
21
+ assert(status == YepStatusOk);}
22
+ end
23
+
24
+ def initialize_yeppp
25
+ %{/* Initialize the Yeppp! library */
26
+ status = yepLibrary_Init();
27
+ assert(status == YepStatusOk);}
28
+ end
29
+
30
+ def guard_integer_input_size(var_name, iteration_var_name)
31
+ %{if (rb_funcall(#{var_name}_a[#{iteration_var_name}], '>', 1, #{MAX_SIGNED_INTEGER})) {
32
+ rb_raise(rb_eRangeError, "input was too large for 64-bit signed integer");
33
+ }
34
+ if (rb_funcall(#{var_name}_a[#{iteration_var_name}], '<', 1, #{MIN_SIGNED_INTEGER})) {
35
+ rb_raise(rb_eRangeError, "input was too small for 64-bit signed integer");
36
+ }}
37
+ end
38
+
39
+ def load_ruby_array_from_yeppp_array(var_name, iteration_var_name, len_var_name, type)
40
+ %{/* Load the Ruby Array */
41
+ new_ary = rb_ary_new2(#{len_var_name});
42
+ for (#{iteration_var_name}=0; #{iteration_var_name}<#{len_var_name}; #{iteration_var_name}++) {
43
+ rb_ary_push(new_ary, #{type == 'f' ? 'DBL' : 'LONG'}2NUM((#{type == 'f' ? 'double' : 'long'})yep_#{var_name}[#{iteration_var_name}]));
44
+ }}
45
+ end
46
+ def load_ruby_array_from_yeppp_array_parameterized(var_name, iteration_var_name, len_var_name)
47
+ %{/* Load the Ruby Array */
48
+ new_ary = rb_ary_new2(#{len_var_name});
49
+ for (#{iteration_var_name}=0; #{iteration_var_name}<#{len_var_name}; #{iteration_var_name}++) {
50
+ rb_ary_push(new_ary, {{ruby_type}}2NUM(({{c_type}})yep_#{var_name}[#{iteration_var_name}]));
51
+ }}
52
+ end
53
+ def load_ruby_array_into_yeppp_array(var_name, iteration_var_name, len_var_name, type, permitted_types, opts={})
54
+ pt = permitted_types.map do |t|
55
+ case t
56
+ when :float
57
+ "TYPE(#{var_name}_a[#{iteration_var_name}]) != T_FLOAT"
58
+ when :integer
59
+ "TYPE(#{var_name}_a[#{iteration_var_name}]) != T_FIXNUM && TYPE(#{var_name}_a[#{iteration_var_name}]) != T_BIGNUM"
60
+ else
61
+ raise "Invalid permitted_type: #{t}."
62
+ end
63
+ end.join(' && ')
64
+ %{/* Load #{var_name}_a into yep_#{var_name}. */
65
+ for (#{iteration_var_name}=0; #{iteration_var_name}<#{len_var_name}; #{iteration_var_name}++) {
66
+ if (#{pt}) {
67
+ rb_raise(rb_eTypeError, "input was not all #{permitted_types.map(&:to_s).map(&:pluralize).join(' and ')}");
68
+ }
69
+ #{guard_integer_input_size(var_name, iteration_var_name)}
70
+ yep_#{var_name}[#{opts[:reverse] ? "#{len_var_name} - #{iteration_var_name} - 1" : iteration_var_name}] = (Yep64#{type})NUM2#{type == 'f' ? 'DBL' : 'LONG'}(#{var_name}_a[#{iteration_var_name}]);
71
+ }}
72
+ end
73
+ def load_ruby_array_into_yeppp_array_parameterized(var_name, iteration_var_name, len_var_name)
74
+ %{/* Load #{var_name}_a into yep_#{var_name}. */
75
+ for (#{iteration_var_name}=0; #{iteration_var_name}<#{len_var_name}; #{iteration_var_name}++) {
76
+ if (TYPE(#{var_name}_a[#{iteration_var_name}]) != {{ruby_klass}} && TYPE(#{var_name}_a[#{iteration_var_name}]) != {{alt_ruby_klass}}) {
77
+ rb_raise(rb_eTypeError, "input was not all {{ruby_klass_human}}");
78
+ }
79
+ #{guard_integer_input_size(var_name, iteration_var_name)}
80
+ yep_#{var_name}[#{iteration_var_name}] = (Yep64{{type}})NUM2{{ruby_type}}(#{var_name}_a[#{iteration_var_name}]);
81
+ }}
82
+ end
83
+
84
+ def release_array_memory(var_names)
85
+ var_names = Array(var_names)
86
+ %{/* Release the memory allocated for array#{var_names.size == 1 ? nil : 's'} */
87
+ #{var_names.map{|vn| %{free(yep_#{vn});}}.join("\n")}}
88
+ end
89
+
90
+ def typed_variants(s, opts={})
91
+ [
92
+ ['s', 'long', 'LONG', 'T_FIXNUM', 'T_BIGNUM', 'integers'],
93
+ ['f', 'double', 'DBL', 'T_FLOAT', 'T_FLOAT', 'floats']
94
+ ].map do |(type, c_type, ruby_type, ruby_klass, alt_ruby_klass, ruby_klass_human)|
95
+ if !opts[:only_type] || opts[:only_type] == type
96
+ s.gsub(/{{type}}/, type)
97
+ .gsub(/{{c_type}}/, c_type)
98
+ .gsub(/{{ruby_type}}/, ruby_type)
99
+ .gsub(/{{ruby_klass}}/, ruby_klass)
100
+ .gsub(/{{alt_ruby_klass}}/, alt_ruby_klass)
101
+ .gsub(/{{ruby_klass_human}}/, ruby_klass_human)
102
+ else
103
+ ''
104
+ end
105
+ end.map(&:strip).join("\n\n")
106
+ end
107
+
108
+ HEADERS = %{
109
+ // Include the Ruby headers and goodies
110
+ #include "ruby.h"
111
+
112
+ #include "assert.h"
113
+
114
+ #include "yepCore.h"
115
+ #include "yepLibrary.h"
116
+ #include "yepMath.h"
117
+ }.strip.freeze
118
+
119
+ PRIMARY = %{
120
+ // Defining a space for information and references about the module to be stored
121
+ // internally
122
+ VALUE cRyeppp;
123
+ }.strip.freeze
124
+
125
+ # verb_name is in [Add, Subtract, Multiply]
126
+ FUNCS = Proc.new do |verb_name|
127
+ %{#{if verb_name == 'Multiply'
128
+ typed_variants(%{
129
+ static VALUE multiply_v64{{type}}s64{{type}}_v64{{type}}(VALUE self, VALUE x, VALUE multiply_by) {
130
+ enum YepStatus status;
131
+ long i;
132
+ VALUE new_ary;
133
+ VALUE *x_a = RARRAY_PTR(x);
134
+ long l = RARRAY_LEN(x);
135
+ Yep64{{type}} mult_by = (Yep64{{type}})NUM2DBL(multiply_by);
136
+
137
+ /* Allocate arrays of inputs and outputs */
138
+ #{allocate_yep64_typed_array_and_assert(%w{x y}, 'l')}
139
+
140
+ #{initialize_yeppp}
141
+
142
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
143
+
144
+ /* Perform the operation */
145
+ status = yepCore_Multiply_V64{{type}}S64{{type}}_V64{{type}}(yep_x, mult_by, yep_y, (YepSize)l);
146
+ assert(status == YepStatusOk);
147
+
148
+ #{load_ruby_array_from_yeppp_array_parameterized('y', 'i', 'l')}
149
+
150
+ #{deinitialize_yeppp}
151
+
152
+ #{release_array_memory(%w{x y})}
153
+
154
+ return new_ary;
155
+ }
156
+ }).strip.freeze
157
+ end
158
+ }
159
+
160
+ #{typed_variants(%{
161
+ // #{verb_name} Arrays of Fixnums.
162
+ static VALUE #{verb_name.downcase}_v64{{type}}v64{{type}}_v64{{type}}(VALUE self, VALUE x, VALUE y) {
163
+ enum YepStatus status;
164
+ VALUE new_ary;
165
+ long i;
166
+ VALUE *x_a = RARRAY_PTR(x);
167
+ VALUE *y_a = RARRAY_PTR(y);
168
+ long l = RARRAY_LEN(x);
169
+
170
+ /* Allocate arrays of inputs and outputs */
171
+ #{allocate_yep64_typed_array_and_assert(%w{x y z}, 'l')}
172
+
173
+ #{initialize_yeppp}
174
+
175
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
176
+ #{load_ruby_array_into_yeppp_array_parameterized('y', 'i', 'l')}
177
+
178
+ /* Perform the addition */
179
+ status = yepCore_#{verb_name}_V64{{type}}V64{{type}}_V64{{type}}(yep_x, yep_y, yep_z, (YepSize)l);
180
+ assert(status == YepStatusOk);
181
+
182
+ #{load_ruby_array_from_yeppp_array_parameterized('z', 'i', 'l')}
183
+
184
+ #{deinitialize_yeppp}
185
+
186
+ #{release_array_memory(%w{x y z})}
187
+
188
+ return new_ary;
189
+ }
190
+ })}
191
+ }
192
+ end
193
+
194
+ DOT_PRODUCT = %{
195
+ // Get the dot product of 2 Arrays.
196
+ static VALUE dotproduct_v64fv64f_s64f(VALUE self, VALUE x, VALUE y) {
197
+ enum YepStatus status;
198
+ long i;
199
+ Yep64f dp;
200
+ VALUE *x_a = RARRAY_PTR(x);
201
+ VALUE *y_a = RARRAY_PTR(y);
202
+ long l = RARRAY_LEN(x);
203
+
204
+ /* Allocate arrays of inputs and outputs */
205
+ #{allocate_yep64_typed_array_and_assert(%w{x y}, 'l', :type => 'f')}
206
+
207
+ #{initialize_yeppp}
208
+
209
+ #{load_ruby_array_into_yeppp_array('x', 'i', 'l', 'f', [:integer, :float])}
210
+ #{load_ruby_array_into_yeppp_array('y', 'i', 'l', 'f', [:integer, :float])}
211
+
212
+ /* Perform the operation */
213
+ status = yepCore_DotProduct_V64fV64f_S64f(yep_x, yep_y, &dp, (YepSize)l);
214
+ assert(status == YepStatusOk);
215
+
216
+ #{deinitialize_yeppp}
217
+
218
+ #{release_array_memory(%w{x y})}
219
+
220
+ return DBL2NUM((double)dp);
221
+ }
222
+ }.strip
223
+
224
+ MIN_MAX = typed_variants(%w{Min Max}.map do |kind|
225
+ %{
226
+ // Get the #{kind.downcase} value from an Array.
227
+ static VALUE #{kind.downcase}_v64{{type}}_s64{{type}}(VALUE self, VALUE x) {
228
+ enum YepStatus status;
229
+ long i;
230
+ Yep64{{type}} #{kind.downcase};
231
+ VALUE *x_a = RARRAY_PTR(x);
232
+ long l = RARRAY_LEN(x);
233
+
234
+ /* Allocate arrays of inputs and outputs */
235
+ #{allocate_yep64_typed_array_and_assert('x', 'l')}
236
+
237
+ #{initialize_yeppp}
238
+
239
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
240
+
241
+ /* Perform the operation */
242
+ status = yepCore_#{kind}_V64{{type}}_S64{{type}}(yep_x, &#{kind.downcase}, (YepSize)l);
243
+ assert(status == YepStatusOk);
244
+
245
+ #{deinitialize_yeppp}
246
+
247
+ #{release_array_memory(%w{x})}
248
+
249
+ return {{ruby_type}}2NUM(({{c_type}})#{kind.downcase});
250
+ }
251
+ }.strip
252
+ end.join("\n\n"))
253
+
254
+ PAIRWISE_MIN_MAX = typed_variants(%w{Min Max}.map do |kind|
255
+ %{
256
+ // Get the pairwise #{kind.downcase}ima from Arrays.
257
+ static VALUE #{kind.downcase}_v64{{type}}v64{{type}}_v64{{type}}(VALUE self, VALUE x, VALUE y) {
258
+ enum YepStatus status;
259
+ long i;
260
+ VALUE new_ary;
261
+ VALUE *x_a = RARRAY_PTR(x);
262
+ VALUE *y_a = RARRAY_PTR(y);
263
+ long l = RARRAY_LEN(x);
264
+
265
+ /* Allocate arrays of inputs and outputs */
266
+ #{allocate_yep64_typed_array_and_assert(%w{x y z}, 'l')}
267
+
268
+ #{initialize_yeppp}
269
+
270
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
271
+ #{load_ruby_array_into_yeppp_array_parameterized('y', 'i', 'l')}
272
+
273
+ /* Perform the operation */
274
+ status = yepCore_#{kind}_V64{{type}}V64{{type}}_V64{{type}}(yep_x, yep_y, yep_z, (YepSize)l);
275
+ assert(status == YepStatusOk);
276
+
277
+ #{load_ruby_array_from_yeppp_array_parameterized('z', 'i', 'l')}
278
+
279
+ #{deinitialize_yeppp}
280
+
281
+ #{release_array_memory(%w{x y z})}
282
+
283
+ return new_ary;
284
+ }
285
+ }.strip
286
+ end.join("\n\n"), :only_type => 'f')
287
+
288
+ CONSTANT_MIN_MAX = typed_variants(%w{Min Max}.map do |kind|
289
+ %{
290
+ // Get the #{kind.downcase}ima from an Array and a constant.
291
+ static VALUE #{kind.downcase}_v64{{type}}s64{{type}}_v64{{type}}(VALUE self, VALUE x, VALUE c) {
292
+ enum YepStatus status;
293
+ long i;
294
+ VALUE new_ary;
295
+ VALUE *x_a = RARRAY_PTR(x);
296
+ long l = RARRAY_LEN(x);
297
+ Yep64f konst = (Yep64f)NUM2{{ruby_type}}(c);
298
+
299
+ /* Allocate arrays of inputs and outputs */
300
+ #{allocate_yep64_typed_array_and_assert(%w{x y}, 'l')}
301
+
302
+ #{initialize_yeppp}
303
+
304
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
305
+
306
+ /* Perform the operation */
307
+ status = yepCore_#{kind}_V64{{type}}S64{{type}}_V64{{type}}(yep_x, konst, yep_y, (YepSize)l);
308
+ assert(status == YepStatusOk);
309
+
310
+ #{load_ruby_array_from_yeppp_array_parameterized('y', 'i', 'l')}
311
+
312
+ #{deinitialize_yeppp}
313
+
314
+ #{release_array_memory(%w{x y})}
315
+
316
+ return new_ary;
317
+ }
318
+ }.strip
319
+ end.join("\n\n"), :only_type => 'f')
320
+
321
+ NEGATE = typed_variants(%{
322
+ // Negate an Array.
323
+ static VALUE negate_v64{{type}}_s64{{type}}(VALUE self, VALUE x) {
324
+ enum YepStatus status;
325
+ long i;
326
+ VALUE new_ary;
327
+ VALUE *x_a = RARRAY_PTR(x);
328
+ long l = RARRAY_LEN(x);
329
+
330
+ /* Allocate arrays of inputs and outputs */
331
+ #{allocate_yep64_typed_array_and_assert(%w{x y}, 'l')}
332
+
333
+ #{initialize_yeppp}
334
+
335
+ #{load_ruby_array_into_yeppp_array_parameterized('x', 'i', 'l')}
336
+
337
+ /* Perform the negation */
338
+ status = yepCore_Negate_V64{{type}}_V64{{type}}(yep_x, yep_y, (YepSize)l);
339
+ assert(status == YepStatusOk);
340
+
341
+ #{load_ruby_array_from_yeppp_array_parameterized('y', 'i', 'l')}
342
+
343
+ #{deinitialize_yeppp}
344
+
345
+ #{release_array_memory(%w{x y})}
346
+
347
+ return new_ary;
348
+ }
349
+ }).freeze
350
+
351
+ SUMS = %w{Sum SumAbs SumSquares}.map do |kind|
352
+ %{
353
+ static VALUE #{kind.downcase}_v64f_s64f(VALUE self, VALUE x) {
354
+ enum YepStatus status;
355
+ long i;
356
+ Yep64f sum;
357
+ long l = RARRAY_LEN(x);
358
+ VALUE *x_a = RARRAY_PTR(x);
359
+
360
+ /* Allocate arrays of inputs and outputs */
361
+ #{allocate_yep64_typed_array_and_assert('x', 'l', :type => 'f')}
362
+
363
+ #{initialize_yeppp}
364
+
365
+ #{load_ruby_array_into_yeppp_array('x', 'i', 'l', 'f', [:integer, :float])}
366
+
367
+ /* Perform the operation */
368
+ status = yepCore_#{kind}_V64f_S64f(yep_x, &sum, (YepSize)l);
369
+ assert(status == YepStatusOk);
370
+
371
+ #{deinitialize_yeppp}
372
+
373
+ #{release_array_memory(%w{x})}
374
+
375
+ return DBL2NUM((double)sum);
376
+ }
377
+ }.strip
378
+ end.join("\n\n").freeze
379
+
380
+ MATHS_KINDS = %w{Log Exp Sin Cos Tan}.freeze
381
+ MATHS = MATHS_KINDS.map do |kind|
382
+ %{
383
+ static VALUE #{kind.downcase}_v64f_v64f(VALUE self, VALUE x) {
384
+ enum YepStatus status;
385
+ long i;
386
+ VALUE new_ary;
387
+ long l = RARRAY_LEN(x);
388
+ VALUE *x_a = RARRAY_PTR(x);
389
+
390
+ /* Allocate arrays of inputs and outputs */
391
+ #{allocate_yep64_typed_array_and_assert(%w{x y}, 'l', :type => 'f')}
392
+
393
+ #{initialize_yeppp}
394
+
395
+ #{load_ruby_array_into_yeppp_array('x', 'i', 'l', 'f', [:integer, :float])}
396
+
397
+ /* Perform the operation */
398
+ status = yepMath_#{kind}_V64f_V64f(yep_x, yep_y, (YepSize)l);
399
+ assert(status == YepStatusOk);
400
+
401
+ #{load_ruby_array_from_yeppp_array('y', 'i', 'l', 'f')}
402
+
403
+ #{deinitialize_yeppp}
404
+
405
+ #{release_array_memory(%w{x y})}
406
+
407
+ return new_ary;
408
+ }
409
+ }.strip
410
+ end.join("\n\n").freeze
411
+
412
+ POLYNOMIAL = %{
413
+ // x is the coefficients in standard form
414
+ // where is the set of points at which to evaluate x
415
+ static VALUE evaluatepolynomial_v64fv64f_v64f(VALUE self, VALUE x, VALUE where) {
416
+ enum YepStatus status;
417
+ long i;
418
+ VALUE new_ary;
419
+ long x_l = RARRAY_LEN(x);
420
+ long y_l = RARRAY_LEN(where);
421
+ VALUE *x_a = RARRAY_PTR(x);
422
+ VALUE *y_a = RARRAY_PTR(where);
423
+
424
+ /* Allocate arrays of inputs and outputs */
425
+ #{allocate_yep64_typed_array_and_assert(%w{x}, 'x_l', :assert => false, :type => 'f')}
426
+ #{allocate_yep64_typed_array_and_assert(%w{y z}, 'y_l', :assert => false, :type => 'f')}
427
+ assert(yep_x != NULL);
428
+ assert(yep_y != NULL);
429
+ assert(yep_z != NULL);
430
+
431
+ #{initialize_yeppp}
432
+
433
+ // Yeppp! polynomial evaluation works in reverse standard form, so we have
434
+ // to load yep_x in reverse.
435
+ #{load_ruby_array_into_yeppp_array('x', 'i', 'x_l', 'f', [:integer, :float], :reverse => true)}
436
+ #{load_ruby_array_into_yeppp_array('y', 'i', 'y_l', 'f', [:integer, :float])}
437
+
438
+ /* Perform the operation */
439
+ status = yepMath_EvaluatePolynomial_V64fV64f_V64f(yep_x, yep_y, yep_z, (YepSize)x_l, (YepSize)y_l);
440
+ assert(status == YepStatusOk);
441
+
442
+ #{load_ruby_array_from_yeppp_array('z', 'i', 'y_l', 'f')}
443
+
444
+ #{deinitialize_yeppp}
445
+
446
+ #{release_array_memory(%w{x y z})}
447
+
448
+ return new_ary;
449
+ }
450
+ }.strip.freeze
451
+
452
+ INITIALIZER = %{
453
+ // The initialization method for this module
454
+ void Init_ryeppp() {
455
+ cRyeppp = rb_define_class("Ryeppp", rb_cObject);
456
+
457
+ /* Addition */
458
+ rb_define_singleton_method(cRyeppp, "add_v64fv64f_v64f", add_v64fv64f_v64f, 2);
459
+ rb_define_singleton_method(cRyeppp, "add_v64sv64s_v64s", add_v64sv64s_v64s, 2);
460
+
461
+ /* Subtraction */
462
+ rb_define_singleton_method(cRyeppp, "subtract_v64fv64f_v64f", subtract_v64fv64f_v64f, 2);
463
+ rb_define_singleton_method(cRyeppp, "subtract_v64sv64s_v64s", subtract_v64sv64s_v64s, 2);
464
+
465
+ /* Multiplication */
466
+ rb_define_singleton_method(cRyeppp, "multiply_v64fs64f_v64f", multiply_v64fs64f_v64f, 2);
467
+ rb_define_singleton_method(cRyeppp, "multiply_v64sv64s_v64s", multiply_v64sv64s_v64s, 2);
468
+ rb_define_singleton_method(cRyeppp, "multiply_v64fv64f_v64f", multiply_v64fv64f_v64f, 2);
469
+ rb_define_singleton_method(cRyeppp, "multiply_v64ss64s_v64s", multiply_v64ss64s_v64s, 2);
470
+
471
+ /* Dot Product */
472
+ rb_define_singleton_method(cRyeppp, "dotproduct_v64fv64f_s64f", dotproduct_v64fv64f_s64f, 2);
473
+
474
+ /* Minimum */
475
+ rb_define_singleton_method(cRyeppp, "min_v64f_s64f", min_v64f_s64f, 1);
476
+ rb_define_singleton_method(cRyeppp, "min_v64s_s64s", min_v64s_s64s, 1);
477
+
478
+ /* Maximum */
479
+ rb_define_singleton_method(cRyeppp, "max_v64f_s64f", max_v64f_s64f, 1);
480
+ rb_define_singleton_method(cRyeppp, "max_v64s_s64s", max_v64s_s64s, 1);
481
+
482
+ /* Pairwise Minima */
483
+ rb_define_singleton_method(cRyeppp, "min_v64fv64f_v64f", min_v64fv64f_v64f, 2);
484
+ // Pairwise signed min is not available.
485
+
486
+ /* Pairwise Maxima */
487
+ rb_define_singleton_method(cRyeppp, "max_v64fv64f_v64f", max_v64fv64f_v64f, 2);
488
+ // Pairwise signed max is not available.
489
+
490
+ /* Constant Minima */
491
+ rb_define_singleton_method(cRyeppp, "min_v64fs64f_v64f", min_v64fs64f_v64f, 2);
492
+ // Constant signed min is not available.
493
+
494
+ /* Constant Maxima */
495
+ rb_define_singleton_method(cRyeppp, "max_v64fs64f_v64f", max_v64fs64f_v64f, 2);
496
+ // Constant signed max is not available.
497
+
498
+ /* Negation */
499
+ rb_define_singleton_method(cRyeppp, "negate_v64f_s64f", negate_v64f_s64f, 1);
500
+ rb_define_singleton_method(cRyeppp, "negate_v64s_s64s", negate_v64s_s64s, 1);
501
+
502
+ /* Sums */
503
+ rb_define_singleton_method(cRyeppp, "sum_v64f_s64f", sum_v64f_s64f, 1);
504
+ // Signed sum is not available.
505
+ rb_define_singleton_method(cRyeppp, "sumabs_v64f_s64f", sumabs_v64f_s64f, 1);
506
+ // Signed abs sum is not available.
507
+ rb_define_singleton_method(cRyeppp, "sumsquares_v64f_s64f", sumsquares_v64f_s64f, 1);
508
+ // Signed squares sum is not available.
509
+
510
+ /* Maths */
511
+ #{MATHS_KINDS.map do |kind|
512
+ %{rb_define_singleton_method(cRyeppp, "#{kind.downcase}_v64f_v64f", #{kind.downcase}_v64f_v64f, 1);}
513
+ end.join("\n")}
514
+
515
+ /* Polynomial */
516
+ rb_define_singleton_method(cRyeppp, "evaluatepolynomial_v64fv64f_v64f", evaluatepolynomial_v64fv64f_v64f, 2);
517
+ }
518
+ }.strip.freeze
data/lib/ryeppp.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "ryeppp/version"
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'ryeppp.so')
3
+
4
+ #module Carray
5
+ # # Your code goes here...
6
+ #end
@@ -0,0 +1,233 @@
1
+ require 'benchmark'
2
+ require 'inline'
3
+
4
+ $:<< './lib'
5
+ require 'ryeppp'
6
+
7
+ VERBOSE = %w{1 t true y yes}.include?(ENV['VERBOSE'])
8
+
9
+ def puts_with_pounds(s)
10
+ puts "\n\n#{s} #{'#' * (79 - s.size)}"
11
+ end
12
+
13
+ class Array
14
+ def sum
15
+ self.inject(0){|sum, o| sum + o}
16
+ end
17
+ def sumabs
18
+ self.inject(0){|sum, o| sum + o.abs}
19
+ end
20
+ def sumsquares
21
+ self.inject(0){|sum, o| sum + o**2}
22
+ end
23
+ inline do |builder|
24
+ builder.c %{
25
+ static VALUE c_sum() {
26
+ long n = RARRAY_LEN(self);
27
+ double sum = 0.0;
28
+
29
+ VALUE *x_a = RARRAY_PTR(self);
30
+
31
+ long i;
32
+ for (i=0; i<n; i++) {
33
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
34
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
35
+ }
36
+ sum += NUM2DBL(x_a[i]);
37
+ }
38
+ return DBL2NUM(sum);
39
+ }
40
+ }
41
+ end
42
+ inline do |builder|
43
+ builder.c %{
44
+ static VALUE c_sumabs() {
45
+ long n = RARRAY_LEN(self);
46
+ double sum = 0.0;
47
+
48
+ VALUE *x_a = RARRAY_PTR(self);
49
+
50
+ long i;
51
+ for (i=0; i<n; i++) {
52
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
53
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
54
+ }
55
+ sum += (NUM2DBL(x_a[i]) < 0) ? (-1.0 * NUM2DBL(x_a[i])) : NUM2DBL(x_a[i]);
56
+ }
57
+ return DBL2NUM(sum);
58
+ }
59
+ }
60
+ end
61
+ inline do |builder|
62
+ builder.c %{
63
+ static VALUE c_sumsquares() {
64
+ long n = RARRAY_LEN(self);
65
+ double sum = 0.0;
66
+
67
+ VALUE *x_a = RARRAY_PTR(self);
68
+
69
+ long i;
70
+ for (i=0; i<n; i++) {
71
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
72
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
73
+ }
74
+ sum += NUM2DBL(x_a[i]) * NUM2DBL(x_a[i]);
75
+ }
76
+ return DBL2NUM(sum);
77
+ }
78
+ }
79
+ end
80
+
81
+ def dot_product_f(v2)
82
+ self.each.with_index.inject(0) do |sum, (o, idx)|
83
+ sum + o.to_f * v2[idx]
84
+ end
85
+ end
86
+ inline do |builder|
87
+ builder.c %{
88
+ static VALUE c_dot_product_f(VALUE v2) {
89
+ long n = RARRAY_LEN(self);
90
+ double sum = 0.0;
91
+
92
+ VALUE *x_a = RARRAY_PTR(self);
93
+ VALUE *y_a = RARRAY_PTR(v2);
94
+
95
+ long i;
96
+ for (i=0; i<n; i++) {
97
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
98
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
99
+ }
100
+ if (TYPE(y_a[i]) != T_FIXNUM && TYPE(y_a[i]) != T_BIGNUM && TYPE(y_a[i]) != T_FLOAT) {
101
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
102
+ }
103
+ sum += NUM2DBL(x_a[i]) * NUM2DBL(y_a[i]);
104
+ }
105
+ return DBL2NUM(sum);
106
+ }
107
+ }
108
+ end
109
+
110
+ def evaluate_polynomial(x)
111
+ if self.size == 1
112
+ self.first
113
+ else
114
+ self.last + x * self[0..-2].evaluate_polynomial(x)
115
+ end
116
+ end
117
+ def evaluate_polynomial_iter(x)
118
+ self.map.with_index do |o, i|
119
+ self[i] * x ** (self.size - 1 - i)
120
+ end.sum
121
+ end
122
+ inline do |builder|
123
+ builder.prefix %{
124
+ static inline double heron_evaluate(VALUE *x_a, long i, double x) {
125
+ if (i == 0) {
126
+ return NUM2DBL(x_a[i]);
127
+ } else {
128
+ return NUM2DBL(x_a[i]) + x * heron_evaluate(x_a, i - 1, x);
129
+ }
130
+ }
131
+ }
132
+ builder.c %{
133
+ static VALUE c_evaluate_polynomial(VALUE x_v) {
134
+ long n = RARRAY_LEN(self);
135
+
136
+ VALUE *x_a = RARRAY_PTR(self);
137
+ double x = NUM2DBL(x_v);
138
+
139
+ long i;
140
+ for (i=0; i<n; i++) {
141
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
142
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
143
+ }
144
+ }
145
+ return DBL2NUM(heron_evaluate(x_a, n - 1, x));
146
+ }
147
+ }
148
+ end
149
+ inline do |builder|
150
+ builder.include('<math.h>')
151
+ builder.c %{
152
+ static VALUE c_evaluate_polynomial_iter(VALUE x_v) {
153
+ long n = RARRAY_LEN(self);
154
+
155
+ VALUE *x_a = RARRAY_PTR(self);
156
+ double x = NUM2DBL(x_v);
157
+ double res = 0;
158
+
159
+ long i;
160
+ for (i=0; i<n; i++) {
161
+ if (TYPE(x_a[i]) != T_FIXNUM && TYPE(x_a[i]) != T_BIGNUM && TYPE(x_a[i]) != T_FLOAT) {
162
+ rb_raise(rb_eTypeError, "input was not all integers and floats");
163
+ }
164
+ res += NUM2DBL(x_a[i]) * pow(x, (n - 1 - i));
165
+ }
166
+ return DBL2NUM(res);
167
+ }
168
+ }
169
+ end
170
+ end
171
+
172
+ WIDTH = 40
173
+ V_f = (0..1_024*1_024).to_a.map{Random.rand}
174
+
175
+ # Dot Product
176
+ puts_with_pounds "Dot Product"
177
+ n = 1
178
+ if VERBOSE
179
+ puts "dot_product_f: #{V_f.dot_product_f(V_f)}"
180
+ puts "c_dot_product_f: #{V_f.c_dot_product_f(V_f)}"
181
+ puts "Ryeppp.dotproduct_v64fv64f_s64f: #{Ryeppp.dotproduct_v64fv64f_s64f(V_f, V_f)}"
182
+ end
183
+ Benchmark.bm(WIDTH) do |x|
184
+ x.report("dot_product_f:") { n.times { V_f.dot_product_f(V_f) } }
185
+ x.report("c_dot_product_f:") { n.times { V_f.c_dot_product_f(V_f) } }
186
+ x.report("Ryeppp.dotproduct_v64fv64f_s64f:") { n.times { Ryeppp.dotproduct_v64fv64f_s64f(V_f, V_f) } }
187
+ end
188
+
189
+ # Sums
190
+ puts_with_pounds "Sums"
191
+ n = 1
192
+ Benchmark.bm(WIDTH) do |x|
193
+ ['', 'abs', 'squares'].each do |suffix|
194
+ x.report("sum#{suffix}:") { n.times { V_f.send("sum#{suffix}") } }
195
+ x.report("c_sum#{suffix}:") { n.times { V_f.send("c_sum#{suffix}") } }
196
+ x.report("Ryeppp.sum#{suffix}_v64f_s64f:") { n.times { Ryeppp.send("sum#{suffix}_v64f_s64f", V_f) } }
197
+ end
198
+ end
199
+
200
+ # Math Functions
201
+ puts_with_pounds "Math Functions"
202
+ n = 1
203
+ Benchmark.bm(WIDTH) do |x|
204
+ %w{log exp sin cos tan}.each do |f|
205
+ x.report("#{f}:") { n.times { V_f.each{|o| Math.send(f, o)} } }
206
+ x.report("Ryeppp.#{f}_v64f_v64f:") { n.times { Ryeppp.send("#{f}_v64f_v64f", V_f) } }
207
+ end
208
+ end
209
+
210
+ # Polynomial
211
+ puts_with_pounds "Polynomial"
212
+ n = 1
213
+ P_SMALL = (0..1_024).to_a.map{Random.rand}
214
+ P_LARGE = (0..1_024*1_024).to_a.map{Random.rand}
215
+ X = Random.rand
216
+ if VERBOSE
217
+ puts "evaluate_polynomial: #{P_SMALL.evaluate_polynomial(X)}"
218
+ puts "evaluate_polynomial_iter: #{P_SMALL.evaluate_polynomial_iter(X)}"
219
+ puts "c_evaluate_polynomial: #{P_SMALL.c_evaluate_polynomial(X)}"
220
+ puts "c_evaluate_polynomial_iter: #{P_SMALL.c_evaluate_polynomial_iter(X)}"
221
+ puts "Ryeppp.evaluatepolynomial_v64fv64f_v64f: #{Ryeppp.evaluatepolynomial_v64fv64f_v64f(P_SMALL, [X])}"
222
+ puts "evaluate_polynomial_iter: #{P_LARGE.evaluate_polynomial_iter(X)}"
223
+ puts "c_evaluate_polynomial_iter: #{P_LARGE.c_evaluate_polynomial_iter(X)}"
224
+ puts "Ryeppp.evaluatepolynomial_v64fv64f_v64f: #{Ryeppp.evaluatepolynomial_v64fv64f_v64f(P_LARGE, [X])}"
225
+ end
226
+ Benchmark.bm(WIDTH) do |x|
227
+ x.report("evaluate_polynomial:") { n.times { P_SMALL.evaluate_polynomial(X) } }
228
+ x.report("c_evaluate_polynomial:") { n.times { P_SMALL.c_evaluate_polynomial(X) } }
229
+ x.report("Ryeppp.evaluatepolynomial_v64fv64f_v64f:") { n.times { Ryeppp.evaluatepolynomial_v64fv64f_v64f(P_SMALL, [X]) } }
230
+ x.report("evaluate_polynomial_iter:") { n.times { P_LARGE.evaluate_polynomial_iter(X) } }
231
+ x.report("c_evaluate_polynomial_iter:") { n.times { P_LARGE.c_evaluate_polynomial_iter(X) } }
232
+ x.report("Ryeppp.evaluatepolynomial_v64fv64f_v64f:") { n.times { Ryeppp.evaluatepolynomial_v64fv64f_v64f(P_LARGE, [X]) } }
233
+ end
@@ -0,0 +1,3 @@
1
+ class Ryeppp
2
+ VERSION = "0.0.3"
3
+ end
data/ryeppp.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ryeppp/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ryeppp"
8
+ spec.version = Ryeppp::VERSION
9
+ spec.authors = ["Brad Cater"]
10
+ spec.email = ["bradcater@gmail.com"]
11
+ spec.description = %q{This gem provides bindings to the Yeppp! library. According to the documentation, "Yeppp! is a high-performance SIMD-optimized mathematical library for x86, ARM, and MIPS processors on Windows, Android, Mac OS X, and GNU/Linux systems."}
12
+ spec.summary = %q{This gem provides bindings to the Yeppp! library.}
13
+ spec.homepage = "https://github.com/bradcater/ruby-yeppp"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.extensions << "ext/ryeppp/extconf.rb"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake-compiler"
25
+ spec.add_development_dependency "rake", ">= 1.9.1"
26
+ spec.add_development_dependency "rspec", ">= 2.13.0"
27
+ spec.add_development_dependency "rspec", ">= 2.13.0"
28
+ spec.add_development_dependency "RubyInline", "~> 3.12.2"
29
+ end
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ryeppp do
4
+ # Addition
5
+ it 'should add vectors of Fixnums' do
6
+ Ryeppp.add_v64sv64s_v64s([1], [2]).should eq([3])
7
+ expect{Ryeppp.add_v64sv64s_v64s([1, 'a'], [2, 'b'])}.to raise_error(TypeError)
8
+ expect{Ryeppp.add_v64sv64s_v64s([2**63], [1])}.to raise_error(RangeError)
9
+ expect{Ryeppp.add_v64sv64s_v64s([-2**63], [1])}.to raise_error(RangeError)
10
+ end
11
+ it 'should add vectors of Floats' do
12
+ Ryeppp.add_v64fv64f_v64f([1.1], [1.1]).should eq([2.2])
13
+ expect{Ryeppp.add_v64fv64f_v64f([1.1, 'a'], [2.2, 'b'])}.to raise_error(TypeError)
14
+ end
15
+
16
+ # Subtraction
17
+ it 'should subtract vectors of Fixnums' do
18
+ Ryeppp.subtract_v64sv64s_v64s([1], [2]).should eq([-1])
19
+ expect{Ryeppp.subtract_v64sv64s_v64s([1, 'a'], [2, 'b'])}.to raise_error(TypeError)
20
+ expect{Ryeppp.subtract_v64sv64s_v64s([2**63], [2])}.to raise_error(RangeError)
21
+ expect{Ryeppp.subtract_v64sv64s_v64s([-2**63], [2])}.to raise_error(RangeError)
22
+ end
23
+ it 'should subtract vectors of Floats' do
24
+ Ryeppp.subtract_v64fv64f_v64f([1.1], [1.1]).should eq([0])
25
+ expect{Ryeppp.subtract_v64fv64f_v64f([1.1, 'a'], [2.2, 'b'])}.to raise_error(TypeError)
26
+ end
27
+
28
+ # Multiplication
29
+ it 'should multiply a vector of Fixnums by a constant' do
30
+ Ryeppp.multiply_v64ss64s_v64s([1, 2, 3], 2).should eq([2, 4, 6])
31
+ expect{Ryeppp.multiply_v64ss64s_v64s([1, 'a'], 2)}.to raise_error(TypeError)
32
+ expect{Ryeppp.multiply_v64ss64s_v64s([2**63], 2)}.to raise_error(RangeError)
33
+ expect{Ryeppp.multiply_v64ss64s_v64s([-2**63], 2)}.to raise_error(RangeError)
34
+ end
35
+ it 'should multiply a vector of Floats by a constant' do
36
+ Ryeppp.multiply_v64fs64f_v64f([1.0, 2.0, 3.0], 2.0).should eq([2.0, 4.0, 6.0])
37
+ expect{Ryeppp.multiply_v64fs64f_v64f([1, 'a'], 2)}.to raise_error(TypeError)
38
+ end
39
+ it 'should multiply vectors of Fixnums' do
40
+ Ryeppp.multiply_v64sv64s_v64s([2], [3]).should eq([6])
41
+ expect{Ryeppp.multiply_v64sv64s_v64s([1, 'a'], [2, 'b'])}.to raise_error(TypeError)
42
+ expect{Ryeppp.multiply_v64sv64s_v64s([2**63], [2])}.to raise_error(RangeError)
43
+ expect{Ryeppp.multiply_v64sv64s_v64s([-2**63], [2])}.to raise_error(RangeError)
44
+ end
45
+ it 'should multiply vectors of Floats' do
46
+ Ryeppp.multiply_v64fv64f_v64f([2.5], [3.5]).should eq([8.75])
47
+ expect{Ryeppp.multiply_v64fv64f_v64f([1.1, 'a'], [2.2, 'b'])}.to raise_error(TypeError)
48
+ end
49
+
50
+ # Dot Product
51
+ it 'should do the dot product of vectors of Floats' do
52
+ Ryeppp.dotproduct_v64fv64f_s64f([1, 2, 3], [4, 5, 6]).should eq(32.0)
53
+ expect{Ryeppp.dotproduct_v64fv64f_s64f([1, 2, 'a'], [4, 5, 'b'])}.to raise_error(TypeError)
54
+ end
55
+
56
+ # Minimum
57
+ it 'should find the minimum in a vector of Fixnums' do
58
+ Ryeppp.min_v64s_s64s([3, 2, 1]).should eq(1)
59
+ expect{Ryeppp.min_v64s_s64s([1, 'a'])}.to raise_error(TypeError)
60
+ expect{Ryeppp.min_v64s_s64s([2**63])}.to raise_error(RangeError)
61
+ expect{Ryeppp.min_v64s_s64s([-2**63])}.to raise_error(RangeError)
62
+ end
63
+ it 'should find the minimum in a vector of Floats' do
64
+ Ryeppp.min_v64f_s64f([1.0, 2.0, 3.0]).should eq(1.0)
65
+ expect{Ryeppp.min_v64f_s64f([1.0, 'a'])}.to raise_error(TypeError)
66
+ end
67
+
68
+ # Maximum
69
+ it 'should find the maximum in a vector of Fixnums' do
70
+ Ryeppp.max_v64s_s64s([3, 2, 1]).should eq(3)
71
+ expect{Ryeppp.max_v64s_s64s([1, 'a'])}.to raise_error(TypeError)
72
+ expect{Ryeppp.max_v64s_s64s([2**63])}.to raise_error(RangeError)
73
+ expect{Ryeppp.max_v64s_s64s([-2**63])}.to raise_error(RangeError)
74
+ end
75
+ it 'should find the maximum in a vector of Floats' do
76
+ Ryeppp.max_v64f_s64f([1.0, 2.0, 3.0]).should eq(3.0)
77
+ expect{Ryeppp.max_v64f_s64f([1.0, 'a'])}.to raise_error(TypeError)
78
+ end
79
+
80
+ # Pairwise Minima
81
+ it 'should find the pairwise minima in vectors of Floats' do
82
+ Ryeppp.min_v64fv64f_v64f([1.0, 2.0, 3.0], [3.0, 2.0, 1.0]).should eq([1.0, 2.0, 1.0])
83
+ expect{Ryeppp.min_v64fv64f_v64f([1.0, 'a'], [2.0, 'b'])}.to raise_error(TypeError)
84
+ end
85
+ # Pairwise Maxima
86
+ it 'should find the pairwise maxima in vectors of Floats' do
87
+ Ryeppp.max_v64fv64f_v64f([1.0, 2.0, 3.0], [3.0, 2.0, 1.0]).should eq([3.0, 2.0, 3.0])
88
+ expect{Ryeppp.max_v64fv64f_v64f([1.0, 'a'], [2.0, 'b'])}.to raise_error(TypeError)
89
+ end
90
+
91
+ # Constant Minima
92
+ it 'should find the minima in a vector of Floats and a constant' do
93
+ Ryeppp.min_v64fs64f_v64f([1.0, 2.0, 3.0], 2.0).should eq([1.0, 2.0, 2.0])
94
+ expect{Ryeppp.min_v64fs64f_v64f([1.0, 'a'], 2.0)}.to raise_error(TypeError)
95
+ end
96
+ # Constant Maxima
97
+ it 'should find the maxima in a vector of Floats and a constant' do
98
+ Ryeppp.max_v64fs64f_v64f([1.0, 2.0, 3.0], 2.5).should eq([2.5, 2.5, 3.0])
99
+ expect{Ryeppp.max_v64fs64f_v64f([1.0, 'a'], 2.5)}.to raise_error(TypeError)
100
+ end
101
+
102
+ # Negation
103
+ it 'should negate vectors of Fixnums' do
104
+ Ryeppp.negate_v64s_s64s([1]).should eq([-1])
105
+ expect{Ryeppp.negate_v64s_s64s([1, 'a'])}.to raise_error(TypeError)
106
+ expect{Ryeppp.negate_v64s_s64s([2**63])}.to raise_error(RangeError)
107
+ expect{Ryeppp.negate_v64s_s64s([-2**63])}.to raise_error(RangeError)
108
+ end
109
+ it 'should negate vectors of Floats' do
110
+ Ryeppp.negate_v64f_s64f([1.1]).should eq([-1.1])
111
+ expect{Ryeppp.negate_v64f_s64f([1.1, 'a'])}.to raise_error(TypeError)
112
+ end
113
+
114
+ # Sum
115
+ it 'should sum a vector of Floats' do
116
+ Ryeppp.sum_v64f_s64f([1, 2, 3]).should eq(6.0)
117
+ expect{Ryeppp.sum_v64f_s64f([1, 'a'])}.to raise_error(TypeError)
118
+ end
119
+ # Sum Absolute Values
120
+ it 'should sum absolute values of a vector of Floats' do
121
+ Ryeppp.sumabs_v64f_s64f([1.0, -1.0, 2.0]).should eq(4.0)
122
+ expect{Ryeppp.sumabs_v64f_s64f([1.0, -1.0, 'a'])}.to raise_error(TypeError)
123
+ end
124
+ # Sum Square Values
125
+ it 'should sum square values of a vector of Floats' do
126
+ Ryeppp.sumsquares_v64f_s64f([1.0, -1.0, 2.0]).should eq(6.0)
127
+ expect{Ryeppp.sumsquares_v64f_s64f([1.0, -1.0, 'a'])}.to raise_error(TypeError)
128
+ end
129
+
130
+ # Log
131
+ it 'should find the natural logarithm of elements of a vector of Floats' do
132
+ Ryeppp.log_v64f_v64f([1.0, 2.0, 3.0]).map{|o| o.round(5)}.should eq([0.0, 0.69315, 1.09861])
133
+ expect{Ryeppp.log_v64f_v64f([1.0, 'a'])}.to raise_error(TypeError)
134
+ end
135
+ # Exp
136
+ it 'should find the base e exponent of elements of a vector of Floats' do
137
+ Ryeppp.exp_v64f_v64f([1.0, 2.0, 3.0]).map{|o| o.round(5)}.should eq([2.71828, 7.38906, 20.08554])
138
+ expect{Ryeppp.exp_v64f_v64f([1.0, 'a'])}.to raise_error(TypeError)
139
+ end
140
+ # Sin
141
+ it 'should find the sine of elements of a vector of Floats' do
142
+ Ryeppp.sin_v64f_v64f([1.0, 2.0, 3.0]).map{|o| o.round(5)}.should eq([0.84147, 0.9093, 0.14112])
143
+ expect{Ryeppp.sin_v64f_v64f([1.0, 'a'])}.to raise_error(TypeError)
144
+ end
145
+ # Cos
146
+ it 'should find the cosine of elements of a vector of Floats' do
147
+ Ryeppp.cos_v64f_v64f([1.0, 2.0, 3.0]).map{|o| o.round(5)}.should eq([0.5403, -0.41615, -0.98999])
148
+ expect{Ryeppp.cos_v64f_v64f([1.0, 'a'])}.to raise_error(TypeError)
149
+ end
150
+ # Tan
151
+ it 'should find the tangent of elements of a vector of Floats' do
152
+ Ryeppp.tan_v64f_v64f([1.0, 2.0, 3.0]).map{|o| o.round(5)}.should eq([1.55741, -2.18504, -0.14255])
153
+ expect{Ryeppp.tan_v64f_v64f([1.0, 'a'])}.to raise_error(TypeError)
154
+ end
155
+
156
+ # Polynomial
157
+ it 'should evaluate a polynomial for a vector of Floats' do
158
+ # x^2 + x + 1
159
+ # evaluated at x=1.
160
+ Ryeppp.evaluatepolynomial_v64fv64f_v64f([1.0, 1.0, 1.0], [1.0]).should eq([3.0])
161
+ # -5x^3 - 4x^2 + 2x + 1
162
+ # evaluated at x=0, x=1, and x=2.
163
+ Ryeppp.evaluatepolynomial_v64fv64f_v64f([-5, -4, 2, 1], [0, 1, 2]).should eq([1.0, -6.0, -51.0])
164
+ expect{Ryeppp.evaluatepolynomial_v64fv64f_v64f([1, 'a'], [0, 1])}.to raise_error(TypeError)
165
+ end
166
+ end
@@ -0,0 +1,7 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'ryeppp'
4
+
5
+ RSpec.configure do |config|
6
+ # some (optional) config here
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ryeppp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -117,7 +117,20 @@ extensions:
117
117
  - ext/ryeppp/extconf.rb
118
118
  extra_rdoc_files: []
119
119
  files:
120
+ - .gitignore
121
+ - .rspec
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
120
126
  - ext/ryeppp/extconf.rb
127
+ - ext/templates/ryeppp.c.rb
128
+ - lib/ryeppp.rb
129
+ - lib/ryeppp/bench.rb
130
+ - lib/ryeppp/version.rb
131
+ - ryeppp.gemspec
132
+ - spec/ryeppp_spec.rb
133
+ - spec/spec_helper.rb
121
134
  homepage: https://github.com/bradcater/ruby-yeppp
122
135
  licenses:
123
136
  - MIT
@@ -143,4 +156,6 @@ rubygems_version: 1.8.25
143
156
  signing_key:
144
157
  specification_version: 3
145
158
  summary: This gem provides bindings to the Yeppp! library.
146
- test_files: []
159
+ test_files:
160
+ - spec/ryeppp_spec.rb
161
+ - spec/spec_helper.rb