nmatrix 0.0.1
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/.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
|
+
}
|