nmatrix 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +23 -0
- data/.gemtest +0 -0
- data/Gemfile +7 -0
- data/History.txt +6 -0
- data/LICENSE.txt +21 -0
- data/Manifest.txt +51 -0
- data/README.rdoc +63 -0
- data/Rakefile +154 -0
- data/ext/nmatrix/cblas.c +150 -0
- data/ext/nmatrix/dense.c +307 -0
- data/ext/nmatrix/dense/blas_header.template.c +52 -0
- data/ext/nmatrix/dense/elementwise.template.c +107 -0
- data/ext/nmatrix/dense/gemm.template.c +159 -0
- data/ext/nmatrix/dense/gemv.template.c +130 -0
- data/ext/nmatrix/dense/rationalmath.template.c +68 -0
- data/ext/nmatrix/depend +18 -0
- data/ext/nmatrix/extconf.rb +143 -0
- data/ext/nmatrix/generator.rb +594 -0
- data/ext/nmatrix/generator/syntax_tree.rb +481 -0
- data/ext/nmatrix/list.c +774 -0
- data/ext/nmatrix/nmatrix.c +1977 -0
- data/ext/nmatrix/nmatrix.h +912 -0
- data/ext/nmatrix/rational.c +98 -0
- data/ext/nmatrix/yale.c +726 -0
- data/ext/nmatrix/yale/complexmath.template.c +71 -0
- data/ext/nmatrix/yale/elementwise.template.c +46 -0
- data/ext/nmatrix/yale/elementwise_op.template.c +73 -0
- data/ext/nmatrix/yale/numbmm.template.c +94 -0
- data/ext/nmatrix/yale/smmp1.template.c +21 -0
- data/ext/nmatrix/yale/smmp1_header.template.c +38 -0
- data/ext/nmatrix/yale/smmp2.template.c +43 -0
- data/ext/nmatrix/yale/smmp2_header.template.c +46 -0
- data/ext/nmatrix/yale/sort_columns.template.c +56 -0
- data/ext/nmatrix/yale/symbmm.template.c +54 -0
- data/ext/nmatrix/yale/transp.template.c +68 -0
- data/lib/array.rb +67 -0
- data/lib/nmatrix.rb +263 -0
- data/lib/string.rb +65 -0
- data/spec/nmatrix_spec.rb +395 -0
- data/spec/nmatrix_yale_spec.rb +239 -0
- data/spec/nvector_spec.rb +43 -0
- data/spec/syntax_tree_spec.rb +46 -0
- metadata +150 -0
data/ext/nmatrix/dense.c
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
2
|
+
// = NMatrix
|
3
|
+
//
|
4
|
+
// A linear algebra library for scientific computation in Ruby.
|
5
|
+
// NMatrix is part of SciRuby.
|
6
|
+
//
|
7
|
+
// NMatrix was originally inspired by and derived from NArray, by
|
8
|
+
// Masahiro Tanaka: http://narray.rubyforge.org
|
9
|
+
//
|
10
|
+
// == Copyright Information
|
11
|
+
//
|
12
|
+
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
|
13
|
+
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
|
14
|
+
//
|
15
|
+
// Please see LICENSE.txt for additional copyright notices.
|
16
|
+
//
|
17
|
+
// == Contributing
|
18
|
+
//
|
19
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
20
|
+
// our Contributor Agreement:
|
21
|
+
//
|
22
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
23
|
+
//
|
24
|
+
// == dense.c
|
25
|
+
//
|
26
|
+
// Dense n-dimensional matrix storage.
|
27
|
+
|
28
|
+
#ifndef DENSE_C
|
29
|
+
#define DENSE_C
|
30
|
+
|
31
|
+
#include <ruby.h>
|
32
|
+
|
33
|
+
#include "nmatrix.h"
|
34
|
+
|
35
|
+
|
36
|
+
/* Calculate the number of elements in the dense storage structure, based on shape and rank */
|
37
|
+
size_t count_dense_storage_elements(const DENSE_STORAGE* s) {
|
38
|
+
size_t i;
|
39
|
+
size_t count = 1;
|
40
|
+
for (i = 0; i < s->rank; ++i) count *= s->shape[i];
|
41
|
+
return count;
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
// Do these two dense matrices of the same dtype have exactly the same contents?
|
46
|
+
bool dense_storage_eqeq(const DENSE_STORAGE* left, const DENSE_STORAGE* right) {
|
47
|
+
return !memcmp(left->elements, right->elements, count_dense_storage_elements(left) / nm_sizeof[left->dtype]);
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
size_t dense_storage_pos(DENSE_STORAGE* s, size_t* coords) {
|
52
|
+
size_t k, l;
|
53
|
+
size_t inner, outer = 0;
|
54
|
+
for (k = 0; k < s->rank; ++k) {
|
55
|
+
inner = coords[k];
|
56
|
+
for (l = k+1; l < s->rank; ++l) {
|
57
|
+
inner *= s->shape[l];
|
58
|
+
}
|
59
|
+
outer += inner;
|
60
|
+
}
|
61
|
+
return outer;
|
62
|
+
}
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
void* dense_storage_get(DENSE_STORAGE* s, size_t* coords) {
|
67
|
+
return (char*)(s->elements) + dense_storage_pos(s, coords) * nm_sizeof[s->dtype];
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
/* Does not free passed-in value! Different from list_storage_insert. */
|
72
|
+
void dense_storage_set(DENSE_STORAGE* s, size_t* coords, void* val) {
|
73
|
+
memcpy((char*)(s->elements) + dense_storage_pos(s, coords) * nm_sizeof[s->dtype], val, nm_sizeof[s->dtype]);
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
DENSE_STORAGE* copy_dense_storage(DENSE_STORAGE* rhs) {
|
78
|
+
DENSE_STORAGE* lhs;
|
79
|
+
size_t count = count_dense_storage_elements(rhs), p;
|
80
|
+
size_t* shape = ALLOC_N(size_t, rhs->rank);
|
81
|
+
if (!shape) return NULL;
|
82
|
+
|
83
|
+
// copy shape array
|
84
|
+
for (p = 0; p < rhs->rank; ++p)
|
85
|
+
shape[p] = rhs->shape[p];
|
86
|
+
|
87
|
+
lhs = create_dense_storage(rhs->dtype, shape, rhs->rank, NULL, 0);
|
88
|
+
|
89
|
+
if (lhs && count) // ensure that allocation worked before copying
|
90
|
+
memcpy(lhs->elements, rhs->elements, nm_sizeof[rhs->dtype] * count);
|
91
|
+
|
92
|
+
return lhs;
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
DENSE_STORAGE* cast_copy_dense_storage(DENSE_STORAGE* rhs, int8_t new_dtype) {
|
97
|
+
DENSE_STORAGE* lhs;
|
98
|
+
size_t count = count_dense_storage_elements(rhs), p;
|
99
|
+
size_t* shape = ALLOC_N(size_t, rhs->rank);
|
100
|
+
if (!shape) return NULL;
|
101
|
+
|
102
|
+
// copy shape array
|
103
|
+
for (p = 0; p < rhs->rank; ++p) shape[p] = rhs->shape[p];
|
104
|
+
|
105
|
+
lhs = create_dense_storage(new_dtype, shape, rhs->rank, NULL, 0);
|
106
|
+
|
107
|
+
if (lhs && count) // ensure that allocation worked before copying
|
108
|
+
if (lhs->dtype == rhs->dtype)
|
109
|
+
memcpy(lhs->elements, rhs->elements, nm_sizeof[rhs->dtype] * count);
|
110
|
+
else
|
111
|
+
SetFuncs[lhs->dtype][rhs->dtype](count, lhs->elements, nm_sizeof[lhs->dtype], rhs->elements, nm_sizeof[rhs->dtype]);
|
112
|
+
|
113
|
+
|
114
|
+
return lhs;
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
// Copy a set of default values into dense
|
120
|
+
static inline void cast_copy_dense_list_default(void* lhs, void* default_val, int8_t l_dtype, int8_t r_dtype, size_t* pos, const size_t* shape, size_t rank, size_t max_elements, size_t recursions) {
|
121
|
+
size_t i;
|
122
|
+
|
123
|
+
for (i = 0; i < shape[rank-1-recursions]; ++i, ++(*pos)) {
|
124
|
+
//fprintf(stderr, "default: pos = %u, dim = %u\t", *pos, shape[rank-1-recursions]);
|
125
|
+
|
126
|
+
if (recursions == 0) { cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], default_val, l_dtype, r_dtype); fprintf(stderr, "zero\n"); }
|
127
|
+
else { cast_copy_dense_list_default(lhs, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); fprintf(stderr, "column of zeros\n"); }
|
128
|
+
}
|
129
|
+
--(*pos);
|
130
|
+
}
|
131
|
+
|
132
|
+
|
133
|
+
// Copy list contents into dense recursively
|
134
|
+
static void cast_copy_dense_list_contents(void* lhs, const LIST* rhs, void* default_val, int8_t l_dtype, int8_t r_dtype, size_t* pos, const size_t* shape, size_t rank, size_t max_elements, size_t recursions) {
|
135
|
+
NODE *curr = rhs->first;
|
136
|
+
int last_key = -1;
|
137
|
+
size_t i = 0;
|
138
|
+
|
139
|
+
for (i = 0; i < shape[rank-1-recursions]; ++i, ++(*pos)) {
|
140
|
+
|
141
|
+
if (!curr || (curr->key > (size_t)(last_key+1))) {
|
142
|
+
//fprintf(stderr, "pos = %u, dim = %u, curr->key XX, last_key+1 = %d\t", *pos, shape[rank-1-recursions], last_key+1);
|
143
|
+
if (recursions == 0) cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], default_val, l_dtype, r_dtype); //fprintf(stderr, "zero\n"); }
|
144
|
+
else cast_copy_dense_list_default(lhs, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); //fprintf(stderr, "column of zeros\n"); }
|
145
|
+
|
146
|
+
++last_key;
|
147
|
+
} else {
|
148
|
+
//fprintf(stderr, "pos = %u, dim = %u, curr->key = %u, last_key+1 = %d\t", *pos, shape[rank-1-recursions], curr->key, last_key+1);
|
149
|
+
if (recursions == 0) cast_copy_value_single((char*)lhs + (*pos)*nm_sizeof[l_dtype], curr->val, l_dtype, r_dtype); //fprintf(stderr, "value\n"); }
|
150
|
+
else cast_copy_dense_list_contents(lhs, curr->val, default_val, l_dtype, r_dtype, pos, shape, rank, max_elements, recursions-1); //fprintf(stderr, "column of values\n"); }
|
151
|
+
|
152
|
+
last_key = curr->key;
|
153
|
+
curr = curr->next;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
--(*pos);
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
// Convert (by creating a copy) from list storage to dense storage.
|
161
|
+
DENSE_STORAGE* scast_copy_dense_list(const LIST_STORAGE* rhs, int8_t l_dtype) {
|
162
|
+
DENSE_STORAGE* lhs;
|
163
|
+
size_t pos = 0; // position in lhs->elements
|
164
|
+
|
165
|
+
// allocate and copy shape
|
166
|
+
size_t* shape = ALLOC_N(size_t, rhs->rank);
|
167
|
+
memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
|
168
|
+
|
169
|
+
lhs = create_dense_storage(l_dtype, shape, rhs->rank, NULL, 0);
|
170
|
+
|
171
|
+
// recursively copy the contents
|
172
|
+
cast_copy_dense_list_contents(lhs->elements, rhs->rows, rhs->default_val, l_dtype, rhs->dtype, &pos, shape, lhs->rank, count_storage_max_elements((STORAGE*)rhs), rhs->rank-1);
|
173
|
+
|
174
|
+
return lhs;
|
175
|
+
}
|
176
|
+
|
177
|
+
|
178
|
+
DENSE_STORAGE* scast_copy_dense_yale(const YALE_STORAGE* rhs, int8_t l_dtype) {
|
179
|
+
DENSE_STORAGE* lhs;
|
180
|
+
y_size_t i, j, // position in lhs->elements
|
181
|
+
ija, ija_next, jj; // position in rhs->elements
|
182
|
+
y_size_t pos = 0; // position in dense to write to
|
183
|
+
void* R_ZERO = (char*)(rhs->a) + rhs->shape[0] * nm_sizeof[rhs->dtype]; // determine zero representation
|
184
|
+
|
185
|
+
// allocate and set shape
|
186
|
+
size_t* shape = ALLOC_N(size_t, rhs->rank);
|
187
|
+
memcpy(shape, rhs->shape, rhs->rank * sizeof(size_t));
|
188
|
+
|
189
|
+
lhs = create_dense_storage(l_dtype, shape, rhs->rank, NULL, 0);
|
190
|
+
|
191
|
+
// Walk through rows. For each entry we set in dense, increment pos.
|
192
|
+
for (i = 0; i < rhs->shape[0]; ++i) {
|
193
|
+
|
194
|
+
// get boundaries of this row, store in ija and ija_next
|
195
|
+
YaleGetIJA(ija, rhs, i);
|
196
|
+
YaleGetIJA(ija_next, rhs, i+1);
|
197
|
+
|
198
|
+
if (ija == ija_next) { // row is empty?
|
199
|
+
|
200
|
+
for (j = 0; j < rhs->shape[1]; ++j) { // write zeros in each column
|
201
|
+
|
202
|
+
// Fill in zeros (except for diagonal)
|
203
|
+
if (i == j) cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
|
204
|
+
else cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], R_ZERO, l_dtype, rhs->dtype);
|
205
|
+
|
206
|
+
++pos; // move to next dense position
|
207
|
+
}
|
208
|
+
|
209
|
+
} else {
|
210
|
+
// row contains entries: write those in each column, interspersed with zeros
|
211
|
+
YaleGetIJA(jj, rhs, ija);
|
212
|
+
|
213
|
+
for (j = 0; j < rhs->shape[1]; ++j) {
|
214
|
+
if (i == j) {
|
215
|
+
|
216
|
+
cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + i*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
|
217
|
+
|
218
|
+
} else if (j == jj) {
|
219
|
+
|
220
|
+
// copy from rhs
|
221
|
+
cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], (char*)(rhs->a) + ija*nm_sizeof[rhs->dtype], l_dtype, rhs->dtype);
|
222
|
+
|
223
|
+
// get next
|
224
|
+
++ija;
|
225
|
+
|
226
|
+
// increment to next column ID (or go off the end)
|
227
|
+
if (ija < ija_next) YaleGetIJA(jj, rhs, ija);
|
228
|
+
else jj = rhs->shape[1];
|
229
|
+
|
230
|
+
} else { // j < jj
|
231
|
+
|
232
|
+
// insert zero
|
233
|
+
cast_copy_value_single((char*)(lhs->elements) + pos*nm_sizeof[l_dtype], R_ZERO, l_dtype, rhs->dtype);
|
234
|
+
}
|
235
|
+
++pos; // move to next dense position
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
return lhs;
|
241
|
+
}
|
242
|
+
|
243
|
+
|
244
|
+
// Note that elements and elements_length are for initial value(s) passed in. If they are the correct length, they will
|
245
|
+
// be used directly. If not, they will be concatenated over and over again into a new elements array. If elements is NULL,
|
246
|
+
// the new elements array will not be initialized.
|
247
|
+
DENSE_STORAGE* create_dense_storage(int8_t dtype, size_t* shape, size_t rank, void* elements, size_t elements_length) {
|
248
|
+
DENSE_STORAGE* s;
|
249
|
+
size_t count, i, copy_length = elements_length;
|
250
|
+
|
251
|
+
s = ALLOC( DENSE_STORAGE );
|
252
|
+
//if (!(s = malloc(sizeof(DENSE_STORAGE)))) return NULL;
|
253
|
+
|
254
|
+
s->rank = rank;
|
255
|
+
s->shape = shape;
|
256
|
+
s->dtype = dtype;
|
257
|
+
|
258
|
+
//fprintf(stderr, "create_dense_storage: %p\n", s);
|
259
|
+
|
260
|
+
count = count_dense_storage_elements(s);
|
261
|
+
//fprintf(stderr, "count_dense_storage_elements: %d\n", count);
|
262
|
+
|
263
|
+
if (elements_length == count) s->elements = elements;
|
264
|
+
else {
|
265
|
+
s->elements = ALLOC_N(char, nm_sizeof[dtype]*count);
|
266
|
+
|
267
|
+
if (elements_length > 0) {
|
268
|
+
// repeat elements over and over again until the end of the matrix
|
269
|
+
for (i = 0; i < count; i += elements_length) {
|
270
|
+
if (i + elements_length > count) copy_length = count - i;
|
271
|
+
memcpy((char*)(s->elements)+i*nm_sizeof[dtype], (char*)(elements)+(i % elements_length)*nm_sizeof[dtype], copy_length*nm_sizeof[dtype]);
|
272
|
+
}
|
273
|
+
|
274
|
+
// get rid of the init_val
|
275
|
+
free(elements);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
|
279
|
+
return s;
|
280
|
+
}
|
281
|
+
|
282
|
+
|
283
|
+
void delete_dense_storage(DENSE_STORAGE* s) {
|
284
|
+
if (s) { // sometimes Ruby passes in NULL storage for some reason (probably on copy construction failure)
|
285
|
+
free(s->shape);
|
286
|
+
free(s->elements);
|
287
|
+
free(s);
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
|
292
|
+
void mark_dense_storage(void* m) {
|
293
|
+
size_t i;
|
294
|
+
DENSE_STORAGE* storage;
|
295
|
+
|
296
|
+
if (m) {
|
297
|
+
storage = (DENSE_STORAGE*)(((NMATRIX*)m)->storage);
|
298
|
+
//fprintf(stderr, "mark_dense_storage\n");
|
299
|
+
if (storage && storage->dtype == NM_ROBJ)
|
300
|
+
for (i = 0; i < count_dense_storage_elements(storage); ++i)
|
301
|
+
rb_gc_mark(*((VALUE*)((char*)(storage->elements) + i*nm_sizeof[NM_ROBJ])));
|
302
|
+
}
|
303
|
+
}
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
#endif
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
2
|
+
// = NMatrix
|
3
|
+
//
|
4
|
+
// A linear algebra library for scientific computation in Ruby.
|
5
|
+
// NMatrix is part of SciRuby.
|
6
|
+
//
|
7
|
+
// NMatrix was originally inspired by and derived from NArray, by
|
8
|
+
// Masahiro Tanaka: http://narray.rubyforge.org
|
9
|
+
//
|
10
|
+
// == Copyright Information
|
11
|
+
//
|
12
|
+
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
|
13
|
+
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
|
14
|
+
//
|
15
|
+
// Please see LICENSE.txt for additional copyright notices.
|
16
|
+
//
|
17
|
+
// == Contributing
|
18
|
+
//
|
19
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
20
|
+
// our Contributor Agreement:
|
21
|
+
//
|
22
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
23
|
+
//
|
24
|
+
// == blas.c
|
25
|
+
//
|
26
|
+
// blas.c is automatically generated by generator.rb. Do not modify
|
27
|
+
// it directly!
|
28
|
+
//
|
29
|
+
// This file contains C ports of BLAS functions that work on integer
|
30
|
+
// types and eventually rationals. You can find the original template
|
31
|
+
// in ext/nmatrix/blas/igemm.template.c.
|
32
|
+
//
|
33
|
+
// The port was accomplished using f2c (on dgemm.f) and a magnifying
|
34
|
+
// glass.
|
35
|
+
//
|
36
|
+
// Note that this is in no way comparable to ATLAS. Why?
|
37
|
+
// * We didn't test any options other than CblasNoTrans (for A and B)
|
38
|
+
// * It doesn't use any of that cool cross-over crap (e.g.,
|
39
|
+
// Strassen's algorithm)
|
40
|
+
// * It really hasn't been tested exhaustively in any way, shape, or
|
41
|
+
// form.
|
42
|
+
//
|
43
|
+
// This file also contains rational math helper functions so that the
|
44
|
+
// aforementioned port will work with rationals too. These are in
|
45
|
+
// ext/nmatrix/blas/rationalmath.template.c. They are derived from
|
46
|
+
// rational.c in Ruby 1.9.3.
|
47
|
+
|
48
|
+
#include "nmatrix.h"
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
|
2
|
+
int nm_d_%%TYPE_ABBREV%%_elementwise(const %%TYPE%%* A, const %%TYPE%%* B, %%TYPE%%* C, size_t n, enum NMatrix_Ops op)
|
3
|
+
{
|
4
|
+
size_t i;
|
5
|
+
//fprintf(stderr, "elementwise: n=%d, op=%c\n", n, op);
|
6
|
+
|
7
|
+
switch (op) {
|
8
|
+
case '+':
|
9
|
+
for (i = 0; i < n; ++i) {
|
10
|
+
%%TYPE C[i] = A[i] + B[i]%%
|
11
|
+
}
|
12
|
+
break;
|
13
|
+
case '-':
|
14
|
+
for (i = 0; i < n; ++i) {
|
15
|
+
%%TYPE C[i] = A[i] - B[i]%%
|
16
|
+
}
|
17
|
+
break;
|
18
|
+
case '*':
|
19
|
+
for (i = 0; i < n; ++i) {
|
20
|
+
%%TYPE C[i] = A[i] * B[i]%%
|
21
|
+
}
|
22
|
+
break;
|
23
|
+
case '/':
|
24
|
+
for (i = 0; i < n; ++i) {
|
25
|
+
%%TYPE C[i] = A[i] / B[i]%%
|
26
|
+
}
|
27
|
+
break;
|
28
|
+
case '%':
|
29
|
+
for (i = 0; i < n; ++i) {
|
30
|
+
%%TYPE C[i] = A[i] % B[i]%%
|
31
|
+
}
|
32
|
+
break;
|
33
|
+
case '!':
|
34
|
+
for (i = 0; i < n; ++i) {
|
35
|
+
%%TYPE C[i] = !A[i]%%
|
36
|
+
}
|
37
|
+
break;
|
38
|
+
case NM_OP_NEG:
|
39
|
+
for (i = 0; i < n; ++i) {
|
40
|
+
%%TYPE C[i] = -A[i]%%
|
41
|
+
}
|
42
|
+
break;
|
43
|
+
case NM_OP_EQEQ:
|
44
|
+
for (i = 0; i < n; ++i) {
|
45
|
+
%%TYPE C[i] = A[i] == B[i]%%
|
46
|
+
}
|
47
|
+
break;
|
48
|
+
case NM_OP_NEQ:
|
49
|
+
for (i = 0; i < n; ++i) {
|
50
|
+
%%TYPE C[i] = A[i] != B[i]%%
|
51
|
+
}
|
52
|
+
break;
|
53
|
+
case '>':
|
54
|
+
for (i = 0; i < n; ++i) {
|
55
|
+
%%TYPE C[i] = A[i] > B[i]%%
|
56
|
+
}
|
57
|
+
break;
|
58
|
+
case '<':
|
59
|
+
for (i = 0; i < n; ++i) {
|
60
|
+
%%TYPE C[i] = A[i] < B[i]%%
|
61
|
+
}
|
62
|
+
break;
|
63
|
+
case NM_OP_GTE:
|
64
|
+
for (i = 0; i < n; ++i) {
|
65
|
+
%%TYPE C[i] = A[i] >= B[i]%%
|
66
|
+
}
|
67
|
+
break;
|
68
|
+
case NM_OP_LTE:
|
69
|
+
for (i = 0; i < n; ++i) {
|
70
|
+
%%TYPE C[i] = A[i] <= B[i]%%
|
71
|
+
}
|
72
|
+
break;
|
73
|
+
case '~':
|
74
|
+
for (i = 0; i < n; ++i) {
|
75
|
+
%%TYPE C[i] = ~A[i]%%
|
76
|
+
}
|
77
|
+
break;
|
78
|
+
case '&':
|
79
|
+
for (i = 0; i < n; ++i) {
|
80
|
+
%%TYPE C[i] = A[i] & B[i]%%
|
81
|
+
}
|
82
|
+
break;
|
83
|
+
case '|':
|
84
|
+
for (i = 0; i < n; ++i) {
|
85
|
+
%%TYPE C[i] = A[i] | B[i]%%
|
86
|
+
}
|
87
|
+
break;
|
88
|
+
case '^':
|
89
|
+
for (i = 0; i < n; ++i) {
|
90
|
+
%%TYPE C[i] = A[i] ^ B[i]%%
|
91
|
+
}
|
92
|
+
break;
|
93
|
+
case NM_OP_LSH:
|
94
|
+
for (i = 0; i < n; ++i) {
|
95
|
+
%%TYPE C[i] = A[i] << B[i]%%
|
96
|
+
}
|
97
|
+
break;
|
98
|
+
case NM_OP_RSH:
|
99
|
+
for (i = 0; i < n; ++i) {
|
100
|
+
%%TYPE C[i] = A[i] >> B[i]%%
|
101
|
+
}
|
102
|
+
break;
|
103
|
+
default:
|
104
|
+
rb_raise(rb_eNotImpError, "Unrecognized element-wise operator");
|
105
|
+
}
|
106
|
+
return 0;
|
107
|
+
}
|