nmatrix 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +102 -10
- data/README.rdoc +24 -32
- data/Rakefile +1 -1
- data/ext/nmatrix/data/complex.h +9 -0
- data/ext/nmatrix/data/data.cpp +78 -4
- data/ext/nmatrix/data/data.h +86 -54
- data/ext/nmatrix/data/rational.h +2 -0
- data/ext/nmatrix/data/ruby_object.h +38 -8
- data/ext/nmatrix/extconf.rb +13 -7
- data/ext/nmatrix/nmatrix.cpp +262 -139
- data/ext/nmatrix/nmatrix.h +11 -4
- data/ext/nmatrix/storage/common.cpp +20 -13
- data/ext/nmatrix/storage/common.h +18 -12
- data/ext/nmatrix/storage/dense.cpp +122 -192
- data/ext/nmatrix/storage/dense.h +4 -2
- data/ext/nmatrix/storage/list.cpp +467 -636
- data/ext/nmatrix/storage/list.h +6 -3
- data/ext/nmatrix/storage/storage.cpp +83 -46
- data/ext/nmatrix/storage/storage.h +7 -7
- data/ext/nmatrix/storage/yale.cpp +621 -361
- data/ext/nmatrix/storage/yale.h +21 -9
- data/ext/nmatrix/ttable_helper.rb +27 -31
- data/ext/nmatrix/types.h +1 -1
- data/ext/nmatrix/util/math.cpp +9 -10
- data/ext/nmatrix/util/sl_list.cpp +1 -7
- data/ext/nmatrix/util/sl_list.h +0 -118
- data/lib/nmatrix/blas.rb +59 -18
- data/lib/nmatrix/monkeys.rb +0 -52
- data/lib/nmatrix/nmatrix.rb +136 -9
- data/lib/nmatrix/nvector.rb +33 -0
- data/lib/nmatrix/shortcuts.rb +95 -16
- data/lib/nmatrix/version.rb +1 -1
- data/lib/nmatrix/yale_functions.rb +25 -19
- data/spec/blas_spec.rb +1 -19
- data/spec/elementwise_spec.rb +132 -17
- data/spec/lapack_spec.rb +0 -3
- data/spec/nmatrix_list_spec.rb +18 -0
- data/spec/nmatrix_spec.rb +44 -18
- data/spec/nmatrix_yale_spec.rb +1 -3
- data/spec/shortcuts_spec.rb +26 -36
- data/spec/slice_spec.rb +2 -4
- metadata +2 -2
data/ext/nmatrix/storage/list.h
CHANGED
@@ -82,7 +82,7 @@ extern "C" {
|
|
82
82
|
// Accessors //
|
83
83
|
///////////////
|
84
84
|
|
85
|
-
VALUE
|
85
|
+
VALUE nm_list_each_with_indices(VALUE nmatrix, bool stored);
|
86
86
|
void* nm_list_storage_ref(STORAGE* s, SLICE* slice);
|
87
87
|
void* nm_list_storage_get(STORAGE* s, SLICE* slice);
|
88
88
|
void* nm_list_storage_insert(STORAGE* s, SLICE* slice, void* val);
|
@@ -98,7 +98,6 @@ extern "C" {
|
|
98
98
|
// Math //
|
99
99
|
//////////
|
100
100
|
|
101
|
-
STORAGE* nm_list_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar);
|
102
101
|
STORAGE* nm_list_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
|
103
102
|
|
104
103
|
|
@@ -122,9 +121,13 @@ extern "C" {
|
|
122
121
|
|
123
122
|
LIST_STORAGE* nm_list_storage_copy(const LIST_STORAGE* rhs);
|
124
123
|
STORAGE* nm_list_storage_copy_transposed(const STORAGE* rhs_base);
|
125
|
-
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype);
|
124
|
+
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype, void*);
|
126
125
|
VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const nm::dtype_t dtype);
|
127
126
|
|
127
|
+
// Exposed functions
|
128
|
+
VALUE nm_to_hash(VALUE self);
|
129
|
+
VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init);
|
130
|
+
VALUE nm_list_default_value(VALUE self);
|
128
131
|
} // end of extern "C" block
|
129
132
|
|
130
133
|
#endif // LIST_H
|
@@ -161,7 +161,7 @@ DENSE_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype
|
|
161
161
|
for (RIType j = 0; j < rhs->shape[1]; ++j) { // Move to next dense position.
|
162
162
|
|
163
163
|
// Fill in zeros (except for diagonal)
|
164
|
-
if (i == j) lhs_elements[pos] = rhs_a[i];
|
164
|
+
if (i == j) lhs_elements[pos] = static_cast<LDType>(rhs_a[i]);
|
165
165
|
else lhs_elements[pos] = LCAST_ZERO;
|
166
166
|
|
167
167
|
++pos;
|
@@ -173,10 +173,10 @@ DENSE_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype
|
|
173
173
|
|
174
174
|
for (size_t j = 0; j < rhs->shape[1]; ++j) {
|
175
175
|
if (i == j) {
|
176
|
-
lhs_elements[pos] = rhs_a[i];
|
176
|
+
lhs_elements[pos] = static_cast<LDType>(rhs_a[i]);
|
177
177
|
|
178
178
|
} else if (j == jj) {
|
179
|
-
lhs_elements[pos] = rhs_a[ija]; // Copy from rhs.
|
179
|
+
lhs_elements[pos] = static_cast<LDType>(rhs_a[ija]); // Copy from rhs.
|
180
180
|
|
181
181
|
// Get next.
|
182
182
|
++ija;
|
@@ -214,14 +214,14 @@ static void cast_copy_list_contents(LDType* lhs, const LIST* rhs, RDType* defaul
|
|
214
214
|
|
215
215
|
if (!curr || (curr->key > (size_t)(last_key+1))) {
|
216
216
|
|
217
|
-
if (recursions == 0) lhs[pos] = *default_val;
|
217
|
+
if (recursions == 0) lhs[pos] = static_cast<LDType>(*default_val);
|
218
218
|
else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
|
219
219
|
|
220
220
|
++last_key;
|
221
221
|
|
222
222
|
} else {
|
223
223
|
|
224
|
-
if (recursions == 0) lhs[pos] = *reinterpret_cast<RDType*>(curr->val);
|
224
|
+
if (recursions == 0) lhs[pos] = static_cast<LDType>(*reinterpret_cast<RDType*>(curr->val));
|
225
225
|
else cast_copy_list_contents<LDType,RDType>(lhs, (const LIST*)(curr->val),
|
226
226
|
default_val, pos, shape, dim, max_elements, recursions-1);
|
227
227
|
|
@@ -240,7 +240,7 @@ template <typename LDType,typename RDType>
|
|
240
240
|
static void cast_copy_list_default(LDType* lhs, RDType* default_val, size_t& pos, const size_t* shape, size_t dim, size_t max_elements, size_t recursions) {
|
241
241
|
for (size_t i = 0; i < shape[dim - 1 - recursions]; ++i, ++pos) {
|
242
242
|
|
243
|
-
if (recursions == 0) lhs[pos] = *default_val;
|
243
|
+
if (recursions == 0) lhs[pos] = static_cast<LDType>(*default_val);
|
244
244
|
else cast_copy_list_default<LDType,RDType>(lhs, default_val, pos, shape, dim, max_elements, recursions-1);
|
245
245
|
|
246
246
|
}
|
@@ -261,7 +261,7 @@ static bool cast_copy_contents_dense(LIST* lhs, const RDType* rhs, RDType* zero,
|
|
261
261
|
* Creation of list storage from dense storage.
|
262
262
|
*/
|
263
263
|
template <typename LDType, typename RDType>
|
264
|
-
LIST_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype) {
|
264
|
+
LIST_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype, void* init) {
|
265
265
|
|
266
266
|
LDType* l_default_val = ALLOC_N(LDType, 1);
|
267
267
|
RDType* r_default_val = ALLOCA_N(RDType, 1); // clean up when finished with this function
|
@@ -274,13 +274,16 @@ LIST_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtyp
|
|
274
274
|
memset(coords, 0, rhs->dim * sizeof(size_t));
|
275
275
|
|
276
276
|
// set list default_val to 0
|
277
|
-
if (
|
278
|
-
else
|
277
|
+
if (init) *l_default_val = *reinterpret_cast<LDType*>(init);
|
278
|
+
else {
|
279
|
+
if (l_dtype == RUBYOBJ) *l_default_val = INT2FIX(0);
|
280
|
+
else *l_default_val = 0;
|
281
|
+
}
|
279
282
|
|
280
283
|
// need test default value for comparing to elements in dense matrix
|
281
|
-
if (rhs->dtype == l_dtype)
|
282
|
-
else
|
283
|
-
|
284
|
+
if (rhs->dtype == l_dtype || rhs->dtype != RUBYOBJ) *r_default_val = static_cast<RDType>(*l_default_val);
|
285
|
+
else *r_default_val = rubyobj_from_cval(l_default_val, l_dtype);
|
286
|
+
|
284
287
|
|
285
288
|
LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, l_default_val);
|
286
289
|
|
@@ -320,7 +323,7 @@ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype)
|
|
320
323
|
|
321
324
|
// copy default value from the zero location in the Yale matrix
|
322
325
|
LDType* default_val = ALLOC_N(LDType, 1);
|
323
|
-
*default_val = R_ZERO;
|
326
|
+
*default_val = static_cast<LDType>(R_ZERO);
|
324
327
|
|
325
328
|
LIST_STORAGE* lhs = nm_list_storage_create(l_dtype, shape, rhs->dim, default_val);
|
326
329
|
|
@@ -353,8 +356,8 @@ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype)
|
|
353
356
|
// Is there a nonzero diagonal item between the previously added item and the current one?
|
354
357
|
if (jj > i && add_diag) {
|
355
358
|
// Allocate and copy insertion value
|
356
|
-
insert_val
|
357
|
-
*insert_val
|
359
|
+
insert_val = ALLOC_N(LDType, 1);
|
360
|
+
*insert_val = static_cast<LDType>(rhs_a[i]);
|
358
361
|
|
359
362
|
// insert the item in the list at the appropriate location
|
360
363
|
if (last_added) last_added = list::insert_after(last_added, i, insert_val);
|
@@ -366,7 +369,7 @@ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype)
|
|
366
369
|
|
367
370
|
// now allocate and add the current item
|
368
371
|
insert_val = ALLOC_N(LDType, 1);
|
369
|
-
*insert_val = rhs_a[ija];
|
372
|
+
*insert_val = static_cast<LDType>(rhs_a[ija]);
|
370
373
|
|
371
374
|
if (last_added) last_added = list::insert_after(last_added, jj, insert_val);
|
372
375
|
else last_added = list::insert(curr_row, false, jj, insert_val);
|
@@ -376,8 +379,8 @@ LIST_STORAGE* create_from_yale_storage(const YALE_STORAGE* rhs, dtype_t l_dtype)
|
|
376
379
|
|
377
380
|
if (add_diag) {
|
378
381
|
// still haven't added the diagonal.
|
379
|
-
insert_val
|
380
|
-
*insert_val = rhs_a[i];
|
382
|
+
insert_val = ALLOC_N(LDType, 1);
|
383
|
+
*insert_val = static_cast<LDType>(rhs_a[i]);
|
381
384
|
|
382
385
|
// insert the item in the list at the appropriate location
|
383
386
|
if (last_added) last_added = list::insert_after(last_added, i, insert_val);
|
@@ -417,7 +420,7 @@ static bool cast_copy_contents_dense(LIST* lhs, const RDType* rhs, RDType* zero,
|
|
417
420
|
|
418
421
|
// Create a copy of our value that we will insert in the list
|
419
422
|
LDType* insert_value = ALLOC_N(LDType, 1);
|
420
|
-
*insert_value =
|
423
|
+
*insert_value = static_cast<LDType>(rhs[pos]);
|
421
424
|
|
422
425
|
if (!lhs->first) prev = list::insert(lhs, false, coords[dim-1-recursions], insert_value);
|
423
426
|
else prev = list::insert_after(prev, coords[dim-1-recursions], insert_value);
|
@@ -454,16 +457,19 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
454
457
|
* Creation of yale storage from dense storage.
|
455
458
|
*/
|
456
459
|
template <typename LDType, typename RDType, typename LIType>
|
457
|
-
YALE_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype) {
|
460
|
+
YALE_STORAGE* create_from_dense_storage(const DENSE_STORAGE* rhs, dtype_t l_dtype, void* init) {
|
458
461
|
if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
|
459
462
|
|
460
463
|
LIType pos = 0;
|
461
464
|
LIType ndnz = 0;
|
462
465
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
466
|
+
// We need a zero value. This should nearly always be zero, but sometimes you might want false or nil.
|
467
|
+
LDType L_INIT(0);
|
468
|
+
if (init) {
|
469
|
+
if (l_dtype == RUBYOBJ) L_INIT = *reinterpret_cast<VALUE*>(init);
|
470
|
+
else L_INIT = rubyobj_from_cval(init, rhs->dtype);
|
471
|
+
}
|
472
|
+
RDType R_INIT = static_cast<RDType>(L_INIT);
|
467
473
|
|
468
474
|
RDType* rhs_elements = reinterpret_cast<RDType*>(rhs->elements);
|
469
475
|
|
@@ -471,7 +477,7 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
471
477
|
for (size_t i = rhs->shape[0]; i-- > 0;) {
|
472
478
|
for (size_t j = rhs->shape[1]; j-- > 0;) {
|
473
479
|
pos = rhs->stride[0]*(i + rhs->offset[0]) + rhs->stride[1]*(j + rhs->offset[1]);
|
474
|
-
if (i != j && rhs_elements[pos] !=
|
480
|
+
if (i != j && rhs_elements[pos] != R_INIT) ++ndnz;
|
475
481
|
|
476
482
|
// move forward 1 position in dense matrix elements array
|
477
483
|
}
|
@@ -494,7 +500,7 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
494
500
|
LIType* lhs_ija = reinterpret_cast<LIType*>(lhs->ija);
|
495
501
|
|
496
502
|
// Set the zero position in the yale matrix
|
497
|
-
lhs_a[shape[0]]
|
503
|
+
lhs_a[shape[0]] = L_INIT;
|
498
504
|
|
499
505
|
// Start just after the zero position.
|
500
506
|
LIType ija = shape[0]+1;
|
@@ -510,11 +516,10 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
510
516
|
pos = rhs->stride[0]*(i + rhs->offset[0]) + rhs->stride[1]*(j + rhs->offset[1]); // calc position with offsets
|
511
517
|
|
512
518
|
if (i == j) { // copy to diagonal
|
513
|
-
lhs_a[i]
|
514
|
-
} else if (rhs_elements[pos] !=
|
519
|
+
lhs_a[i] = static_cast<LDType>(rhs_elements[pos]);
|
520
|
+
} else if (rhs_elements[pos] != R_INIT) { // copy nonzero to LU
|
515
521
|
lhs_ija[ija] = j; // write column index
|
516
|
-
|
517
|
-
lhs_a[ija] = rhs_elements[pos];
|
522
|
+
lhs_a[ija] = static_cast<LDType>(rhs_elements[pos]);
|
518
523
|
|
519
524
|
++ija;
|
520
525
|
}
|
@@ -534,9 +539,12 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
534
539
|
YALE_STORAGE* create_from_list_storage(const LIST_STORAGE* rhs, nm::dtype_t l_dtype) {
|
535
540
|
if (rhs->dim != 2) rb_raise(nm_eStorageTypeError, "can only convert matrices of dim 2 to yale");
|
536
541
|
|
537
|
-
if (
|
538
|
-
|
539
|
-
|
542
|
+
if (rhs->dtype == RUBYOBJ) {
|
543
|
+
VALUE init_val = *reinterpret_cast<VALUE*>(rhs->default_val);
|
544
|
+
if (rb_funcall(init_val, rb_intern("!="), 1, Qnil) == Qtrue && rb_funcall(init_val, rb_intern("!="), 1, Qfalse) == Qtrue && rb_funcall(init_val, rb_intern("!="), 1, INT2FIX(0)) == Qtrue)
|
545
|
+
rb_raise(nm_eStorageTypeError, "list matrix of Ruby objects must have default value equal to 0, nil, or false to convert to yale");
|
546
|
+
} else if (strncmp(reinterpret_cast<const char*>(rhs->default_val), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", DTYPE_SIZES[rhs->dtype]))
|
547
|
+
rb_raise(nm_eStorageTypeError, "list matrix of non-Ruby objects must have default value of 0 to convert to yale");
|
540
548
|
|
541
549
|
|
542
550
|
size_t ndnz = nm_list_storage_count_nd_elements(rhs);
|
@@ -552,7 +560,7 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
552
560
|
rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", (unsigned long)request_capacity, (unsigned long)(lhs->capacity));
|
553
561
|
|
554
562
|
// Initialize the A and IJA arrays
|
555
|
-
init<LDType,LIType>(lhs);
|
563
|
+
init<LDType,LIType>(lhs, rhs->default_val);
|
556
564
|
|
557
565
|
LIType* lhs_ija = reinterpret_cast<LIType*>(lhs->ija);
|
558
566
|
LDType* lhs_a = reinterpret_cast<LDType*>(lhs->a);
|
@@ -602,7 +610,6 @@ namespace yale_storage { // FIXME: Move to yale.cpp
|
|
602
610
|
|
603
611
|
extern "C" {
|
604
612
|
|
605
|
-
|
606
613
|
/*
|
607
614
|
* The following functions represent stype casts -- conversions from one
|
608
615
|
* stype to another. Each of these is the C accessor for a templated C++
|
@@ -610,47 +617,77 @@ extern "C" {
|
|
610
617
|
*/
|
611
618
|
|
612
619
|
|
613
|
-
|
614
|
-
|
615
|
-
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_dense_storage, YALE_STORAGE*, const DENSE_STORAGE* rhs, nm::dtype_t l_dtype);
|
620
|
+
STORAGE* nm_yale_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void* init) {
|
621
|
+
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_dense_storage, YALE_STORAGE*, const DENSE_STORAGE* rhs, nm::dtype_t l_dtype, void*);
|
616
622
|
|
617
623
|
nm::itype_t itype = nm_yale_storage_default_itype((const YALE_STORAGE*)right);
|
618
624
|
|
619
|
-
|
625
|
+
if (!ttable[l_dtype][right->dtype][itype]) {
|
626
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
627
|
+
return NULL;
|
628
|
+
}
|
629
|
+
|
630
|
+
return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const DENSE_STORAGE*)right, l_dtype, init);
|
620
631
|
}
|
621
632
|
|
622
|
-
STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype) {
|
633
|
+
STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
|
623
634
|
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::create_from_list_storage, YALE_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t l_dtype);
|
624
635
|
|
625
636
|
nm::itype_t itype = nm_yale_storage_default_itype((const YALE_STORAGE*)right);
|
626
637
|
|
638
|
+
if (!ttable[l_dtype][right->dtype][itype]) {
|
639
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
640
|
+
return NULL;
|
641
|
+
}
|
642
|
+
|
627
643
|
return (STORAGE*)ttable[l_dtype][right->dtype][itype]((const LIST_STORAGE*)right, l_dtype);
|
628
644
|
}
|
629
645
|
|
630
|
-
STORAGE* nm_dense_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype) {
|
646
|
+
STORAGE* nm_dense_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
|
631
647
|
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_list_storage, DENSE_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t l_dtype);
|
632
648
|
|
649
|
+
if (!ttable[l_dtype][right->dtype]) {
|
650
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
651
|
+
return NULL;
|
652
|
+
}
|
653
|
+
|
633
654
|
return (STORAGE*)ttable[l_dtype][right->dtype]((const LIST_STORAGE*)right, l_dtype);
|
634
655
|
}
|
635
656
|
|
636
|
-
STORAGE* nm_dense_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype) {
|
657
|
+
STORAGE* nm_dense_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
|
637
658
|
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::create_from_yale_storage, DENSE_STORAGE*, const YALE_STORAGE* rhs, nm::dtype_t l_dtype);
|
638
659
|
|
639
660
|
const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
|
661
|
+
|
662
|
+
if (!ttable[l_dtype][right->dtype][casted_right->itype]) {
|
663
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
664
|
+
return NULL;
|
665
|
+
}
|
666
|
+
|
640
667
|
return reinterpret_cast<STORAGE*>(ttable[l_dtype][right->dtype][casted_right->itype](casted_right, l_dtype));
|
641
668
|
}
|
642
669
|
|
643
|
-
STORAGE* nm_list_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype) {
|
644
|
-
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_dense_storage, LIST_STORAGE*, const DENSE_STORAGE*, nm::dtype_t);
|
670
|
+
STORAGE* nm_list_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void* init) {
|
671
|
+
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_dense_storage, LIST_STORAGE*, const DENSE_STORAGE*, nm::dtype_t, void*);
|
672
|
+
|
673
|
+
if (!ttable[l_dtype][right->dtype]) {
|
674
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
675
|
+
return NULL;
|
676
|
+
}
|
645
677
|
|
646
|
-
return (STORAGE*)ttable[l_dtype][right->dtype]((DENSE_STORAGE*)right, l_dtype);
|
678
|
+
return (STORAGE*)ttable[l_dtype][right->dtype]((DENSE_STORAGE*)right, l_dtype, init);
|
647
679
|
}
|
648
680
|
|
649
|
-
STORAGE* nm_list_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype) {
|
681
|
+
STORAGE* nm_list_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void* dummy) {
|
650
682
|
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::create_from_yale_storage, LIST_STORAGE*, const YALE_STORAGE* rhs, nm::dtype_t l_dtype);
|
651
683
|
|
652
684
|
const YALE_STORAGE* casted_right = reinterpret_cast<const YALE_STORAGE*>(right);
|
653
685
|
|
686
|
+
if (!ttable[l_dtype][right->dtype][casted_right->itype]) {
|
687
|
+
rb_raise(nm_eDataTypeError, "casting between these dtypes is undefined");
|
688
|
+
return NULL;
|
689
|
+
}
|
690
|
+
|
654
691
|
return (STORAGE*)ttable[l_dtype][right->dtype][casted_right->itype](casted_right, l_dtype);
|
655
692
|
}
|
656
693
|
|
@@ -34,7 +34,7 @@
|
|
34
34
|
* Standard Includes
|
35
35
|
*/
|
36
36
|
|
37
|
-
#include <
|
37
|
+
#include <cstdlib>
|
38
38
|
|
39
39
|
/*
|
40
40
|
* Project Includes
|
@@ -86,12 +86,12 @@ extern "C" {
|
|
86
86
|
// Copying and Casting //
|
87
87
|
/////////////////////////
|
88
88
|
|
89
|
-
STORAGE* nm_dense_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype);
|
90
|
-
STORAGE* nm_dense_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype);
|
91
|
-
STORAGE* nm_list_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype);
|
92
|
-
STORAGE* nm_list_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype);
|
93
|
-
STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype);
|
94
|
-
STORAGE* nm_yale_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype);
|
89
|
+
STORAGE* nm_dense_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
90
|
+
STORAGE* nm_dense_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
91
|
+
STORAGE* nm_list_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
92
|
+
STORAGE* nm_list_storage_from_yale(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
93
|
+
STORAGE* nm_yale_storage_from_list(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
94
|
+
STORAGE* nm_yale_storage_from_dense(const STORAGE* right, nm::dtype_t l_dtype, void*);
|
95
95
|
|
96
96
|
} // end of extern "C" block
|
97
97
|
|
@@ -43,6 +43,11 @@
|
|
43
43
|
#include <algorithm> // std::min
|
44
44
|
#include <cstdio> // std::fprintf
|
45
45
|
#include <iostream>
|
46
|
+
#include <array>
|
47
|
+
|
48
|
+
#define RB_P(OBJ) \
|
49
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("object_id"), 0)); \
|
50
|
+
rb_funcall(rb_stderr, rb_intern("puts"), 1, rb_funcall(OBJ, rb_intern("inspect"), 0));
|
46
51
|
|
47
52
|
/*
|
48
53
|
* Project Includes
|
@@ -81,6 +86,9 @@ extern "C" {
|
|
81
86
|
static YALE_STORAGE* nm_copy_alloc_struct(const YALE_STORAGE* rhs, const nm::dtype_t new_dtype, const size_t new_capacity, const size_t new_size);
|
82
87
|
static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim, nm::itype_t min_itype);
|
83
88
|
|
89
|
+
static void* default_value_ptr(const YALE_STORAGE* s);
|
90
|
+
static VALUE default_value(const YALE_STORAGE* s);
|
91
|
+
|
84
92
|
/* Ruby-accessible functions */
|
85
93
|
static VALUE nm_size(VALUE self);
|
86
94
|
static VALUE nm_a(int argc, VALUE* argv, VALUE self);
|
@@ -91,7 +99,6 @@ extern "C" {
|
|
91
99
|
static VALUE nm_ija(int argc, VALUE* argv, VALUE self);
|
92
100
|
|
93
101
|
static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self);
|
94
|
-
static VALUE nm_vector_insert(int argc, VALUE* argv, VALUE self);
|
95
102
|
|
96
103
|
|
97
104
|
} // end extern "C" block
|
@@ -107,6 +114,9 @@ static bool ndrow_eqeq_ndrow(const YALE_STORAGE* l, const YALE_STORAGE* r,
|
|
107
114
|
template <typename LDType, typename RDType, typename IType>
|
108
115
|
static bool eqeq(const YALE_STORAGE* left, const YALE_STORAGE* right);
|
109
116
|
|
117
|
+
template <typename LDType, typename RDType, typename IType>
|
118
|
+
static bool eqeq_different_defaults(const YALE_STORAGE* s, const LDType& s_init, const YALE_STORAGE* t, const RDType& t_init);
|
119
|
+
|
110
120
|
template <typename IType>
|
111
121
|
static YALE_STORAGE* copy_alloc_struct(const YALE_STORAGE* rhs, const dtype_t new_dtype, const size_t new_capacity, const size_t new_size);
|
112
122
|
|
@@ -127,8 +137,6 @@ static char vector_insert(YALE_STORAGE* s, size_t pos, size_t* j, void
|
|
127
137
|
template <typename DType, typename IType>
|
128
138
|
static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t pos, size_t* j, size_t n, bool struct_only);
|
129
139
|
|
130
|
-
template <typename nm::ewop_t op, typename IType, typename DType>
|
131
|
-
YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t dtype);
|
132
140
|
|
133
141
|
/*
|
134
142
|
* Functions
|
@@ -239,7 +247,7 @@ YALE_STORAGE* create_from_old_yale(dtype_t dtype, size_t* shape, void* r_ia, voi
|
|
239
247
|
* Uses the left as a template for the creation of a new one.
|
240
248
|
*/
|
241
249
|
template <typename DType, typename IType>
|
242
|
-
YALE_STORAGE*
|
250
|
+
YALE_STORAGE* create_merged__(const YALE_STORAGE* left, const YALE_STORAGE* right) {
|
243
251
|
char ins_type;
|
244
252
|
|
245
253
|
size_t size = get_size<IType>(left);
|
@@ -305,7 +313,7 @@ YALE_STORAGE* create_merged(const YALE_STORAGE* left, const YALE_STORAGE* right)
|
|
305
313
|
* Called when most YALE_STORAGE objects are created.
|
306
314
|
*/
|
307
315
|
template <typename DType, typename IType>
|
308
|
-
void init(YALE_STORAGE* s) {
|
316
|
+
void init(YALE_STORAGE* s, void* init_val) {
|
309
317
|
IType IA_INIT = s->shape[0] + 1;
|
310
318
|
|
311
319
|
IType* ija = reinterpret_cast<IType*>(s->ija);
|
@@ -314,7 +322,7 @@ void init(YALE_STORAGE* s) {
|
|
314
322
|
ija[i] = IA_INIT; // set initial values for IJA
|
315
323
|
}
|
316
324
|
|
317
|
-
clear_diagonal_and_zero<DType>(s);
|
325
|
+
clear_diagonal_and_zero<DType>(s, init_val);
|
318
326
|
}
|
319
327
|
|
320
328
|
size_t max_size(YALE_STORAGE* s) {
|
@@ -376,7 +384,7 @@ void* get(YALE_STORAGE* storage, SLICE* slice) {
|
|
376
384
|
rb_raise(nm_eStorageTypeError, "conversion failed; capacity of %ld requested, max allowable is %ld", request_capacity, ns->capacity);
|
377
385
|
|
378
386
|
// Initialize the A and IJA arrays
|
379
|
-
init<DType,IType>(ns);
|
387
|
+
init<DType,IType>(ns, default_value_ptr(storage));
|
380
388
|
IType* dst_ija = reinterpret_cast<IType*>(ns->ija);
|
381
389
|
DType* dst_a = reinterpret_cast<DType*>(ns->a);
|
382
390
|
|
@@ -516,6 +524,13 @@ char set(YALE_STORAGE* storage, SLICE* slice, void* value) {
|
|
516
524
|
*/
|
517
525
|
template <typename LDType, typename RDType, typename IType>
|
518
526
|
static bool eqeq(const YALE_STORAGE* left, const YALE_STORAGE* right) {
|
527
|
+
LDType l_init = reinterpret_cast<LDType*>(left->a )[left->shape[0] ];
|
528
|
+
RDType r_init = reinterpret_cast<RDType*>(right->a)[right->shape[0]];
|
529
|
+
|
530
|
+
// If the defaults are different between the two matrices, or if slicing is involved, use this other function instead:
|
531
|
+
if (l_init != r_init || left->src != left || right->src != right)
|
532
|
+
return eqeq_different_defaults<LDType,RDType,IType>(left, l_init, right, r_init);
|
533
|
+
|
519
534
|
LDType* la = reinterpret_cast<LDType*>(left->a);
|
520
535
|
RDType* ra = reinterpret_cast<RDType*>(right->a);
|
521
536
|
|
@@ -555,6 +570,8 @@ static bool eqeq(const YALE_STORAGE* left, const YALE_STORAGE* right) {
|
|
555
570
|
return true;
|
556
571
|
}
|
557
572
|
|
573
|
+
|
574
|
+
|
558
575
|
/*
|
559
576
|
* Are two non-diagonal rows the same? We already know.
|
560
577
|
*/
|
@@ -573,6 +590,9 @@ static bool ndrow_eqeq_ndrow(const YALE_STORAGE* l, const YALE_STORAGE* r, IType
|
|
573
590
|
|
574
591
|
IType ja = std::min(l_ja, r_ja);
|
575
592
|
|
593
|
+
LDType LZERO = la[l->shape[0]];
|
594
|
+
RDType RZERO = ra[r->shape[0]];
|
595
|
+
|
576
596
|
while (!(l_no_more && r_no_more)) {
|
577
597
|
if (l_ja == r_ja) {
|
578
598
|
|
@@ -599,7 +619,7 @@ static bool ndrow_eqeq_ndrow(const YALE_STORAGE* l, const YALE_STORAGE* r, IType
|
|
599
619
|
|
600
620
|
} else if (l_no_more || ja < l_ja) {
|
601
621
|
|
602
|
-
if (ra[r_ija] !=
|
622
|
+
if (ra[r_ija] != RZERO) return false;
|
603
623
|
|
604
624
|
++r_ija;
|
605
625
|
if (r_ija < r_ija_next) {
|
@@ -613,7 +633,7 @@ static bool ndrow_eqeq_ndrow(const YALE_STORAGE* l, const YALE_STORAGE* r, IType
|
|
613
633
|
|
614
634
|
} else if (r_no_more || ja < r_ja) {
|
615
635
|
|
616
|
-
if (la[l_ija] !=
|
636
|
+
if (la[l_ija] != LZERO) return false;
|
617
637
|
|
618
638
|
++l_ija;
|
619
639
|
if (l_ija < l_ija_next) {
|
@@ -658,243 +678,6 @@ static bool ndrow_is_empty(const YALE_STORAGE* s, IType ija, const IType ija_nex
|
|
658
678
|
#define YALE_IJ(s) (reinterpret_cast<IType*>(s->ija) + s->shape[0] + 1)
|
659
679
|
#define YALE_COUNT(yale) (yale->ndnz + yale->shape[0])
|
660
680
|
|
661
|
-
template <typename nm::ewop_t op, typename IType, typename DType>
|
662
|
-
YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t dtype) {
|
663
|
-
size_t init_capacity;
|
664
|
-
size_t* new_shape;
|
665
|
-
|
666
|
-
unsigned int da_index,
|
667
|
-
la_index,
|
668
|
-
ra_index,
|
669
|
-
|
670
|
-
a_index_offset,
|
671
|
-
|
672
|
-
la_row_max,
|
673
|
-
ra_row_max,
|
674
|
-
|
675
|
-
row_index;
|
676
|
-
|
677
|
-
DType tmp_result;
|
678
|
-
|
679
|
-
DType * la = reinterpret_cast<DType*> (left->a),
|
680
|
-
* ra = reinterpret_cast<DType*>(right->a),
|
681
|
-
* da;
|
682
|
-
|
683
|
-
YALE_STORAGE* dest;
|
684
|
-
|
685
|
-
new_shape = reinterpret_cast<size_t*>(ALLOC_N(size_t, 2));
|
686
|
-
new_shape[0] = left->shape[0];
|
687
|
-
new_shape[1] = left->shape[1];
|
688
|
-
|
689
|
-
init_capacity = std::min(left->ndnz + right->ndnz + new_shape[0], new_shape[0] * new_shape[1]);
|
690
|
-
|
691
|
-
dest = nm_yale_storage_create(dtype, new_shape, 2, init_capacity, left->itype);
|
692
|
-
da = reinterpret_cast<DType*>(dest->a);
|
693
|
-
|
694
|
-
// Calculate diagonal values.
|
695
|
-
for (da_index = 0; da_index < dest->shape[0]; ++da_index) {
|
696
|
-
da[da_index] = ew_op_switch<op, DType, DType>(la[da_index], ra[da_index]);
|
697
|
-
}
|
698
|
-
|
699
|
-
// Set the zero representation seperator.
|
700
|
-
da[da_index] = typeid(DType) == typeid(RubyObject) ? INT2FIX(0) : 0;
|
701
|
-
|
702
|
-
/*
|
703
|
-
* Calculate the offset between start of the A arrays and the non-diagonal
|
704
|
-
* entries.
|
705
|
-
*/
|
706
|
-
a_index_offset = dest->shape[0] + 1;
|
707
|
-
|
708
|
-
// Re-base the A arrays.
|
709
|
-
la = la + a_index_offset;
|
710
|
-
ra = ra + a_index_offset;
|
711
|
-
da = da + a_index_offset;
|
712
|
-
|
713
|
-
// Initialize our A array indices.
|
714
|
-
la_index = ra_index = da_index = 0;
|
715
|
-
|
716
|
-
// Calculate the non-diagonal values.
|
717
|
-
for (row_index = 0; row_index < dest->shape[0]; ++row_index) {
|
718
|
-
/*
|
719
|
-
* Each row.
|
720
|
-
*/
|
721
|
-
|
722
|
-
printf("Row %d\n", row_index);
|
723
|
-
|
724
|
-
// Get row bounds.
|
725
|
-
la_row_max = YALE_IA( left)[row_index + 1] - a_index_offset;
|
726
|
-
ra_row_max = YALE_IA(right)[row_index + 1] - a_index_offset;
|
727
|
-
|
728
|
-
printf("Left : Row Start: %d - Row End %d\n", la_index + a_index_offset, la_row_max + a_index_offset);
|
729
|
-
printf("Right : Row Start: %d - Row End %d\n", ra_index + a_index_offset, ra_row_max + a_index_offset);
|
730
|
-
|
731
|
-
/*
|
732
|
-
* Set this row's left bound (which is also the previous row's right
|
733
|
-
* bound).
|
734
|
-
*/
|
735
|
-
YALE_IA(dest)[row_index] = da_index + a_index_offset;
|
736
|
-
|
737
|
-
printf("Left bound of row %d in destination: %d\n", (int)row_index, (int)YALE_IA(dest)[row_index]);
|
738
|
-
|
739
|
-
// Iterate over non-diagonal entries in this row.
|
740
|
-
while (la_index < la_row_max and ra_index < ra_row_max) {
|
741
|
-
/*
|
742
|
-
* Elements are present on both the left- and right-hand side.
|
743
|
-
*/
|
744
|
-
|
745
|
-
printf("Marker 0\n");
|
746
|
-
|
747
|
-
if (YALE_IJ(left)[la_index] == YALE_IJ(right)[ra_index]) {
|
748
|
-
/*
|
749
|
-
* Current left- and right-hand values are in the same row and
|
750
|
-
* column.
|
751
|
-
*/
|
752
|
-
|
753
|
-
printf("Calculating value for [%d, %d].\n", (int)row_index, (int)YALE_IJ(left)[la_index]);
|
754
|
-
|
755
|
-
tmp_result = ew_op_switch<op, DType, DType>(la[la_index], ra[ra_index]);
|
756
|
-
|
757
|
-
if (tmp_result != 0) {
|
758
|
-
printf("Setting value for [%d, %d] at index %d in destination's A array.\n", (int)row_index, (int)YALE_IJ(left)[la_index], (int)(da_index + a_index_offset));
|
759
|
-
|
760
|
-
da[da_index] = tmp_result;
|
761
|
-
YALE_IJ(dest)[da_index] = YALE_IJ(left)[la_index];
|
762
|
-
|
763
|
-
++da_index;
|
764
|
-
|
765
|
-
} else {
|
766
|
-
printf("Result was 0. Skipping.\n");
|
767
|
-
}
|
768
|
-
|
769
|
-
++la_index;
|
770
|
-
++ra_index;
|
771
|
-
|
772
|
-
} else if (YALE_IJ(left)[la_index] < YALE_IJ(right)[ra_index]) {
|
773
|
-
/*
|
774
|
-
* The right-hand index is ahead of the left-hand index.
|
775
|
-
*/
|
776
|
-
|
777
|
-
if (op != EW_MUL) {
|
778
|
-
// If this is multiplion there is no point in doing the operation.
|
779
|
-
|
780
|
-
tmp_result = ew_op_switch<op, DType, DType>(la[la_index], typeid(DType) == typeid(RubyObject) ? INT2FIX(0) : 0);
|
781
|
-
|
782
|
-
printf("Setting value for [%d, %d].\n", (int)row_index, (int)YALE_IJ(left)[la_index]);
|
783
|
-
|
784
|
-
if (tmp_result != 0) {
|
785
|
-
da[da_index] = tmp_result;
|
786
|
-
YALE_IJ(dest)[da_index] = YALE_IJ(left)[la_index];
|
787
|
-
|
788
|
-
++da_index;
|
789
|
-
}
|
790
|
-
}
|
791
|
-
|
792
|
-
++la_index;
|
793
|
-
|
794
|
-
} else {
|
795
|
-
/*
|
796
|
-
* The left-hand index is ahead of the right-hand index.
|
797
|
-
*/
|
798
|
-
|
799
|
-
if (op != EW_MUL) {
|
800
|
-
// If this is multiplion there is no point in doing the operation.
|
801
|
-
|
802
|
-
tmp_result = ew_op_switch<op, DType, DType>(typeid(DType) == typeid(RubyObject) ? INT2FIX(0) : 0, ra[ra_index]);
|
803
|
-
|
804
|
-
printf("Setting value for [%d, %d].\n", (int)row_index, (int)YALE_IJ(right)[ra_index]);
|
805
|
-
|
806
|
-
if (tmp_result != 0) {
|
807
|
-
da[da_index] = tmp_result;
|
808
|
-
YALE_IJ(dest)[da_index] = YALE_IJ(right)[ra_index];
|
809
|
-
|
810
|
-
++da_index;
|
811
|
-
}
|
812
|
-
}
|
813
|
-
|
814
|
-
++ra_index;
|
815
|
-
}
|
816
|
-
}
|
817
|
-
|
818
|
-
if (op != EW_MUL) {
|
819
|
-
/*
|
820
|
-
* Process the remaining elements on the left- or right-hand side. One or
|
821
|
-
* the other, or neither, of the following loops may execute, but not
|
822
|
-
* both.
|
823
|
-
*
|
824
|
-
* If we are doing multiplication this is unnecessary as all remaining
|
825
|
-
* operations will produce a zero value.
|
826
|
-
*/
|
827
|
-
|
828
|
-
while (la_index < la_row_max) {
|
829
|
-
/*
|
830
|
-
* Process the remaining elements on the left-hand side.
|
831
|
-
*/
|
832
|
-
|
833
|
-
printf("Marker 1\n");
|
834
|
-
|
835
|
-
tmp_result = ew_op_switch<op, DType, DType>(la[la_index], typeid(DType) == typeid(RubyObject) ? INT2FIX(0) : 0);
|
836
|
-
|
837
|
-
printf("Setting value for [%d, %d].\n", (int)row_index, (int)YALE_IJ(left)[la_index]);
|
838
|
-
|
839
|
-
if (tmp_result != 0) {
|
840
|
-
da[da_index] = tmp_result;
|
841
|
-
YALE_IJ(dest)[da_index] = YALE_IJ(left)[la_index];
|
842
|
-
|
843
|
-
++da_index;
|
844
|
-
}
|
845
|
-
|
846
|
-
++la_index;
|
847
|
-
}
|
848
|
-
|
849
|
-
while (ra_index < ra_row_max) {
|
850
|
-
/*
|
851
|
-
* Process the remaining elements on the right-hand side.
|
852
|
-
*/
|
853
|
-
|
854
|
-
printf("Marker 2\n");
|
855
|
-
|
856
|
-
tmp_result = ew_op_switch<op, DType, DType>(typeid(DType) == typeid(RubyObject) ? INT2FIX(0) : 0, ra[ra_index]);
|
857
|
-
|
858
|
-
printf("Setting value for [%d, %d].\n", (int)row_index, (int)YALE_IJ(right)[ra_index]);
|
859
|
-
|
860
|
-
if (tmp_result != 0) {
|
861
|
-
da[da_index] = tmp_result;
|
862
|
-
YALE_IJ(dest)[da_index] = YALE_IJ(right)[ra_index];
|
863
|
-
|
864
|
-
++da_index;
|
865
|
-
}
|
866
|
-
|
867
|
-
++ra_index;
|
868
|
-
}
|
869
|
-
}
|
870
|
-
|
871
|
-
// Advance the row indices.
|
872
|
-
la_index = la_row_max;
|
873
|
-
ra_index = ra_row_max;
|
874
|
-
|
875
|
-
printf("End of row %d\n\n", row_index);
|
876
|
-
}
|
877
|
-
|
878
|
-
// Set the last row's right bound.
|
879
|
-
YALE_IA(dest)[row_index] = da_index + a_index_offset;
|
880
|
-
|
881
|
-
printf("Right bound of row %d in destination: %d\n", row_index - 1, da_index + a_index_offset);
|
882
|
-
|
883
|
-
// Set the number of non-diagonal non-zero entries in the destination matrix.
|
884
|
-
dest->ndnz = da_index;
|
885
|
-
|
886
|
-
printf("Number of non-diagonal non-zero entries: %ld\n\n", (unsigned long)(dest->ndnz));
|
887
|
-
|
888
|
-
// Set the capacity of the destination matrix.
|
889
|
-
dest->capacity = dest->shape[0] + dest->ndnz + 1;
|
890
|
-
|
891
|
-
// Resize the destination matrix.
|
892
|
-
dest->a = realloc(dest->a, sizeof(DType) * dest->capacity);
|
893
|
-
dest->ija = realloc(dest->ija, sizeof(IType) * dest->capacity);
|
894
|
-
|
895
|
-
return dest;
|
896
|
-
}
|
897
|
-
|
898
681
|
/////////////
|
899
682
|
// Utility //
|
900
683
|
/////////////
|
@@ -923,6 +706,36 @@ int binary_search(YALE_STORAGE* s, IType left, IType right, IType key) {
|
|
923
706
|
}
|
924
707
|
|
925
708
|
|
709
|
+
/*
|
710
|
+
* Resize yale storage vectors A and IJA, copying values.
|
711
|
+
*/
|
712
|
+
static void vector_grow(YALE_STORAGE* s) {
|
713
|
+
size_t new_capacity = s->capacity * GROWTH_CONSTANT;
|
714
|
+
size_t max_capacity = max_size(s);
|
715
|
+
|
716
|
+
if (new_capacity > max_capacity) new_capacity = max_capacity;
|
717
|
+
|
718
|
+
void* new_ija = ALLOC_N(char, ITYPE_SIZES[s->itype] * new_capacity);
|
719
|
+
NM_CHECK_ALLOC(new_ija);
|
720
|
+
|
721
|
+
void* new_a = ALLOC_N(char, DTYPE_SIZES[s->dtype] * new_capacity);
|
722
|
+
NM_CHECK_ALLOC(new_a);
|
723
|
+
|
724
|
+
void* old_ija = s->ija;
|
725
|
+
void* old_a = s->a;
|
726
|
+
|
727
|
+
memcpy(new_ija, old_ija, s->capacity * ITYPE_SIZES[s->itype]);
|
728
|
+
memcpy(new_a, old_a, s->capacity * DTYPE_SIZES[s->dtype]);
|
729
|
+
|
730
|
+
s->capacity = new_capacity;
|
731
|
+
|
732
|
+
xfree(old_ija);
|
733
|
+
xfree(old_a);
|
734
|
+
|
735
|
+
s->ija = new_ija;
|
736
|
+
s->a = new_a;
|
737
|
+
}
|
738
|
+
|
926
739
|
|
927
740
|
/*
|
928
741
|
* Resize yale storage vectors A and IJA in preparation for an insertion.
|
@@ -979,14 +792,12 @@ static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t po
|
|
979
792
|
|
980
793
|
s->capacity = new_capacity;
|
981
794
|
|
982
|
-
|
983
|
-
|
795
|
+
xfree(s->ija);
|
796
|
+
xfree(s->a);
|
984
797
|
|
985
798
|
s->ija = reinterpret_cast<void*>(new_ija);
|
986
799
|
s->a = reinterpret_cast<void*>(new_a);
|
987
800
|
|
988
|
-
fprintf(stderr, "resize\n");
|
989
|
-
|
990
801
|
return 'i';
|
991
802
|
}
|
992
803
|
|
@@ -1145,6 +956,8 @@ static YALE_STORAGE* copy_alloc_struct(const YALE_STORAGE* rhs, const dtype_t ne
|
|
1145
956
|
YALE_STORAGE* lhs = ALLOC( YALE_STORAGE );
|
1146
957
|
lhs->dim = rhs->dim;
|
1147
958
|
lhs->shape = ALLOC_N( size_t, lhs->dim );
|
959
|
+
lhs->offset = ALLOC_N( size_t, lhs->dim );
|
960
|
+
memcpy(lhs->shape, rhs->shape, lhs->dim * sizeof(size_t));
|
1148
961
|
memcpy(lhs->shape, rhs->shape, lhs->dim * sizeof(size_t));
|
1149
962
|
lhs->itype = rhs->itype;
|
1150
963
|
lhs->capacity = new_capacity;
|
@@ -1153,6 +966,7 @@ static YALE_STORAGE* copy_alloc_struct(const YALE_STORAGE* rhs, const dtype_t ne
|
|
1153
966
|
|
1154
967
|
lhs->ija = ALLOC_N( IType, lhs->capacity );
|
1155
968
|
lhs->a = ALLOC_N( char, DTYPE_SIZES[new_dtype] * lhs->capacity );
|
969
|
+
lhs->src = lhs;
|
1156
970
|
|
1157
971
|
// Now copy the contents -- but only within the boundaries set by the size. Leave
|
1158
972
|
// the rest uninitialized.
|
@@ -1176,9 +990,7 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
|
|
1176
990
|
IType* ijl;
|
1177
991
|
if (left->itype == result_itype) ijl = reinterpret_cast<IType*>(left->ija);
|
1178
992
|
else { // make a temporary copy of the IJA vector for L with the correct itype
|
1179
|
-
std::cerr << "changing left itype from " << static_cast<uint8_t>(left->itype) << " to " << static_cast<int8_t>(result_itype) << std::endl;
|
1180
993
|
size_t length = nm_yale_storage_get_size(left);
|
1181
|
-
std::cerr << "length = " << length << std::endl;
|
1182
994
|
ijl = ALLOCA_N(IType, length);
|
1183
995
|
copy_recast_itype_vector(reinterpret_cast<void*>(left->ija), left->itype, reinterpret_cast<void*>(ijl), result_itype, length);
|
1184
996
|
}
|
@@ -1186,9 +998,7 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
|
|
1186
998
|
IType* ijr;
|
1187
999
|
if (right->itype == result_itype) ijr = reinterpret_cast<IType*>(right->ija);
|
1188
1000
|
else { // make a temporary copy of the IJA vector for R with the correct itype
|
1189
|
-
std::cerr << "changing right itype from " << static_cast<uint8_t>(right->itype) << " to " << static_cast<int8_t>(result_itype) << std::endl;
|
1190
1001
|
size_t length = nm_yale_storage_get_size(right);
|
1191
|
-
std::cerr << "length = " << length << std::endl;
|
1192
1002
|
ijr = ALLOCA_N(IType, length);
|
1193
1003
|
copy_recast_itype_vector(reinterpret_cast<void*>(right->ija), right->itype, reinterpret_cast<void*>(ijr), result_itype, length);
|
1194
1004
|
}
|
@@ -1200,7 +1010,7 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
|
|
1200
1010
|
|
1201
1011
|
// Create result storage.
|
1202
1012
|
YALE_STORAGE* result = nm_yale_storage_create(left->dtype, resulting_shape, 2, result_ndnz, result_itype);
|
1203
|
-
init<DType,IType>(result);
|
1013
|
+
init<DType,IType>(result, NULL);
|
1204
1014
|
IType* ija = reinterpret_cast<IType*>(result->ija);
|
1205
1015
|
|
1206
1016
|
// Symbolic multiplication step (build the structure)
|
@@ -1221,28 +1031,395 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
|
|
1221
1031
|
}
|
1222
1032
|
|
1223
1033
|
|
1034
|
+
/*
|
1035
|
+
* Get the sum of offsets from the original matrix (for sliced iteration).
|
1036
|
+
*/
|
1037
|
+
static std::array<size_t,2> get_offsets(YALE_STORAGE* x) {
|
1038
|
+
std::array<size_t, 2> offsets{ {0,0} };
|
1039
|
+
while (x != x->src) {
|
1040
|
+
offsets[0] += x->offset[0];
|
1041
|
+
offsets[1] += x->offset[1];
|
1042
|
+
x = reinterpret_cast<YALE_STORAGE*>(x->src);
|
1043
|
+
}
|
1044
|
+
return offsets;
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
|
1048
|
+
static VALUE obj_at(YALE_STORAGE* s, size_t k) {
|
1049
|
+
if (s->dtype == nm::RUBYOBJ) return reinterpret_cast<VALUE*>(s->a)[k];
|
1050
|
+
else return rubyobj_from_cval(reinterpret_cast<void*>(reinterpret_cast<char*>(s->a) + k * DTYPE_SIZES[s->dtype]), s->dtype).rval;
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
|
1054
|
+
|
1055
|
+
template <typename IType>
|
1056
|
+
class IJAManager {
|
1057
|
+
protected:
|
1058
|
+
bool needs_free;
|
1059
|
+
|
1060
|
+
public:
|
1061
|
+
IType* ija;
|
1062
|
+
|
1063
|
+
IJAManager(YALE_STORAGE* s, itype_t temp_itype) : needs_free(false), ija(reinterpret_cast<IType*>(s->ija)) {
|
1064
|
+
if (s->itype != temp_itype) {
|
1065
|
+
size_t len = nm_yale_storage_get_size(s);
|
1066
|
+
needs_free = true;
|
1067
|
+
ija = ALLOC_N(IType, len);
|
1068
|
+
copy_recast_itype_vector(s->ija, s->itype, reinterpret_cast<void*>(ija), temp_itype, len);
|
1069
|
+
}
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
~IJAManager() {
|
1073
|
+
if (needs_free) xfree(ija);
|
1074
|
+
}
|
1075
|
+
};
|
1076
|
+
|
1077
|
+
|
1078
|
+
template <typename IType>
|
1079
|
+
class RowIterator {
|
1080
|
+
protected:
|
1081
|
+
YALE_STORAGE* s;
|
1082
|
+
IType* ija;
|
1083
|
+
void* a;
|
1084
|
+
IType i, k, k_end;
|
1085
|
+
size_t j_offset, j_shape;
|
1086
|
+
bool diag, End;
|
1087
|
+
VALUE init;
|
1088
|
+
public:
|
1089
|
+
RowIterator(YALE_STORAGE* s_, IType* ija_, IType i_, size_t j_shape_, size_t j_offset_ = 0)
|
1090
|
+
: s(s_),
|
1091
|
+
ija(ija_),
|
1092
|
+
a(s->a),
|
1093
|
+
i(i_),
|
1094
|
+
k(ija[i]),
|
1095
|
+
k_end(ija[i+1]),
|
1096
|
+
j_offset(j_offset_),
|
1097
|
+
j_shape(j_shape_),
|
1098
|
+
diag(row_has_no_nd() || diag_is_first()),
|
1099
|
+
End(false),
|
1100
|
+
init(default_value(s))
|
1101
|
+
{ }
|
1102
|
+
|
1103
|
+
RowIterator(YALE_STORAGE* s_, IType i_, size_t j_shape_, size_t j_offset_ = 0)
|
1104
|
+
: s(s_),
|
1105
|
+
ija(reinterpret_cast<IType*>(s->ija)),
|
1106
|
+
a(s->a),
|
1107
|
+
i(i_),
|
1108
|
+
k(ija[i]),
|
1109
|
+
k_end(ija[i+1]),
|
1110
|
+
j_offset(j_offset_),
|
1111
|
+
j_shape(j_shape_),
|
1112
|
+
diag(row_has_no_nd() || diag_is_first()),
|
1113
|
+
End(false),
|
1114
|
+
init(default_value(s))
|
1115
|
+
{ }
|
1116
|
+
|
1117
|
+
RowIterator(const RowIterator& rhs) : s(rhs.s), ija(rhs.ija), a(s->a), i(rhs.i), k(rhs.k), k_end(rhs.k_end), j_offset(rhs.j_offset), j_shape(rhs.j_shape), diag(rhs.diag), End(rhs.End), init(rhs.init) { }
|
1118
|
+
|
1119
|
+
VALUE obj() const {
|
1120
|
+
return diag ? obj_at(s, i) : obj_at(s, k);
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
template <typename T>
|
1124
|
+
T cobj() const {
|
1125
|
+
if (typeid(T) == typeid(RubyObject)) return obj();
|
1126
|
+
return diag ? reinterpret_cast<T*>(s->a)[i] : reinterpret_cast<T*>(s->a)[k];
|
1127
|
+
}
|
1128
|
+
|
1129
|
+
inline IType proper_j() const {
|
1130
|
+
//if (!diag && k >= s->capacity) {
|
1131
|
+
// std::cerr << "proper_j(): Warning: (nondiag) k exceeded capacity at row " << int(i) << ": k=" << int(k) << ", cap=" << s->capacity << std::endl;
|
1132
|
+
// throw;
|
1133
|
+
//}
|
1134
|
+
return diag ? i : ija[k];
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
inline IType offset_j() const {
|
1138
|
+
return proper_j() - j_offset;
|
1139
|
+
}
|
1140
|
+
|
1141
|
+
/* Returns true if an additional value is inserted, false if it goes on the diagonal */
|
1142
|
+
bool insert(IType j, VALUE v) {
|
1143
|
+
if (j == i) { // insert regardless on diagonal
|
1144
|
+
reinterpret_cast<VALUE*>(a)[j] = v;
|
1145
|
+
return false;
|
1146
|
+
|
1147
|
+
} else {
|
1148
|
+
if (rb_funcall(v, rb_intern("!="), 1, init) == Qtrue) {
|
1149
|
+
if (k >= s->capacity) {
|
1150
|
+
vector_grow(s);
|
1151
|
+
ija = reinterpret_cast<IType*>(s->ija);
|
1152
|
+
a = s->a;
|
1153
|
+
}
|
1154
|
+
reinterpret_cast<VALUE*>(a)[k] = v;
|
1155
|
+
ija[k] = j;
|
1156
|
+
k++;
|
1157
|
+
return true;
|
1158
|
+
}
|
1159
|
+
return false;
|
1160
|
+
}
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
void update_row_end() {
|
1164
|
+
ija[i+1] = k;
|
1165
|
+
k_end = k;
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
/* Past the j_shape? */
|
1169
|
+
inline bool end() const {
|
1170
|
+
if (End) return true;
|
1171
|
+
//if (diag) return i - j_offset >= j_shape;
|
1172
|
+
//else return k >= s->capacity || ija[k] - j_offset >= j_shape;
|
1173
|
+
return (diag ? i : ija[k]) - j_offset >= j_shape;
|
1174
|
+
}
|
1175
|
+
|
1176
|
+
inline bool row_has_no_nd() const { return ija[i] == k_end; /* k_start == k_end */ }
|
1177
|
+
inline bool diag_is_first() const { return i < ija[ija[i]]; }
|
1178
|
+
inline bool diag_is_last() const { return i > ija[k_end-1]; } // only works if !row_has_no_nd()
|
1179
|
+
inline bool k_is_last_nd() const { return k == k_end-1; }
|
1180
|
+
inline bool k_is_last() const { return k_is_last_nd() && !diag_is_last(); }
|
1181
|
+
inline bool diag_is_ahead() const { return i > ija[k]; }
|
1182
|
+
inline bool row_has_diag() const { return i < s->shape[1]; }
|
1183
|
+
inline bool diag_is_next() const { // assumes we've already tested for diag, row_has_no_nd(), diag_is_first()
|
1184
|
+
if (i == ija[k]+1) return true; // definite next
|
1185
|
+
else if (k+1 < k_end && i >= ija[k+1]+1) return false; // at least one item before it
|
1186
|
+
else return true;
|
1187
|
+
}
|
1188
|
+
|
1189
|
+
RowIterator<IType>& operator++() {
|
1190
|
+
if (diag) { // we're at the diagonal
|
1191
|
+
if (row_has_no_nd() || diag_is_last()) End = true; // and there are no non-diagonals (or none still to visit)
|
1192
|
+
diag = false;
|
1193
|
+
} else if (!row_has_diag()) { // row has no diagonal entries
|
1194
|
+
if (row_has_no_nd() || k_is_last_nd()) End = true; // row is totally empty, or we're at last entry
|
1195
|
+
else k++; // still entries to visit
|
1196
|
+
// } else if (row_has_no_nd()) { // in this case we started at diag, so don't check it
|
1197
|
+
} else { // not at diag but it exists somewhere in the row, and row has at least one nd entry
|
1198
|
+
if (diag_is_ahead()) { // diag is ahead
|
1199
|
+
if (k_is_last_nd()) diag = true; // diag is next and last
|
1200
|
+
else if (diag_is_next()) { // diag is next and not last
|
1201
|
+
diag = true;
|
1202
|
+
k++;
|
1203
|
+
} else k++; // diag is not next
|
1204
|
+
} else { // diag is past
|
1205
|
+
if (k_is_last_nd()) End = true; // and we're at the end
|
1206
|
+
else k++; // and we're not at the end
|
1207
|
+
}
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
//if (k >= s->capacity)
|
1211
|
+
// std::cerr << "operator++: Warning: k has exceeded capacity for row " << int(i) << "; k=" << int(k) << ", cap=" << s->capacity << std::endl;
|
1212
|
+
|
1213
|
+
return *this;
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
|
1217
|
+
RowIterator<IType> operator++(int unused) {
|
1218
|
+
RowIterator<IType> x(*this);
|
1219
|
+
++(*this);
|
1220
|
+
return x;
|
1221
|
+
}
|
1222
|
+
};
|
1223
|
+
|
1224
|
+
|
1225
|
+
template <typename IType>
|
1226
|
+
static VALUE map_stored(VALUE self) {
|
1227
|
+
|
1228
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1229
|
+
|
1230
|
+
size_t* shape = ALLOC_N(size_t, 2);
|
1231
|
+
shape[0] = s->shape[0];
|
1232
|
+
shape[1] = s->shape[1];
|
1233
|
+
|
1234
|
+
std::array<size_t,2> s_offsets = get_offsets(s);
|
1235
|
+
|
1236
|
+
RETURN_SIZED_ENUMERATOR(self, 0, 0, nm_yale_enumerator_length);
|
1237
|
+
VALUE init = rb_yield(default_value(s));
|
1238
|
+
|
1239
|
+
YALE_STORAGE* r = nm_yale_storage_create(nm::RUBYOBJ, shape, 2, s->capacity, NM_ITYPE(self));
|
1240
|
+
nm_yale_storage_init(r, &init);
|
1241
|
+
|
1242
|
+
for (IType ri = 0; ri < shape[0]; ++ri) {
|
1243
|
+
RowIterator<IType> sit(s, ri + s_offsets[0], shape[1], s_offsets[1]);
|
1244
|
+
RowIterator<IType> rit(r, ri, shape[1]);
|
1245
|
+
|
1246
|
+
while (!sit.end()) {
|
1247
|
+
VALUE rv = rb_yield(sit.obj());
|
1248
|
+
VALUE rj = sit.offset_j();
|
1249
|
+
rit.insert(rj, rv);
|
1250
|
+
++sit;
|
1251
|
+
}
|
1252
|
+
// Update the row end information.
|
1253
|
+
rit.update_row_end();
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
NMATRIX* m = nm_create(nm::YALE_STORE, reinterpret_cast<STORAGE*>(r));
|
1257
|
+
return Data_Wrap_Struct(CLASS_OF(self), nm_yale_storage_mark, nm_delete, m);
|
1258
|
+
}
|
1259
|
+
|
1260
|
+
|
1261
|
+
/*
|
1262
|
+
* eqeq function for slicing and different defaults.
|
1263
|
+
*/
|
1264
|
+
template <typename LDType, typename RDType, typename IType>
|
1265
|
+
static bool eqeq_different_defaults(const YALE_STORAGE* s, const LDType& s_init, const YALE_STORAGE* t, const RDType& t_init) {
|
1266
|
+
|
1267
|
+
std::array<size_t,2> s_offsets = get_offsets(const_cast<YALE_STORAGE*>(s)),
|
1268
|
+
t_offsets = get_offsets(const_cast<YALE_STORAGE*>(t));
|
1269
|
+
|
1270
|
+
for (IType ri = 0; ri < s->shape[0]; ++ri) {
|
1271
|
+
RowIterator<IType> sit(const_cast<YALE_STORAGE*>(s), reinterpret_cast<IType*>(s->ija), ri + s_offsets[0], s->shape[1], s_offsets[1]);
|
1272
|
+
RowIterator<IType> tit(const_cast<YALE_STORAGE*>(t), reinterpret_cast<IType*>(t->ija), ri + t_offsets[0], s->shape[1], t_offsets[1]);
|
1273
|
+
|
1274
|
+
while (!sit.end() || !tit.end()) {
|
1275
|
+
|
1276
|
+
// Perform the computation. Use a default value if the matrix doesn't have some value stored.
|
1277
|
+
if (tit.end() || (!sit.end() && sit.offset_j() < tit.offset_j())) {
|
1278
|
+
if (sit.template cobj<LDType>() != t_init) return false;
|
1279
|
+
++sit;
|
1280
|
+
|
1281
|
+
} else if (sit.end() || (!tit.end() && sit.offset_j() > tit.offset_j())) {
|
1282
|
+
if (s_init != tit.template cobj<RDType>()) return false;
|
1283
|
+
++tit;
|
1284
|
+
|
1285
|
+
} else { // same index
|
1286
|
+
if (sit.template cobj<LDType>() != tit.template cobj<RDType>()) return false;
|
1287
|
+
++sit;
|
1288
|
+
++tit;
|
1289
|
+
}
|
1290
|
+
}
|
1291
|
+
}
|
1292
|
+
return true;
|
1293
|
+
}
|
1294
|
+
|
1295
|
+
|
1296
|
+
template <typename IType>
|
1297
|
+
static VALUE map_merged_stored(VALUE left, VALUE right, VALUE init, nm::itype_t itype) {
|
1298
|
+
|
1299
|
+
YALE_STORAGE *s = NM_STORAGE_YALE(left),
|
1300
|
+
*t = NM_STORAGE_YALE(right);
|
1301
|
+
|
1302
|
+
size_t* shape = ALLOC_N(size_t, 2);
|
1303
|
+
shape[0] = s->shape[0];
|
1304
|
+
shape[1] = s->shape[1];
|
1305
|
+
|
1306
|
+
std::array<size_t,2> s_offsets = get_offsets(s),
|
1307
|
+
t_offsets = get_offsets(t);
|
1308
|
+
|
1309
|
+
VALUE s_init = default_value(s),
|
1310
|
+
t_init = default_value(t);
|
1311
|
+
|
1312
|
+
RETURN_SIZED_ENUMERATOR(left, 0, 0, 0);
|
1313
|
+
|
1314
|
+
if (init == Qnil)
|
1315
|
+
init = rb_yield_values(2, s_init, t_init);
|
1316
|
+
|
1317
|
+
YALE_STORAGE* r = nm_yale_storage_create(nm::RUBYOBJ, shape, 2, NM_MAX(s->capacity, t->capacity), itype);
|
1318
|
+
nm_yale_storage_init(r, &init);
|
1319
|
+
|
1320
|
+
IJAManager<IType> sm(s, itype),
|
1321
|
+
tm(t, itype);
|
1322
|
+
|
1323
|
+
for (IType ri = 0; ri < shape[0]; ++ri) {
|
1324
|
+
RowIterator<IType> sit(s, sm.ija, ri + s_offsets[0], shape[1], s_offsets[1]);
|
1325
|
+
RowIterator<IType> tit(t, tm.ija, ri + t_offsets[0], shape[1], t_offsets[1]);
|
1326
|
+
|
1327
|
+
RowIterator<IType> rit(r, reinterpret_cast<IType*>(r->ija), ri, shape[1]);
|
1328
|
+
while (!rit.end() && (!sit.end() || !tit.end())) {
|
1329
|
+
VALUE rv;
|
1330
|
+
IType rj;
|
1331
|
+
|
1332
|
+
// Perform the computation. Use a default value if the matrix doesn't have some value stored.
|
1333
|
+
if (tit.end() || (!sit.end() && sit.offset_j() < tit.offset_j())) {
|
1334
|
+
rv = rb_yield_values(2, sit.obj(), t_init);
|
1335
|
+
rj = sit.offset_j();
|
1336
|
+
++sit;
|
1337
|
+
|
1338
|
+
} else if (sit.end() || (!tit.end() && sit.offset_j() > tit.offset_j())) {
|
1339
|
+
rv = rb_yield_values(2, s_init, tit.obj());
|
1340
|
+
rj = tit.offset_j();
|
1341
|
+
++tit;
|
1342
|
+
|
1343
|
+
} else { // same index
|
1344
|
+
rv = rb_yield_values(2, sit.obj(), tit.obj());
|
1345
|
+
rj = sit.offset_j();
|
1346
|
+
++sit;
|
1347
|
+
++tit;
|
1348
|
+
}
|
1349
|
+
|
1350
|
+
rit.insert(rj, rv); // handles increment (and testing for default, etc)
|
1351
|
+
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
// Update the row end information.
|
1355
|
+
rit.update_row_end();
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
NMATRIX* m = nm_create(nm::YALE_STORE, reinterpret_cast<STORAGE*>(r));
|
1359
|
+
return Data_Wrap_Struct(CLASS_OF(left), nm_yale_storage_mark, nm_delete, m);
|
1360
|
+
}
|
1361
|
+
|
1362
|
+
|
1224
1363
|
} // end of namespace nm::yale_storage
|
1225
1364
|
|
1226
1365
|
|
1227
1366
|
// Helper function used only for the RETURN_SIZED_ENUMERATOR macro. Returns the length of
|
1228
1367
|
// the matrix's storage.
|
1229
|
-
static VALUE
|
1368
|
+
static VALUE nm_yale_stored_enumerator_length(VALUE nmatrix) {
|
1230
1369
|
long len = nm_yale_storage_get_size(NM_STORAGE_YALE(nmatrix));
|
1231
1370
|
return LONG2NUM(len);
|
1232
1371
|
}
|
1233
1372
|
|
1234
1373
|
|
1374
|
+
|
1235
1375
|
template <typename DType, typename IType>
|
1236
|
-
struct
|
1237
|
-
static VALUE iterate(VALUE nm) {
|
1376
|
+
struct yale_iteration_helper {
|
1238
1377
|
|
1378
|
+
static VALUE iterate_with_indices(VALUE nm) {
|
1239
1379
|
YALE_STORAGE* s = NM_STORAGE_YALE(nm);
|
1240
|
-
DType* a
|
1241
|
-
IType* ija
|
1380
|
+
DType* a = reinterpret_cast<DType*>(s->a);
|
1381
|
+
IType* ija = reinterpret_cast<IType*>(s->ija);
|
1242
1382
|
|
1243
1383
|
// If we don't have a block, return an enumerator.
|
1244
1384
|
RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_enumerator_length);
|
1245
1385
|
|
1386
|
+
// Iterate in two dimensions.
|
1387
|
+
for (long i = 0; i < s->shape[0]; ++i) {
|
1388
|
+
VALUE ii = LONG2NUM(i);
|
1389
|
+
|
1390
|
+
IType k = ija[i], k_next = ija[i+1];
|
1391
|
+
|
1392
|
+
for (long j = 0; j < s->shape[1]; ++j) {
|
1393
|
+
VALUE v, jj = LONG2NUM(j);
|
1394
|
+
|
1395
|
+
// zero is stored in s->shape[0]
|
1396
|
+
if (i == j) {
|
1397
|
+
v = rubyobj_from_cval(&(a[i]), NM_DTYPE(nm)).rval;
|
1398
|
+
} else {
|
1399
|
+
// Walk through the row until we find the correct location.
|
1400
|
+
while (ija[k] < j && k < k_next) ++k;
|
1401
|
+
if (k < k_next && ija[k] == j) {
|
1402
|
+
v = rubyobj_from_cval(&(a[k]), NM_DTYPE(nm)).rval;
|
1403
|
+
++k;
|
1404
|
+
} else v = rubyobj_from_cval(&(a[s->shape[0]]), NM_DTYPE(nm)).rval;
|
1405
|
+
}
|
1406
|
+
rb_yield_values(3, v, ii, jj);
|
1407
|
+
}
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
return nm;
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
|
1414
|
+
static VALUE iterate_stored_with_indices(VALUE nm) {
|
1415
|
+
|
1416
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(nm);
|
1417
|
+
DType* a = reinterpret_cast<DType*>(s->a);
|
1418
|
+
IType* ija = reinterpret_cast<IType*>(s->ija);
|
1419
|
+
|
1420
|
+
// If we don't have a block, return an enumerator.
|
1421
|
+
RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_stored_enumerator_length);
|
1422
|
+
|
1246
1423
|
// Iterate along diagonal
|
1247
1424
|
for (size_t k = 0; k < s->shape[0]; ++k) {
|
1248
1425
|
VALUE ii = LONG2NUM(k),
|
@@ -1263,7 +1440,7 @@ struct yale_each_stored_with_indices_helper {
|
|
1263
1440
|
jj = LONG2NUM(j);
|
1264
1441
|
|
1265
1442
|
VALUE v = rubyobj_from_cval(&(a[p]), NM_DTYPE(nm)).rval;
|
1266
|
-
rb_yield_values(3, v, ii, jj
|
1443
|
+
rb_yield_values(3, v, ii, jj);
|
1267
1444
|
}
|
1268
1445
|
}
|
1269
1446
|
|
@@ -1273,9 +1450,8 @@ struct yale_each_stored_with_indices_helper {
|
|
1273
1450
|
|
1274
1451
|
|
1275
1452
|
template <typename IType>
|
1276
|
-
struct
|
1277
|
-
static VALUE
|
1278
|
-
|
1453
|
+
struct yale_iteration_helper<RubyObject, IType> {
|
1454
|
+
static VALUE iterate_with_indices(VALUE nm) {
|
1279
1455
|
YALE_STORAGE* s = NM_STORAGE_YALE(nm);
|
1280
1456
|
RubyObject* a = reinterpret_cast<RubyObject*>(s->a);
|
1281
1457
|
IType* ija = reinterpret_cast<IType*>(s->ija);
|
@@ -1283,6 +1459,42 @@ struct yale_each_stored_with_indices_helper<RubyObject, IType> {
|
|
1283
1459
|
// If we don't have a block, return an enumerator.
|
1284
1460
|
RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_enumerator_length);
|
1285
1461
|
|
1462
|
+
// Iterate in two dimensions.
|
1463
|
+
for (long i = 0; i < s->shape[0]; ++i) {
|
1464
|
+
VALUE ii = LONG2NUM(i);
|
1465
|
+
|
1466
|
+
IType k = ija[i], k_next = ija[i+1];
|
1467
|
+
|
1468
|
+
for (long j = 0; j < s->shape[1]; ++j) {
|
1469
|
+
VALUE v, jj = LONG2NUM(j);
|
1470
|
+
|
1471
|
+
// zero is stored in s->shape[0]
|
1472
|
+
if (i == j) {
|
1473
|
+
v = a[i].rval;
|
1474
|
+
} else {
|
1475
|
+
// Walk through the row until we find the correct location.
|
1476
|
+
while (ija[k] < j && k < k_next) ++k;
|
1477
|
+
if (k < k_next && ija[k] == j) {
|
1478
|
+
v = a[k].rval;
|
1479
|
+
++k;
|
1480
|
+
} else v = a[s->shape[0]].rval;
|
1481
|
+
}
|
1482
|
+
rb_yield_values(3, v, ii, jj);
|
1483
|
+
}
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
return nm;
|
1487
|
+
}
|
1488
|
+
|
1489
|
+
static VALUE iterate_stored_with_indices(VALUE nm) {
|
1490
|
+
|
1491
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(nm);
|
1492
|
+
RubyObject* a = reinterpret_cast<RubyObject*>(s->a);
|
1493
|
+
IType* ija = reinterpret_cast<IType*>(s->ija);
|
1494
|
+
|
1495
|
+
// If we don't have a block, return an enumerator.
|
1496
|
+
RETURN_SIZED_ENUMERATOR(nm, 0, 0, nm_yale_stored_enumerator_length);
|
1497
|
+
|
1286
1498
|
// Iterate along diagonal
|
1287
1499
|
for (size_t k = 0; k < s->shape[0]; ++k) {
|
1288
1500
|
VALUE ii = LONG2NUM(k),
|
@@ -1292,8 +1504,8 @@ struct yale_each_stored_with_indices_helper<RubyObject, IType> {
|
|
1292
1504
|
|
1293
1505
|
// Iterate through non-diagonal elements, row by row
|
1294
1506
|
for (long i = 0; i < s->shape[0]; ++i) {
|
1295
|
-
|
1296
|
-
|
1507
|
+
IType p = ija[i],
|
1508
|
+
next_p = ija[i+1];
|
1297
1509
|
|
1298
1510
|
for (; p < next_p; ++p) {
|
1299
1511
|
long j = static_cast<long>(ija[p]);
|
@@ -1315,7 +1527,12 @@ struct yale_each_stored_with_indices_helper<RubyObject, IType> {
|
|
1315
1527
|
*/
|
1316
1528
|
template <typename DType, typename IType>
|
1317
1529
|
static VALUE yale_each_stored_with_indices(VALUE nm) {
|
1318
|
-
return
|
1530
|
+
return yale_iteration_helper<DType, IType>::iterate_stored_with_indices(nm);
|
1531
|
+
}
|
1532
|
+
|
1533
|
+
template <typename DType, typename IType>
|
1534
|
+
static VALUE yale_each_with_indices(VALUE nm) {
|
1535
|
+
return yale_iteration_helper<DType, IType>::iterate_with_indices(nm);
|
1319
1536
|
}
|
1320
1537
|
|
1321
1538
|
|
@@ -1345,7 +1562,6 @@ void nm_init_yale_functions() {
|
|
1345
1562
|
rb_define_method(cNMatrix_YaleFunctions, "yale_lu", (METHOD)nm_lu, 0);
|
1346
1563
|
|
1347
1564
|
rb_define_method(cNMatrix_YaleFunctions, "yale_nd_row", (METHOD)nm_nd_row, -1);
|
1348
|
-
rb_define_method(cNMatrix_YaleFunctions, "yale_vector_insert", (METHOD)nm_vector_insert, -1);
|
1349
1565
|
|
1350
1566
|
rb_define_const(cNMatrix_YaleFunctions, "YALE_GROWTH_CONSTANT", rb_float_new(nm::yale_storage::GROWTH_CONSTANT));
|
1351
1567
|
}
|
@@ -1356,7 +1572,18 @@ void nm_init_yale_functions() {
|
|
1356
1572
|
/////////////////
|
1357
1573
|
|
1358
1574
|
|
1575
|
+
/* C interface for NMatrix#each_with_indices (Yale) */
|
1576
|
+
VALUE nm_yale_each_with_indices(VALUE nmatrix) {
|
1577
|
+
nm::dtype_t d = NM_DTYPE(nmatrix);
|
1578
|
+
nm::itype_t i = NM_ITYPE(nmatrix);
|
1579
|
+
|
1580
|
+
NAMED_LI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_each_with_indices, VALUE, VALUE)
|
1581
|
+
|
1582
|
+
return ttable[d][i](nmatrix);
|
1583
|
+
}
|
1584
|
+
|
1359
1585
|
|
1586
|
+
/* C interface for NMatrix#each_stored_with_indices (Yale) */
|
1360
1587
|
VALUE nm_yale_each_stored_with_indices(VALUE nmatrix) {
|
1361
1588
|
nm::dtype_t d = NM_DTYPE(nmatrix);
|
1362
1589
|
nm::itype_t i = NM_ITYPE(nmatrix);
|
@@ -1367,6 +1594,7 @@ VALUE nm_yale_each_stored_with_indices(VALUE nmatrix) {
|
|
1367
1594
|
}
|
1368
1595
|
|
1369
1596
|
|
1597
|
+
|
1370
1598
|
/*
|
1371
1599
|
* C accessor for inserting some value in a matrix (or replacing an existing cell).
|
1372
1600
|
*/
|
@@ -1422,10 +1650,9 @@ void* nm_yale_storage_ref(STORAGE* storage, SLICE* slice) {
|
|
1422
1650
|
return ttable[casted_storage->dtype][casted_storage->itype](casted_storage, slice);
|
1423
1651
|
}
|
1424
1652
|
|
1653
|
+
|
1425
1654
|
/*
|
1426
1655
|
* C accessor for determining whether two YALE_STORAGE objects have the same contents.
|
1427
|
-
*
|
1428
|
-
* FIXME: Is this for element-wise or whole-matrix equality?
|
1429
1656
|
*/
|
1430
1657
|
bool nm_yale_storage_eqeq(const STORAGE* left, const STORAGE* right) {
|
1431
1658
|
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::eqeq, bool, const YALE_STORAGE* left, const YALE_STORAGE* right);
|
@@ -1435,10 +1662,11 @@ bool nm_yale_storage_eqeq(const STORAGE* left, const STORAGE* right) {
|
|
1435
1662
|
return ttable[casted_left->dtype][right->dtype][casted_left->itype](casted_left, (const YALE_STORAGE*)right);
|
1436
1663
|
}
|
1437
1664
|
|
1665
|
+
|
1438
1666
|
/*
|
1439
1667
|
* Copy constructor for changing dtypes. (C accessor)
|
1440
1668
|
*/
|
1441
|
-
STORAGE* nm_yale_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype) {
|
1669
|
+
STORAGE* nm_yale_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype, void* dummy) {
|
1442
1670
|
NAMED_LRI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::cast_copy, YALE_STORAGE*, const YALE_STORAGE* rhs, nm::dtype_t new_dtype);
|
1443
1671
|
|
1444
1672
|
const YALE_STORAGE* casted_rhs = reinterpret_cast<const YALE_STORAGE*>(rhs);
|
@@ -1446,6 +1674,7 @@ STORAGE* nm_yale_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype) {
|
|
1446
1674
|
return (STORAGE*)ttable[new_dtype][casted_rhs->dtype][casted_rhs->itype](casted_rhs, new_dtype);
|
1447
1675
|
}
|
1448
1676
|
|
1677
|
+
|
1449
1678
|
/*
|
1450
1679
|
* Returns size of Yale storage as a size_t (no matter what the itype is). (C accessor)
|
1451
1680
|
*/
|
@@ -1455,6 +1684,32 @@ size_t nm_yale_storage_get_size(const YALE_STORAGE* storage) {
|
|
1455
1684
|
return ttable[storage->itype](storage);
|
1456
1685
|
}
|
1457
1686
|
|
1687
|
+
|
1688
|
+
/*
|
1689
|
+
* Return a void pointer to the matrix's default value entry.
|
1690
|
+
*/
|
1691
|
+
static void* default_value_ptr(const YALE_STORAGE* s) {
|
1692
|
+
return reinterpret_cast<void*>(reinterpret_cast<char*>(s->a) + (s->shape[0] * DTYPE_SIZES[s->dtype]));
|
1693
|
+
}
|
1694
|
+
|
1695
|
+
|
1696
|
+
/*
|
1697
|
+
* Return the matrix's default value as a Ruby VALUE.
|
1698
|
+
*/
|
1699
|
+
static VALUE default_value(const YALE_STORAGE* s) {
|
1700
|
+
if (s->dtype == nm::RUBYOBJ) return *reinterpret_cast<VALUE*>(default_value_ptr(s));
|
1701
|
+
else return rubyobj_from_cval(default_value_ptr(s), s->dtype).rval;
|
1702
|
+
}
|
1703
|
+
|
1704
|
+
|
1705
|
+
/*
|
1706
|
+
* Check to see if a default value is some form of zero. Easy for non-Ruby object matrices, which should always be 0.
|
1707
|
+
*/
|
1708
|
+
static bool default_value_is_numeric_zero(const YALE_STORAGE* s) {
|
1709
|
+
return rb_funcall(default_value(s), rb_intern("=="), 1, INT2FIX(0)) == Qtrue;
|
1710
|
+
}
|
1711
|
+
|
1712
|
+
|
1458
1713
|
/*
|
1459
1714
|
* C accessor for allocating a yale storage object for cast-copying. Copies the IJA vector, does not copy the A vector.
|
1460
1715
|
*/
|
@@ -1476,8 +1731,8 @@ STORAGE* nm_yale_storage_copy_transposed(const STORAGE* rhs_base) {
|
|
1476
1731
|
|
1477
1732
|
size_t size = nm_yale_storage_get_size(rhs);
|
1478
1733
|
|
1479
|
-
YALE_STORAGE* lhs = nm_yale_storage_create(rhs->dtype, shape, 2, size,
|
1480
|
-
nm_yale_storage_init(lhs);
|
1734
|
+
YALE_STORAGE* lhs = nm_yale_storage_create(rhs->dtype, shape, 2, size, rhs->itype);
|
1735
|
+
nm_yale_storage_init(lhs, default_value_ptr(rhs));
|
1481
1736
|
|
1482
1737
|
NAMED_LI_DTYPE_TEMPLATE_TABLE(transp, nm::math::transpose_yale, void, const size_t n, const size_t m, const void* ia_, const void* ja_, const void* a_, const bool diaga, void* ib_, void* jb_, void* b_, const bool move);
|
1483
1738
|
|
@@ -1498,6 +1753,11 @@ STORAGE* nm_yale_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, siz
|
|
1498
1753
|
YALE_STORAGE* left = reinterpret_cast<YALE_STORAGE*>(casted_storage.left);
|
1499
1754
|
YALE_STORAGE* right = reinterpret_cast<YALE_STORAGE*>(casted_storage.right);
|
1500
1755
|
|
1756
|
+
if (!default_value_is_numeric_zero(left) || !default_value_is_numeric_zero(right)) {
|
1757
|
+
rb_raise(rb_eNotImpError, "matrix default value must be some form of zero (not false or nil) for multiplication");
|
1758
|
+
return NULL;
|
1759
|
+
}
|
1760
|
+
|
1501
1761
|
// Determine the itype for the matrix that will be returned.
|
1502
1762
|
nm::itype_t itype = nm_yale_storage_itype_by_shape(resulting_shape),
|
1503
1763
|
max_itype = NM_MAX_ITYPE(left->itype, right->itype);
|
@@ -1506,70 +1766,6 @@ STORAGE* nm_yale_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, siz
|
|
1506
1766
|
return ttable[left->dtype][itype](casted_storage, resulting_shape, vector, itype);
|
1507
1767
|
}
|
1508
1768
|
|
1509
|
-
/*
|
1510
|
-
* Documentation goes here.
|
1511
|
-
*/
|
1512
|
-
STORAGE* nm_yale_storage_ew_op(nm::ewop_t op, const STORAGE* left, const STORAGE* right, VALUE scalar) {
|
1513
|
-
OP_ITYPE_DTYPE_TEMPLATE_TABLE(nm::yale_storage::ew_op, YALE_STORAGE*, const YALE_STORAGE*, const YALE_STORAGE*, nm::dtype_t);
|
1514
|
-
|
1515
|
-
YALE_STORAGE* new_l = NULL, * new_r = NULL;
|
1516
|
-
YALE_STORAGE* result;
|
1517
|
-
|
1518
|
-
const YALE_STORAGE* casted_l, * casted_r;
|
1519
|
-
|
1520
|
-
nm::dtype_t new_dtype;
|
1521
|
-
|
1522
|
-
if (left->dtype != right->dtype) {
|
1523
|
-
|
1524
|
-
new_dtype = Upcast[left->dtype][right->dtype];
|
1525
|
-
|
1526
|
-
if (left->dtype != new_dtype) {
|
1527
|
-
new_l = reinterpret_cast<YALE_STORAGE*>(nm_yale_storage_cast_copy( left, new_dtype));
|
1528
|
-
}
|
1529
|
-
|
1530
|
-
if (right->dtype != new_dtype) {
|
1531
|
-
new_r = reinterpret_cast<YALE_STORAGE*>(nm_yale_storage_cast_copy(right, new_dtype));
|
1532
|
-
}
|
1533
|
-
|
1534
|
-
if (static_cast<uint8_t>(op) < nm::NUM_NONCOMP_EWOPS) {
|
1535
|
-
result = ttable[op][new_l->itype][new_dtype]( left->dtype == new_dtype ?
|
1536
|
-
reinterpret_cast<const YALE_STORAGE*>( left) :
|
1537
|
-
reinterpret_cast<const YALE_STORAGE*>(new_l),
|
1538
|
-
|
1539
|
-
right->dtype == new_dtype ?
|
1540
|
-
reinterpret_cast<const YALE_STORAGE*>(right) :
|
1541
|
-
reinterpret_cast<const YALE_STORAGE*>(new_r),
|
1542
|
-
|
1543
|
-
new_dtype);
|
1544
|
-
|
1545
|
-
} else {
|
1546
|
-
rb_raise(rb_eNotImpError, "Elementwise comparison is not yet implemented for the Yale storage class.");
|
1547
|
-
}
|
1548
|
-
|
1549
|
-
if (new_l != NULL) {
|
1550
|
-
nm_yale_storage_delete(new_l);
|
1551
|
-
}
|
1552
|
-
|
1553
|
-
if (new_r != NULL) {
|
1554
|
-
nm_yale_storage_delete(new_r);
|
1555
|
-
}
|
1556
|
-
|
1557
|
-
return result;
|
1558
|
-
|
1559
|
-
} else {
|
1560
|
-
|
1561
|
-
casted_l = reinterpret_cast<const YALE_STORAGE*>( left);
|
1562
|
-
casted_r = reinterpret_cast<const YALE_STORAGE*>(right);
|
1563
|
-
|
1564
|
-
if (static_cast<uint8_t>(op) < nm::NUM_NONCOMP_EWOPS) {
|
1565
|
-
|
1566
|
-
return ttable[op][casted_l->itype][casted_l->dtype](casted_l, casted_r, casted_l->dtype);
|
1567
|
-
|
1568
|
-
} else {
|
1569
|
-
rb_raise(rb_eNotImpError, "Elementwise comparison is not yet implemented for the Yale storage class.");
|
1570
|
-
}
|
1571
|
-
}
|
1572
|
-
}
|
1573
1769
|
|
1574
1770
|
///////////////
|
1575
1771
|
// Lifecycle //
|
@@ -1620,10 +1816,11 @@ YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t di
|
|
1620
1816
|
void nm_yale_storage_delete(STORAGE* s) {
|
1621
1817
|
if (s) {
|
1622
1818
|
YALE_STORAGE* storage = (YALE_STORAGE*)s;
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1819
|
+
xfree(storage->shape);
|
1820
|
+
xfree(storage->offset);
|
1821
|
+
xfree(storage->ija);
|
1822
|
+
xfree(storage->a);
|
1823
|
+
xfree(storage);
|
1627
1824
|
}
|
1628
1825
|
}
|
1629
1826
|
|
@@ -1632,10 +1829,10 @@ void nm_yale_storage_delete(STORAGE* s) {
|
|
1632
1829
|
*
|
1633
1830
|
* Initializes the IJA vector of the YALE_STORAGE matrix.
|
1634
1831
|
*/
|
1635
|
-
void nm_yale_storage_init(YALE_STORAGE* s) {
|
1636
|
-
NAMED_LI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::init, void, YALE_STORAGE*
|
1832
|
+
void nm_yale_storage_init(YALE_STORAGE* s, void* init_val) {
|
1833
|
+
NAMED_LI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::init, void, YALE_STORAGE*, void*);
|
1637
1834
|
|
1638
|
-
ttable[s->dtype][s->itype](s);
|
1835
|
+
ttable[s->dtype][s->itype](s, init_val);
|
1639
1836
|
}
|
1640
1837
|
|
1641
1838
|
|
@@ -1664,8 +1861,12 @@ static YALE_STORAGE* alloc(nm::dtype_t dtype, size_t* shape, size_t dim, nm::ity
|
|
1664
1861
|
s->ndnz = 0;
|
1665
1862
|
s->dtype = dtype;
|
1666
1863
|
s->shape = shape;
|
1864
|
+
s->offset = ALLOC_N(size_t, dim);
|
1865
|
+
for (size_t i = 0; i < dim; ++i)
|
1866
|
+
s->offset[i] = 0;
|
1667
1867
|
s->dim = dim;
|
1668
1868
|
s->itype = nm_yale_storage_itype_by_shape(shape);
|
1869
|
+
s->src = reinterpret_cast<STORAGE*>(s);
|
1669
1870
|
|
1670
1871
|
// See if a higher itype has been requested.
|
1671
1872
|
if (static_cast<int8_t>(s->itype) < static_cast<int8_t>(min_itype))
|
@@ -1723,8 +1924,14 @@ static VALUE nm_a(int argc, VALUE* argv, VALUE self) {
|
|
1723
1924
|
if (idx == Qnil) {
|
1724
1925
|
VALUE* vals = ALLOCA_N(VALUE, size);
|
1725
1926
|
|
1726
|
-
|
1727
|
-
|
1927
|
+
if (NM_DTYPE(self) == nm::RUBYOBJ) {
|
1928
|
+
for (size_t i = 0; i < size; ++i) {
|
1929
|
+
vals[i] = reinterpret_cast<VALUE*>(s->a)[i];
|
1930
|
+
}
|
1931
|
+
} else {
|
1932
|
+
for (size_t i = 0; i < size; ++i) {
|
1933
|
+
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*i, s->dtype).rval;
|
1934
|
+
}
|
1728
1935
|
}
|
1729
1936
|
VALUE ary = rb_ary_new4(size, vals);
|
1730
1937
|
|
@@ -1757,9 +1964,16 @@ static VALUE nm_d(int argc, VALUE* argv, VALUE self) {
|
|
1757
1964
|
if (idx == Qnil) {
|
1758
1965
|
VALUE* vals = ALLOCA_N(VALUE, s->shape[0]);
|
1759
1966
|
|
1760
|
-
|
1761
|
-
|
1967
|
+
if (NM_DTYPE(self) == nm::RUBYOBJ) {
|
1968
|
+
for (size_t i = 0; i < s->shape[0]; ++i) {
|
1969
|
+
vals[i] = reinterpret_cast<VALUE*>(s->a)[i];
|
1970
|
+
}
|
1971
|
+
} else {
|
1972
|
+
for (size_t i = 0; i < s->shape[0]; ++i) {
|
1973
|
+
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*i, s->dtype).rval;
|
1974
|
+
}
|
1762
1975
|
}
|
1976
|
+
|
1763
1977
|
return rb_ary_new4(s->shape[0], vals);
|
1764
1978
|
} else {
|
1765
1979
|
size_t index = FIX2INT(idx);
|
@@ -1782,8 +1996,14 @@ static VALUE nm_lu(VALUE self) {
|
|
1782
1996
|
|
1783
1997
|
VALUE* vals = ALLOCA_N(VALUE, size - s->shape[0] - 1);
|
1784
1998
|
|
1785
|
-
|
1786
|
-
|
1999
|
+
if (NM_DTYPE(self) == nm::RUBYOBJ) {
|
2000
|
+
for (size_t i = 0; i < size - s->shape[0] - 1; ++i) {
|
2001
|
+
vals[i] = reinterpret_cast<VALUE*>(s->a)[s->shape[0] + 1 + i];
|
2002
|
+
}
|
2003
|
+
} else {
|
2004
|
+
for (size_t i = 0; i < size - s->shape[0] - 1; ++i) {
|
2005
|
+
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*(s->shape[0] + 1 + i), s->dtype).rval;
|
2006
|
+
}
|
1787
2007
|
}
|
1788
2008
|
|
1789
2009
|
VALUE ary = rb_ary_new4(size - s->shape[0] - 1, vals);
|
@@ -1882,20 +2102,18 @@ static VALUE nm_ija(int argc, VALUE* argv, VALUE self) {
|
|
1882
2102
|
* yale_nd_row -> ...
|
1883
2103
|
*
|
1884
2104
|
* This function gets the non-diagonal contents of a Yale matrix row.
|
1885
|
-
* The first argument should be the row index. The optional second argument may be :hash or :
|
1886
|
-
* to :hash. If :
|
2105
|
+
* The first argument should be the row index. The optional second argument may be :hash or :keys, but defaults
|
2106
|
+
* to :hash. If :keys is given, it will only return the Hash keys (the column indices).
|
1887
2107
|
*
|
1888
2108
|
* This function is meant to accomplish its purpose as efficiently as possible. It does not check for appropriate
|
1889
2109
|
* range.
|
1890
|
-
*
|
1891
|
-
* FIXME: :array doesn't make sense. This should be :keys or :values to indicate which array we want.
|
1892
2110
|
*/
|
1893
2111
|
static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self) {
|
1894
2112
|
VALUE i_, as;
|
1895
2113
|
rb_scan_args(argc, argv, "11", &i_, &as);
|
1896
2114
|
|
1897
|
-
bool
|
1898
|
-
if (as != Qnil && rb_to_id(as) != nm_rb_hash)
|
2115
|
+
bool keys = false;
|
2116
|
+
if (as != Qnil && rb_to_id(as) != nm_rb_hash) keys = true;
|
1899
2117
|
|
1900
2118
|
size_t i = FIX2INT(i_);
|
1901
2119
|
|
@@ -1912,7 +2130,7 @@ static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self) {
|
|
1912
2130
|
//std::cerr << "diff = " << diff << "\tpos = " << pos << "\tnextpos = " << nextpos << std::endl;
|
1913
2131
|
|
1914
2132
|
VALUE ret; // HERE
|
1915
|
-
if (
|
2133
|
+
if (keys) {
|
1916
2134
|
ret = rb_ary_new3(diff);
|
1917
2135
|
|
1918
2136
|
for (size_t idx = pos; idx < nextpos; ++idx) {
|
@@ -1933,7 +2151,7 @@ static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self) {
|
|
1933
2151
|
|
1934
2152
|
/*
|
1935
2153
|
* call-seq:
|
1936
|
-
*
|
2154
|
+
* yale_vector_set(i, column_index_array, cell_contents_array, pos) -> Fixnum
|
1937
2155
|
*
|
1938
2156
|
* Insert at position pos an array of non-diagonal elements with column indices given. Note that the column indices and values
|
1939
2157
|
* must be storage-contiguous -- that is, you can't insert them around existing elements in some row, only amid some
|
@@ -1949,18 +2167,18 @@ static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self) {
|
|
1949
2167
|
* lead to undefined behavior.
|
1950
2168
|
*
|
1951
2169
|
* Example:
|
1952
|
-
* m.
|
2170
|
+
* m.yale_vector_set(3, [0,3,4], [1,1,1], 15)
|
1953
2171
|
*
|
1954
2172
|
* The example above inserts the values 1, 1, and 1 in columns 0, 3, and 4, assumed to be located at position 15 (which
|
1955
2173
|
* corresponds to row 3).
|
1956
2174
|
*
|
1957
2175
|
* Example:
|
1958
|
-
* next = m.
|
2176
|
+
* next = m.yale_vector_set(3, [0,3,4], [1,1,1])
|
1959
2177
|
*
|
1960
2178
|
* This example determines that i=3 is at position 15 automatically. The value returned, next, is the position where the
|
1961
2179
|
* next value(s) should be inserted.
|
1962
2180
|
*/
|
1963
|
-
|
2181
|
+
VALUE nm_vector_set(int argc, VALUE* argv, VALUE self) { //, VALUE i_, VALUE jv, VALUE vv, VALUE pos_) {
|
1964
2182
|
|
1965
2183
|
// i, jv, vv are mandatory; pos is optional; thus "31"
|
1966
2184
|
VALUE i_, jv, vv, pos_;
|
@@ -2002,4 +2220,46 @@ static VALUE nm_vector_insert(int argc, VALUE* argv, VALUE self) { //, VALUE i_,
|
|
2002
2220
|
}
|
2003
2221
|
|
2004
2222
|
|
2223
|
+
|
2224
|
+
|
2225
|
+
/*
|
2226
|
+
* call-seq:
|
2227
|
+
* __yale_default_value__ -> ...
|
2228
|
+
*
|
2229
|
+
* Get the default_value property from a yale matrix.
|
2230
|
+
*/
|
2231
|
+
VALUE nm_yale_default_value(VALUE self) {
|
2232
|
+
return default_value(NM_STORAGE_YALE(self));
|
2233
|
+
}
|
2234
|
+
|
2235
|
+
|
2236
|
+
/*
|
2237
|
+
* call-seq:
|
2238
|
+
* __yale_map_merged_stored__(right) -> Enumerator
|
2239
|
+
*
|
2240
|
+
* A map operation on two Yale matrices which only iterates across the stored indices.
|
2241
|
+
*/
|
2242
|
+
VALUE nm_yale_map_merged_stored(VALUE left, VALUE right, VALUE init) {
|
2243
|
+
YALE_STORAGE *s = NM_STORAGE_YALE(left),
|
2244
|
+
*t = NM_STORAGE_YALE(right);
|
2245
|
+
|
2246
|
+
ITYPE_TEMPLATE_TABLE(nm::yale_storage::map_merged_stored, VALUE, VALUE l, VALUE r, VALUE init, nm::itype_t)
|
2247
|
+
|
2248
|
+
nm::itype_t itype = NM_MAX_ITYPE(s->itype, t->itype);
|
2249
|
+
return ttable[itype](left, right, init, itype);
|
2250
|
+
}
|
2251
|
+
|
2252
|
+
|
2253
|
+
/*
|
2254
|
+
* call-seq:
|
2255
|
+
* __yale_map_stored__ -> Enumerator
|
2256
|
+
*
|
2257
|
+
* A map operation on two Yale matrices which only iterates across the stored indices.
|
2258
|
+
*/
|
2259
|
+
VALUE nm_yale_map_stored(VALUE self) {
|
2260
|
+
ITYPE_TEMPLATE_TABLE(nm::yale_storage::map_stored, VALUE, VALUE)
|
2261
|
+
|
2262
|
+
return ttable[NM_ITYPE(self)](self);
|
2263
|
+
}
|
2264
|
+
|
2005
2265
|
} // end of extern "C" block
|