nmatrix 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/History.txt +31 -3
- data/Manifest.txt +5 -0
- data/README.rdoc +29 -27
- data/ext/nmatrix/binary_format.txt +53 -0
- data/ext/nmatrix/data/data.cpp +18 -18
- data/ext/nmatrix/data/data.h +38 -7
- data/ext/nmatrix/data/rational.h +13 -0
- data/ext/nmatrix/data/ruby_object.h +10 -0
- data/ext/nmatrix/extconf.rb +2 -0
- data/ext/nmatrix/nmatrix.cpp +655 -103
- data/ext/nmatrix/nmatrix.h +26 -14
- data/ext/nmatrix/ruby_constants.cpp +4 -0
- data/ext/nmatrix/ruby_constants.h +2 -0
- data/ext/nmatrix/storage/dense.cpp +99 -41
- data/ext/nmatrix/storage/dense.h +3 -3
- data/ext/nmatrix/storage/list.cpp +36 -14
- data/ext/nmatrix/storage/list.h +4 -4
- data/ext/nmatrix/storage/storage.cpp +19 -19
- data/ext/nmatrix/storage/storage.h +11 -11
- data/ext/nmatrix/storage/yale.cpp +17 -20
- data/ext/nmatrix/storage/yale.h +13 -11
- data/ext/nmatrix/util/io.cpp +25 -23
- data/ext/nmatrix/util/io.h +5 -5
- data/ext/nmatrix/util/math.cpp +634 -17
- data/ext/nmatrix/util/math.h +958 -9
- data/ext/nmatrix/util/sl_list.cpp +7 -7
- data/ext/nmatrix/util/sl_list.h +2 -2
- data/lib/nmatrix.rb +9 -0
- data/lib/nmatrix/blas.rb +4 -4
- data/lib/nmatrix/io/market.rb +227 -0
- data/lib/nmatrix/io/mat_reader.rb +7 -7
- data/lib/nmatrix/lapack.rb +80 -0
- data/lib/nmatrix/nmatrix.rb +78 -52
- data/lib/nmatrix/shortcuts.rb +486 -0
- data/lib/nmatrix/version.rb +1 -1
- data/spec/2x2_dense_double.mat +0 -0
- data/spec/blas_spec.rb +59 -9
- data/spec/elementwise_spec.rb +25 -12
- data/spec/io_spec.rb +69 -1
- data/spec/lapack_spec.rb +53 -4
- data/spec/math_spec.rb +9 -0
- data/spec/nmatrix_list_spec.rb +95 -0
- data/spec/nmatrix_spec.rb +10 -53
- data/spec/nmatrix_yale_spec.rb +17 -15
- data/spec/shortcuts_spec.rb +154 -0
- metadata +22 -15
data/ext/nmatrix/nmatrix.h
CHANGED
@@ -112,8 +112,8 @@
|
|
112
112
|
|
113
113
|
#ifdef __cplusplus /* These are the C++ versions of the macros. */
|
114
114
|
|
115
|
-
#define NM_DECL_ENUM(enum_type, name) enum_type name
|
116
|
-
#define NM_DECL_STRUCT(type, name) type
|
115
|
+
#define NM_DECL_ENUM(enum_type, name) nm::enum_type name
|
116
|
+
#define NM_DECL_STRUCT(type, name) type name;
|
117
117
|
|
118
118
|
#define NM_DEF_STORAGE_ELEMENTS \
|
119
119
|
NM_DECL_ENUM(dtype_t, dtype); \
|
@@ -135,13 +135,15 @@
|
|
135
135
|
#define NM_DEF_STRUCT_POST(name) };
|
136
136
|
|
137
137
|
#define NM_DEF_ENUM(name, ...) \
|
138
|
-
|
139
|
-
|
140
|
-
|
138
|
+
namespace nm { \
|
139
|
+
enum name { \
|
140
|
+
__VA_ARGS__ \
|
141
|
+
}; \
|
142
|
+
} // end of namespace nm
|
141
143
|
|
142
144
|
#else /* These are the C versions of the macros. */
|
143
145
|
|
144
|
-
#define NM_DECL_ENUM(enum_type, name) nm_ ## enum_type name
|
146
|
+
#define NM_DECL_ENUM(enum_type, name) nm_ ## enum_type name
|
145
147
|
#define NM_DECL_STRUCT(type, name) NM_ ## type name;
|
146
148
|
|
147
149
|
#define NM_DEF_STORAGE_ELEMENTS \
|
@@ -160,7 +162,6 @@
|
|
160
162
|
typedef struct NM_STORAGE { \
|
161
163
|
NM_DEF_STORAGE_ELEMENTS; \
|
162
164
|
} NM_STORAGE;
|
163
|
-
>>>>>>> compile_point
|
164
165
|
|
165
166
|
#define NM_DEF_STRUCT_PRE(name) typedef struct NM_ ## name {
|
166
167
|
#define NM_DEF_STRUCT_POST(name) } NM_ ## name;
|
@@ -181,11 +182,9 @@
|
|
181
182
|
#define NM_NUM_ITYPES 4 // data/data.h
|
182
183
|
#define NM_NUM_STYPES 3 // storage/storage.h
|
183
184
|
|
184
|
-
|
185
|
+
//#ifdef __cplusplus
|
185
186
|
//namespace nm {
|
186
|
-
|
187
|
-
|
188
|
-
#endif
|
187
|
+
//#endif
|
189
188
|
|
190
189
|
/* Storage Type -- Dense or Sparse */
|
191
190
|
NM_DEF_ENUM(stype_t, DENSE_STORE = 0,
|
@@ -213,6 +212,17 @@ NM_DEF_ENUM(itype_t, UINT8 = 0,
|
|
213
212
|
UINT32 = 2,
|
214
213
|
UINT64 = 3);
|
215
214
|
|
215
|
+
NM_DEF_ENUM(symm_t, NONSYMM = 0,
|
216
|
+
SYMM = 1,
|
217
|
+
SKEW = 2,
|
218
|
+
HERM = 3,
|
219
|
+
UPPER = 4,
|
220
|
+
LOWER = 5);
|
221
|
+
|
222
|
+
//#ifdef __cplusplus
|
223
|
+
//}; // end of namespace nm
|
224
|
+
//#endif
|
225
|
+
|
216
226
|
/* struct STORAGE */
|
217
227
|
NM_DEF_STORAGE_STRUCT;
|
218
228
|
|
@@ -227,7 +237,7 @@ NM_DEF_STORAGE_CHILD_STRUCT_PRE(YALE_STORAGE);
|
|
227
237
|
void* a; // should go first
|
228
238
|
size_t ndnz; // Strictly non-diagonal non-zero count!
|
229
239
|
size_t capacity;
|
230
|
-
itype_t
|
240
|
+
NM_DECL_ENUM(itype_t, itype);
|
231
241
|
void* ija;
|
232
242
|
NM_DEF_STORAGE_STRUCT_POST(YALE_STORAGE);
|
233
243
|
|
@@ -321,8 +331,10 @@ extern "C" {
|
|
321
331
|
void Init_nmatrix();
|
322
332
|
|
323
333
|
// External API
|
324
|
-
VALUE rb_nmatrix_dense_create(dtype_t dtype, size_t* shape, size_t dim, void* elements, size_t length);
|
325
|
-
VALUE rb_nvector_dense_create(dtype_t dtype, void* elements, size_t length);
|
334
|
+
VALUE rb_nmatrix_dense_create(NM_DECL_ENUM(dtype_t, dtype), size_t* shape, size_t dim, void* elements, size_t length);
|
335
|
+
VALUE rb_nvector_dense_create(NM_DECL_ENUM(dtype_t, dtype), void* elements, size_t length);
|
336
|
+
|
337
|
+
NM_DECL_ENUM(dtype_t, nm_dtype_guess(VALUE)); // (This is a function)
|
326
338
|
}
|
327
339
|
|
328
340
|
#endif // NMATRIX_H
|
@@ -68,6 +68,8 @@ ID nm_rb_real,
|
|
68
68
|
nm_rb_mul,
|
69
69
|
nm_rb_div,
|
70
70
|
|
71
|
+
nm_rb_negate,
|
72
|
+
|
71
73
|
nm_rb_percent,
|
72
74
|
nm_rb_gt,
|
73
75
|
nm_rb_lt,
|
@@ -116,6 +118,8 @@ void nm_init_ruby_constants(void) {
|
|
116
118
|
nm_rb_mul = rb_intern("*");
|
117
119
|
nm_rb_div = rb_intern("/");
|
118
120
|
|
121
|
+
nm_rb_negate = rb_intern("-@");
|
122
|
+
|
119
123
|
nm_rb_percent = rb_intern("%");
|
120
124
|
nm_rb_gt = rb_intern(">");
|
121
125
|
nm_rb_lt = rb_intern("<");
|
@@ -56,13 +56,13 @@
|
|
56
56
|
namespace nm { namespace dense_storage {
|
57
57
|
|
58
58
|
template <typename LDType, typename RDType>
|
59
|
-
DENSE_STORAGE* cast_copy(const DENSE_STORAGE* rhs, dtype_t new_dtype);
|
59
|
+
DENSE_STORAGE* cast_copy(const DENSE_STORAGE* rhs, nm::dtype_t new_dtype);
|
60
60
|
|
61
61
|
template <typename LDType, typename RDType>
|
62
62
|
bool eqeq(const DENSE_STORAGE* left, const DENSE_STORAGE* right);
|
63
63
|
|
64
64
|
template <ewop_t op, typename LDType, typename RDType>
|
65
|
-
static DENSE_STORAGE* ew_op(const DENSE_STORAGE* left, const DENSE_STORAGE* right);
|
65
|
+
static DENSE_STORAGE* ew_op(const DENSE_STORAGE* left, const DENSE_STORAGE* right, const void* rscalar);
|
66
66
|
|
67
67
|
template <typename DType>
|
68
68
|
static DENSE_STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
|
@@ -95,7 +95,7 @@ static void slice_copy(DENSE_STORAGE *dest, const DENSE_STORAGE *src, size_t* le
|
|
95
95
|
* will be concatenated over and over again into a new elements array. If
|
96
96
|
* elements is NULL, the new elements array will not be initialized.
|
97
97
|
*/
|
98
|
-
DENSE_STORAGE* nm_dense_storage_create(dtype_t dtype, size_t* shape, size_t dim, void* elements, size_t elements_length) {
|
98
|
+
DENSE_STORAGE* nm_dense_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, void* elements, size_t elements_length) {
|
99
99
|
DENSE_STORAGE* s = ALLOC( DENSE_STORAGE );
|
100
100
|
|
101
101
|
s->dim = dim;
|
@@ -175,7 +175,7 @@ void nm_dense_storage_delete_ref(STORAGE* s) {
|
|
175
175
|
void nm_dense_storage_mark(void* storage_base) {
|
176
176
|
DENSE_STORAGE* storage = (DENSE_STORAGE*)storage_base;
|
177
177
|
|
178
|
-
if (storage && storage->dtype == RUBYOBJ) {
|
178
|
+
if (storage && storage->dtype == nm::RUBYOBJ) {
|
179
179
|
VALUE* els = reinterpret_cast<VALUE*>(storage->elements);
|
180
180
|
|
181
181
|
for (size_t index = nm_storage_count_max_elements(storage); index-- > 0;) {
|
@@ -281,10 +281,10 @@ bool nm_dense_storage_eqeq(const STORAGE* left, const STORAGE* right) {
|
|
281
281
|
* dtype of Complex64 or Complex128 this is the same as testing for symmetry.
|
282
282
|
*/
|
283
283
|
bool nm_dense_storage_is_hermitian(const DENSE_STORAGE* mat, int lda) {
|
284
|
-
if (mat->dtype == COMPLEX64) {
|
284
|
+
if (mat->dtype == nm::COMPLEX64) {
|
285
285
|
return nm::dense_storage::is_hermitian<nm::Complex64>(mat, lda);
|
286
286
|
|
287
|
-
} else if (mat->dtype == COMPLEX128) {
|
287
|
+
} else if (mat->dtype == nm::COMPLEX128) {
|
288
288
|
return nm::dense_storage::is_hermitian<nm::Complex128>(mat, lda);
|
289
289
|
|
290
290
|
} else {
|
@@ -306,12 +306,22 @@ bool nm_dense_storage_is_symmetric(const DENSE_STORAGE* mat, int lda) {
|
|
306
306
|
//////////
|
307
307
|
|
308
308
|
/*
|
309
|
-
* Dense element-wise operations.
|
309
|
+
* Dense matrix-matrix and matrix-scalar element-wise operations.
|
310
|
+
*
|
311
|
+
* right or rscalar should be NULL; they should not both be initialized. If right is NULL, it'll use the scalar value instead.
|
310
312
|
*/
|
311
|
-
STORAGE* nm_dense_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right) {
|
312
|
-
OP_LR_DTYPE_TEMPLATE_TABLE(nm::dense_storage::ew_op, DENSE_STORAGE*, const DENSE_STORAGE* left, const DENSE_STORAGE* right);
|
313
|
+
STORAGE* nm_dense_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar) {
|
314
|
+
OP_LR_DTYPE_TEMPLATE_TABLE(nm::dense_storage::ew_op, DENSE_STORAGE*, const DENSE_STORAGE* left, const DENSE_STORAGE* right, const void*);
|
315
|
+
|
316
|
+
if (right)
|
317
|
+
return ttable[op][left->dtype][right->dtype](reinterpret_cast<const DENSE_STORAGE*>(left), reinterpret_cast<const DENSE_STORAGE*>(right), NULL);
|
318
|
+
else {
|
319
|
+
nm::dtype_t r_dtype = nm_dtype_guess(scalar);
|
320
|
+
void* r_scalar = ALLOCA_N(char, DTYPE_SIZES[r_dtype]);
|
321
|
+
rubyval_to_cval(scalar, r_dtype, r_scalar);
|
313
322
|
|
314
|
-
|
323
|
+
return ttable[op][left->dtype][r_dtype](reinterpret_cast<const DENSE_STORAGE*>(left), NULL, r_scalar);
|
324
|
+
}
|
315
325
|
}
|
316
326
|
|
317
327
|
/*
|
@@ -383,8 +393,8 @@ static void slice_copy(DENSE_STORAGE *dest, const DENSE_STORAGE *src, size_t* le
|
|
383
393
|
/*
|
384
394
|
* Copy dense storage, changing dtype if necessary.
|
385
395
|
*/
|
386
|
-
STORAGE* nm_dense_storage_cast_copy(const STORAGE* rhs, dtype_t new_dtype) {
|
387
|
-
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::cast_copy, DENSE_STORAGE*, const DENSE_STORAGE* rhs, dtype_t new_dtype);
|
396
|
+
STORAGE* nm_dense_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype) {
|
397
|
+
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::cast_copy, DENSE_STORAGE*, const DENSE_STORAGE* rhs, nm::dtype_t new_dtype);
|
388
398
|
|
389
399
|
return (STORAGE*)ttable[new_dtype][rhs->dtype]((DENSE_STORAGE*)rhs, new_dtype);
|
390
400
|
}
|
@@ -572,7 +582,7 @@ bool is_symmetric(const DENSE_STORAGE* mat, int lda) {
|
|
572
582
|
* Templated dense storage element-wise operations which return the same DType.
|
573
583
|
*/
|
574
584
|
template <ewop_t op, typename LDType, typename RDType>
|
575
|
-
static DENSE_STORAGE* ew_op(const DENSE_STORAGE* left, const DENSE_STORAGE* right) {
|
585
|
+
static DENSE_STORAGE* ew_op(const DENSE_STORAGE* left, const DENSE_STORAGE* right, const void* rscalar) {
|
576
586
|
unsigned int count;
|
577
587
|
|
578
588
|
size_t* new_shape = (size_t*)calloc(left->dim, sizeof(size_t));
|
@@ -585,46 +595,94 @@ static DENSE_STORAGE* ew_op(const DENSE_STORAGE* left, const DENSE_STORAGE* righ
|
|
585
595
|
DENSE_STORAGE* result = nm_dense_storage_create(new_dtype, new_shape, left->dim, NULL, 0);
|
586
596
|
|
587
597
|
LDType* l_elems = reinterpret_cast<LDType*>(left->elements);
|
588
|
-
RDType* r_elems = reinterpret_cast<RDType*>(right->elements);
|
589
598
|
|
590
|
-
if (
|
599
|
+
if (right) { // matrix-matrix operation
|
600
|
+
RDType* r_elems = reinterpret_cast<RDType*>(right->elements);
|
601
|
+
|
602
|
+
if (static_cast<uint8_t>(op) < NUM_NONCOMP_EWOPS) { // use left-dtype
|
603
|
+
|
604
|
+
for (count = nm_storage_count_max_elements(result); count-- > 0;) {
|
605
|
+
reinterpret_cast<LDType*>(result->elements)[count] = ew_op_switch<op,LDType,RDType>(l_elems[count], r_elems[count]);
|
606
|
+
}
|
607
|
+
|
608
|
+
} else { // new_dtype is BYTE: comparison operators
|
609
|
+
uint8_t* res_elems = reinterpret_cast<uint8_t*>(result->elements);
|
610
|
+
|
611
|
+
for (count = nm_storage_count_max_elements(result); count-- > 0;) {
|
612
|
+
switch (op) {
|
613
|
+
case EW_EQEQ:
|
614
|
+
res_elems[count] = l_elems[count] == r_elems[count];
|
615
|
+
break;
|
616
|
+
|
617
|
+
case EW_NEQ:
|
618
|
+
res_elems[count] = l_elems[count] != r_elems[count];
|
619
|
+
break;
|
620
|
+
|
621
|
+
case EW_LT:
|
622
|
+
res_elems[count] = l_elems[count] < r_elems[count];
|
623
|
+
break;
|
624
|
+
|
625
|
+
case EW_GT:
|
626
|
+
res_elems[count] = l_elems[count] > r_elems[count];
|
627
|
+
break;
|
591
628
|
|
592
|
-
|
593
|
-
|
629
|
+
case EW_LEQ:
|
630
|
+
res_elems[count] = l_elems[count] <= r_elems[count];
|
631
|
+
break;
|
632
|
+
|
633
|
+
case EW_GEQ:
|
634
|
+
res_elems[count] = l_elems[count] >= r_elems[count];
|
635
|
+
break;
|
636
|
+
|
637
|
+
default:
|
638
|
+
rb_raise(rb_eStandardError, "this should not happen");
|
639
|
+
}
|
640
|
+
}
|
594
641
|
}
|
595
642
|
|
596
|
-
} else { //
|
597
|
-
|
643
|
+
} else { // matrix-scalar operation
|
644
|
+
const RDType* r_elem = reinterpret_cast<const RDType*>(rscalar);
|
598
645
|
|
599
|
-
|
600
|
-
switch (op) {
|
601
|
-
case EW_EQEQ:
|
602
|
-
res_elems[count] = l_elems[count] == r_elems[count];
|
603
|
-
break;
|
646
|
+
if (static_cast<uint8_t>(op) < NUM_NONCOMP_EWOPS) { // use left-dtype
|
604
647
|
|
605
|
-
|
606
|
-
|
607
|
-
|
648
|
+
for (count = nm_storage_count_max_elements(result); count-- > 0;) {
|
649
|
+
reinterpret_cast<LDType*>(result->elements)[count] = ew_op_switch<op,LDType,RDType>(l_elems[count], *r_elem);
|
650
|
+
}
|
608
651
|
|
609
|
-
|
610
|
-
|
611
|
-
break;
|
652
|
+
} else {
|
653
|
+
uint8_t* res_elems = reinterpret_cast<uint8_t*>(result->elements);
|
612
654
|
|
613
|
-
|
614
|
-
|
615
|
-
|
655
|
+
for (count = nm_storage_count_max_elements(result); count-- > 0;) {
|
656
|
+
switch (op) {
|
657
|
+
case EW_EQEQ:
|
658
|
+
res_elems[count] = l_elems[count] == *r_elem;
|
659
|
+
break;
|
616
660
|
|
617
|
-
|
618
|
-
|
619
|
-
|
661
|
+
case EW_NEQ:
|
662
|
+
res_elems[count] = l_elems[count] != *r_elem;
|
663
|
+
break;
|
620
664
|
|
621
|
-
|
622
|
-
|
623
|
-
|
665
|
+
case EW_LT:
|
666
|
+
res_elems[count] = l_elems[count] < *r_elem;
|
667
|
+
break;
|
624
668
|
|
625
|
-
|
626
|
-
|
669
|
+
case EW_GT:
|
670
|
+
res_elems[count] = l_elems[count] > *r_elem;
|
671
|
+
break;
|
672
|
+
|
673
|
+
case EW_LEQ:
|
674
|
+
res_elems[count] = l_elems[count] <= *r_elem;
|
675
|
+
break;
|
676
|
+
|
677
|
+
case EW_GEQ:
|
678
|
+
res_elems[count] = l_elems[count] >= *r_elem;
|
679
|
+
break;
|
680
|
+
|
681
|
+
default:
|
682
|
+
rb_raise(rb_eStandardError, "this should not happen");
|
683
|
+
}
|
627
684
|
}
|
685
|
+
|
628
686
|
}
|
629
687
|
}
|
630
688
|
|
data/ext/nmatrix/storage/dense.h
CHANGED
@@ -69,7 +69,7 @@ extern "C" {
|
|
69
69
|
// Lifecycle //
|
70
70
|
///////////////
|
71
71
|
|
72
|
-
DENSE_STORAGE* nm_dense_storage_create(dtype_t dtype, size_t* shape, size_t dim, void* elements, size_t elements_length);
|
72
|
+
DENSE_STORAGE* nm_dense_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, void* elements, size_t elements_length);
|
73
73
|
void nm_dense_storage_delete(STORAGE* s);
|
74
74
|
void nm_dense_storage_delete_ref(STORAGE* s);
|
75
75
|
void nm_dense_storage_mark(void*);
|
@@ -94,7 +94,7 @@ bool nm_dense_storage_is_hermitian(const DENSE_STORAGE* mat, int lda);
|
|
94
94
|
// Math //
|
95
95
|
//////////
|
96
96
|
|
97
|
-
STORAGE* nm_dense_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right);
|
97
|
+
STORAGE* nm_dense_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar);
|
98
98
|
STORAGE* nm_dense_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
|
99
99
|
|
100
100
|
/////////////
|
@@ -109,7 +109,7 @@ size_t nm_dense_storage_pos(const DENSE_STORAGE* s, const size_t* coords);
|
|
109
109
|
|
110
110
|
DENSE_STORAGE* nm_dense_storage_copy(const DENSE_STORAGE* rhs);
|
111
111
|
STORAGE* nm_dense_storage_copy_transposed(const STORAGE* rhs_base);
|
112
|
-
STORAGE* nm_dense_storage_cast_copy(const STORAGE* rhs, dtype_t new_dtype);
|
112
|
+
STORAGE* nm_dense_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype);
|
113
113
|
|
114
114
|
} // end of extern "C" block
|
115
115
|
|
@@ -340,27 +340,44 @@ bool nm_list_storage_eqeq(const STORAGE* left, const STORAGE* right) {
|
|
340
340
|
|
341
341
|
/*
|
342
342
|
* Element-wise operations for list storage.
|
343
|
+
*
|
344
|
+
* If a scalar is given, a temporary matrix is created with that scalar as a default value.
|
343
345
|
*/
|
344
|
-
STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right) {
|
345
|
-
rb_raise(rb_eNotImpError, "elementwise operations for list storage currently broken");
|
346
|
+
STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar) {
|
347
|
+
// rb_raise(rb_eNotImpError, "elementwise operations for list storage currently broken");
|
346
348
|
|
347
|
-
|
349
|
+
bool cleanup = false;
|
350
|
+
LIST_STORAGE *r, *new_l;
|
351
|
+
const LIST_STORAGE* l = reinterpret_cast<const LIST_STORAGE*>(left);
|
352
|
+
|
353
|
+
if (!right) { // need to build a right-hand matrix temporarily, with default value of 'scalar'
|
354
|
+
|
355
|
+
dtype_t scalar_dtype = nm_dtype_guess(scalar);
|
356
|
+
void* scalar_init = rubyobj_to_cval(scalar, scalar_dtype);
|
357
|
+
|
358
|
+
size_t* shape = ALLOC_N(size_t, l->dim);
|
359
|
+
memcpy(shape, left->shape, sizeof(size_t) * l->dim);
|
360
|
+
|
361
|
+
r = nm_list_storage_create(scalar_dtype, shape, l->dim, scalar_init);
|
362
|
+
|
363
|
+
cleanup = true;
|
364
|
+
|
365
|
+
} else {
|
366
|
+
|
367
|
+
r = reinterpret_cast<LIST_STORAGE*>(const_cast<STORAGE*>(right));
|
368
|
+
|
369
|
+
}
|
348
370
|
|
349
371
|
// We may need to upcast our arguments to the same type.
|
350
|
-
dtype_t new_dtype = Upcast[left->dtype][
|
372
|
+
dtype_t new_dtype = Upcast[left->dtype][r->dtype];
|
351
373
|
|
352
374
|
// Make sure we allocate a byte-storing matrix for comparison operations; otherwise, use the argument dtype (new_dtype)
|
353
375
|
dtype_t result_dtype = static_cast<uint8_t>(op) < NUM_NONCOMP_EWOPS ? new_dtype : BYTE;
|
354
376
|
|
355
|
-
|
356
|
-
|
357
|
-
const LIST_STORAGE* l = reinterpret_cast<const LIST_STORAGE*>(left),
|
358
|
-
* r = reinterpret_cast<const LIST_STORAGE*>(right);
|
359
|
-
|
360
|
-
LIST_STORAGE* new_l = NULL;
|
377
|
+
OP_LR_DTYPE_TEMPLATE_TABLE(nm::list_storage::ew_op, void*, LIST* dest, const LIST* left, const void* l_default, const LIST* right, const void* r_default, const size_t* shape, size_t dim);
|
361
378
|
|
362
379
|
// Allocate a new shape array for the resulting matrix.
|
363
|
-
size_t* new_shape = (size_t
|
380
|
+
size_t* new_shape = ALLOC_N(size_t, l->dim);
|
364
381
|
memcpy(new_shape, left->shape, sizeof(size_t) * l->dim);
|
365
382
|
|
366
383
|
// Create the result matrix.
|
@@ -375,14 +392,19 @@ STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE
|
|
375
392
|
new_l = reinterpret_cast<LIST_STORAGE*>(nm_list_storage_cast_copy(l, new_dtype));
|
376
393
|
|
377
394
|
result->default_val =
|
378
|
-
ttable[op][new_l->dtype][
|
395
|
+
ttable[op][new_l->dtype][r->dtype](result->rows, new_l->rows, new_l->default_val, r->rows, r->default_val, result->shape, result->dim);
|
379
396
|
|
380
397
|
// Delete the temporary left-hand side matrix.
|
381
398
|
nm_list_storage_delete(reinterpret_cast<STORAGE*>(new_l));
|
382
|
-
|
399
|
+
|
383
400
|
} else {
|
384
401
|
result->default_val =
|
385
|
-
ttable[op][left->dtype][
|
402
|
+
ttable[op][left->dtype][r->dtype](result->rows, l->rows, l->default_val, r->rows, r->default_val, result->shape, result->dim);
|
403
|
+
}
|
404
|
+
|
405
|
+
// If we created a temporary scalar matrix (for matrix-scalar operations), we now need to delete it.
|
406
|
+
if (cleanup) {
|
407
|
+
nm_list_storage_delete(reinterpret_cast<STORAGE*>(r));
|
386
408
|
}
|
387
409
|
|
388
410
|
return result;
|
data/ext/nmatrix/storage/list.h
CHANGED
@@ -73,7 +73,7 @@ extern "C" {
|
|
73
73
|
// Lifecycle //
|
74
74
|
///////////////
|
75
75
|
|
76
|
-
LIST_STORAGE* nm_list_storage_create(dtype_t dtype, size_t* shape, size_t dim, void* init_val);
|
76
|
+
LIST_STORAGE* nm_list_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, void* init_val);
|
77
77
|
void nm_list_storage_delete(STORAGE* s);
|
78
78
|
void nm_list_storage_delete_ref(STORAGE* s);
|
79
79
|
void nm_list_storage_mark(void*);
|
@@ -97,7 +97,7 @@ extern "C" {
|
|
97
97
|
// Math //
|
98
98
|
//////////
|
99
99
|
|
100
|
-
STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right);
|
100
|
+
STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar);
|
101
101
|
STORAGE* nm_list_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
|
102
102
|
|
103
103
|
|
@@ -121,8 +121,8 @@ extern "C" {
|
|
121
121
|
|
122
122
|
LIST_STORAGE* nm_list_storage_copy(const LIST_STORAGE* rhs);
|
123
123
|
STORAGE* nm_list_storage_copy_transposed(const STORAGE* rhs_base);
|
124
|
-
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, dtype_t new_dtype);
|
125
|
-
VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const dtype_t dtype);
|
124
|
+
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype);
|
125
|
+
VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const nm::dtype_t dtype);
|
126
126
|
|
127
127
|
} // end of extern "C" block
|
128
128
|
|