nmatrix 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -8
- data/.rspec +1 -1
- data/.travis.yml +12 -0
- data/CONTRIBUTING.md +27 -12
- data/Gemfile +1 -0
- data/History.txt +38 -0
- data/Manifest.txt +15 -15
- data/README.rdoc +7 -6
- data/Rakefile +40 -5
- data/ext/nmatrix/data/data.cpp +2 -37
- data/ext/nmatrix/data/data.h +19 -121
- data/ext/nmatrix/data/meta.h +70 -0
- data/ext/nmatrix/extconf.rb +40 -12
- data/ext/nmatrix/math/math.h +13 -103
- data/ext/nmatrix/nmatrix.cpp +10 -2018
- data/ext/nmatrix/nmatrix.h +16 -13
- data/ext/nmatrix/ruby_constants.cpp +12 -1
- data/ext/nmatrix/ruby_constants.h +7 -1
- data/ext/nmatrix/ruby_nmatrix.c +2169 -0
- data/ext/nmatrix/storage/dense.cpp +123 -14
- data/ext/nmatrix/storage/dense.h +10 -4
- data/ext/nmatrix/storage/list.cpp +265 -48
- data/ext/nmatrix/storage/list.h +6 -9
- data/ext/nmatrix/storage/storage.cpp +44 -54
- data/ext/nmatrix/storage/storage.h +2 -2
- data/ext/nmatrix/storage/yale/class.h +1070 -0
- data/ext/nmatrix/storage/yale/iterators/base.h +142 -0
- data/ext/nmatrix/storage/yale/iterators/iterator.h +130 -0
- data/ext/nmatrix/storage/yale/iterators/row.h +449 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored.h +139 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +167 -0
- data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +123 -0
- data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
- data/ext/nmatrix/storage/yale/yale.cpp +1785 -0
- data/ext/nmatrix/storage/{yale.h → yale/yale.h} +23 -55
- data/ext/nmatrix/types.h +2 -0
- data/ext/nmatrix/util/io.cpp +27 -45
- data/ext/nmatrix/util/io.h +0 -2
- data/ext/nmatrix/util/sl_list.cpp +169 -28
- data/ext/nmatrix/util/sl_list.h +9 -3
- data/lib/nmatrix/blas.rb +20 -20
- data/lib/nmatrix/enumerate.rb +1 -1
- data/lib/nmatrix/io/mat5_reader.rb +8 -14
- data/lib/nmatrix/lapack.rb +3 -3
- data/lib/nmatrix/math.rb +3 -3
- data/lib/nmatrix/nmatrix.rb +19 -5
- data/lib/nmatrix/nvector.rb +2 -0
- data/lib/nmatrix/shortcuts.rb +90 -125
- data/lib/nmatrix/version.rb +1 -1
- data/nmatrix.gemspec +7 -8
- data/spec/{nmatrix_spec.rb → 00_nmatrix_spec.rb} +45 -208
- data/spec/01_enum_spec.rb +184 -0
- data/spec/{slice_spec.rb → 02_slice_spec.rb} +55 -39
- data/spec/blas_spec.rb +22 -54
- data/spec/elementwise_spec.rb +9 -8
- data/spec/io_spec.rb +6 -4
- data/spec/lapack_spec.rb +26 -26
- data/spec/math_spec.rb +9 -5
- data/spec/nmatrix_yale_spec.rb +29 -61
- data/spec/shortcuts_spec.rb +34 -22
- data/spec/slice_set_spec.rb +157 -0
- data/spec/spec_helper.rb +42 -2
- data/spec/stat_spec.rb +192 -0
- metadata +52 -55
- data/ext/nmatrix/storage/yale.cpp +0 -2284
- data/spec/nmatrix_list_spec.rb +0 -113
- data/spec/nvector_spec.rb +0 -112
@@ -99,6 +99,69 @@ namespace nm { namespace dense_storage {
|
|
99
99
|
|
100
100
|
}
|
101
101
|
|
102
|
+
/*
|
103
|
+
* Recursive function, sets multiple values in a matrix from a single source value. Same basic pattern as slice_copy.
|
104
|
+
*/
|
105
|
+
template <typename D>
|
106
|
+
static void slice_set(DENSE_STORAGE* dest, size_t* lengths, size_t pdest, size_t rank, D* const v, size_t v_size, size_t& v_offset) {
|
107
|
+
if (dest->dim - rank > 1) {
|
108
|
+
for (size_t i = 0; i < lengths[rank]; ++i) {
|
109
|
+
slice_set<D>(dest, lengths, pdest + dest->stride[rank] * i, rank + 1, v, v_size, v_offset);
|
110
|
+
}
|
111
|
+
} else {
|
112
|
+
for (size_t p = 0; p < lengths[rank]; ++p, ++v_offset) {
|
113
|
+
if (v_offset >= v_size) v_offset %= v_size;
|
114
|
+
|
115
|
+
D* elem = reinterpret_cast<D*>(dest->elements);
|
116
|
+
elem[p + pdest] = v[v_offset];
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
/*
|
123
|
+
* Dense storage set/slice-set function, templated version.
|
124
|
+
*/
|
125
|
+
template <typename D>
|
126
|
+
void set(VALUE left, SLICE* slice, VALUE right) {
|
127
|
+
DENSE_STORAGE* s = NM_STORAGE_DENSE(left);
|
128
|
+
|
129
|
+
std::pair<NMATRIX*,bool> nm_and_free =
|
130
|
+
interpret_arg_as_dense_nmatrix(right, NM_DTYPE(left));
|
131
|
+
|
132
|
+
// Map the data onto D* v.
|
133
|
+
D* v;
|
134
|
+
size_t v_size = 1;
|
135
|
+
|
136
|
+
if (nm_and_free.first) {
|
137
|
+
DENSE_STORAGE* t = reinterpret_cast<DENSE_STORAGE*>(nm_and_free.first->storage);
|
138
|
+
v = reinterpret_cast<D*>(t->elements);
|
139
|
+
v_size = nm_storage_count_max_elements(t);
|
140
|
+
|
141
|
+
} else if (TYPE(right) == T_ARRAY) {
|
142
|
+
v_size = RARRAY_LEN(right);
|
143
|
+
v = ALLOC_N(D, v_size);
|
144
|
+
for (size_t m = 0; m < v_size; ++m) {
|
145
|
+
rubyval_to_cval(rb_ary_entry(right, m), s->dtype, &(v[m]));
|
146
|
+
}
|
147
|
+
} else {
|
148
|
+
v = reinterpret_cast<D*>(rubyobj_to_cval(right, NM_DTYPE(left)));
|
149
|
+
}
|
150
|
+
|
151
|
+
if (slice->single) {
|
152
|
+
reinterpret_cast<D*>(s->elements)[nm_dense_storage_pos(s, slice->coords)] = *v;
|
153
|
+
} else {
|
154
|
+
size_t v_offset = 0;
|
155
|
+
slice_set(s, slice->lengths, nm_dense_storage_pos(s, slice->coords), 0, v, v_size, v_offset);
|
156
|
+
}
|
157
|
+
|
158
|
+
// Only free v if it was allocated in this function.
|
159
|
+
if (nm_and_free.first && nm_and_free.second)
|
160
|
+
nm_delete(nm_and_free.first);
|
161
|
+
else
|
162
|
+
xfree(v);
|
163
|
+
}
|
164
|
+
|
102
165
|
}} // end of namespace nm::dense_storage
|
103
166
|
|
104
167
|
|
@@ -216,15 +279,18 @@ void nm_dense_storage_delete_ref(STORAGE* s) {
|
|
216
279
|
/*
|
217
280
|
* Mark values in a dense matrix for garbage collection. This may not be necessary -- further testing required.
|
218
281
|
*/
|
219
|
-
void nm_dense_storage_mark(
|
282
|
+
void nm_dense_storage_mark(STORAGE* storage_base) {
|
283
|
+
|
220
284
|
DENSE_STORAGE* storage = (DENSE_STORAGE*)storage_base;
|
221
285
|
|
222
286
|
if (storage && storage->dtype == nm::RUBYOBJ) {
|
223
287
|
VALUE* els = reinterpret_cast<VALUE*>(storage->elements);
|
224
288
|
|
225
|
-
|
226
|
-
|
227
|
-
|
289
|
+
rb_gc_mark_locations(els, els + nm_storage_count_max_elements(storage) * sizeof(VALUE));
|
290
|
+
|
291
|
+
//for (size_t index = nm_storage_count_max_elements(storage); index-- > 0;) {
|
292
|
+
// rb_gc_mark(els[index]);
|
293
|
+
//}
|
228
294
|
}
|
229
295
|
}
|
230
296
|
|
@@ -254,6 +320,8 @@ VALUE nm_dense_map_pair(VALUE self, VALUE right) {
|
|
254
320
|
DENSE_STORAGE* result = nm_dense_storage_create(nm::RUBYOBJ, shape_copy, s->dim, NULL, 0);
|
255
321
|
VALUE* result_elem = reinterpret_cast<VALUE*>(result->elements);
|
256
322
|
|
323
|
+
nm_register_values(result_elem, count);
|
324
|
+
|
257
325
|
for (size_t k = 0; k < count; ++k) {
|
258
326
|
nm_dense_storage_coords(result, k, coords);
|
259
327
|
size_t s_index = nm_dense_storage_pos(s, coords),
|
@@ -266,10 +334,13 @@ VALUE nm_dense_map_pair(VALUE self, VALUE right) {
|
|
266
334
|
}
|
267
335
|
|
268
336
|
NMATRIX* m = nm_create(nm::DENSE_STORE, reinterpret_cast<STORAGE*>(result));
|
337
|
+
VALUE rb_nm = Data_Wrap_Struct(CLASS_OF(self), nm_mark, nm_delete, m);
|
269
338
|
|
270
|
-
|
271
|
-
}
|
339
|
+
nm_unregister_values(result_elem, count);
|
272
340
|
|
341
|
+
return rb_nm;
|
342
|
+
|
343
|
+
}
|
273
344
|
|
274
345
|
/*
|
275
346
|
* map enumerator for dense matrices.
|
@@ -290,6 +361,8 @@ VALUE nm_dense_map(VALUE self) {
|
|
290
361
|
DENSE_STORAGE* result = nm_dense_storage_create(nm::RUBYOBJ, shape_copy, s->dim, NULL, 0);
|
291
362
|
VALUE* result_elem = reinterpret_cast<VALUE*>(result->elements);
|
292
363
|
|
364
|
+
nm_register_values(result_elem, count);
|
365
|
+
|
293
366
|
for (size_t k = 0; k < count; ++k) {
|
294
367
|
nm_dense_storage_coords(result, k, coords);
|
295
368
|
size_t s_index = nm_dense_storage_pos(s, coords);
|
@@ -298,8 +371,12 @@ VALUE nm_dense_map(VALUE self) {
|
|
298
371
|
}
|
299
372
|
|
300
373
|
NMATRIX* m = nm_create(nm::DENSE_STORE, reinterpret_cast<STORAGE*>(result));
|
374
|
+
VALUE rb_nm = Data_Wrap_Struct(CLASS_OF(self), nm_mark, nm_delete, m);
|
375
|
+
|
376
|
+
nm_unregister_values(result_elem, count);
|
377
|
+
|
378
|
+
return rb_nm;
|
301
379
|
|
302
|
-
return Data_Wrap_Struct(CLASS_OF(self), nm_dense_storage_mark, nm_delete, m);
|
303
380
|
}
|
304
381
|
|
305
382
|
|
@@ -408,7 +485,7 @@ static void slice_copy(DENSE_STORAGE *dest, const DENSE_STORAGE *src, size_t* le
|
|
408
485
|
*
|
409
486
|
* FIXME: Template the first condition.
|
410
487
|
*/
|
411
|
-
void* nm_dense_storage_get(STORAGE* storage, SLICE* slice) {
|
488
|
+
void* nm_dense_storage_get(const STORAGE* storage, SLICE* slice) {
|
412
489
|
DENSE_STORAGE* s = (DENSE_STORAGE*)storage;
|
413
490
|
|
414
491
|
if (slice->single)
|
@@ -437,7 +514,7 @@ void* nm_dense_storage_get(STORAGE* storage, SLICE* slice) {
|
|
437
514
|
*
|
438
515
|
* FIXME: Template the first condition.
|
439
516
|
*/
|
440
|
-
void* nm_dense_storage_ref(STORAGE* storage, SLICE* slice) {
|
517
|
+
void* nm_dense_storage_ref(const STORAGE* storage, SLICE* slice) {
|
441
518
|
DENSE_STORAGE* s = (DENSE_STORAGE*)storage;
|
442
519
|
|
443
520
|
if (slice->single)
|
@@ -466,14 +543,18 @@ void* nm_dense_storage_ref(STORAGE* storage, SLICE* slice) {
|
|
466
543
|
}
|
467
544
|
|
468
545
|
|
546
|
+
|
547
|
+
|
469
548
|
/*
|
470
|
-
*
|
549
|
+
* Set a value or values in a dense matrix. Requires that right be either a single value or an NMatrix (ref or real).
|
471
550
|
*/
|
472
|
-
void nm_dense_storage_set(
|
473
|
-
|
474
|
-
|
551
|
+
void nm_dense_storage_set(VALUE left, SLICE* slice, VALUE right) {
|
552
|
+
NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::dense_storage::set, void, VALUE, SLICE*, VALUE)
|
553
|
+
|
554
|
+
ttable[NM_DTYPE(left)](left, slice, right);
|
475
555
|
}
|
476
556
|
|
557
|
+
|
477
558
|
///////////
|
478
559
|
// Tests //
|
479
560
|
///////////
|
@@ -678,7 +759,35 @@ STORAGE* nm_dense_storage_copy_transposed(const STORAGE* rhs_base) {
|
|
678
759
|
|
679
760
|
} // end of extern "C" block
|
680
761
|
|
681
|
-
namespace nm {
|
762
|
+
namespace nm {
|
763
|
+
|
764
|
+
/*
|
765
|
+
* Used for slice setting. Takes the right-hand of the equal sign, a single VALUE, and massages
|
766
|
+
* it into the correct form if it's not already there (dtype, non-ref, dense). Returns a pair of the NMATRIX* and a
|
767
|
+
* boolean. If the boolean is true, the calling function is responsible for calling nm_delete on the NMATRIX*.
|
768
|
+
* Otherwise, the NMATRIX* still belongs to Ruby and Ruby will free it.
|
769
|
+
*/
|
770
|
+
std::pair<NMATRIX*,bool> interpret_arg_as_dense_nmatrix(VALUE right, nm::dtype_t dtype) {
|
771
|
+
if (TYPE(right) == T_DATA && (RDATA(right)->dfree == (RUBY_DATA_FUNC)nm_delete || RDATA(right)->dfree == (RUBY_DATA_FUNC)nm_delete_ref)) {
|
772
|
+
NMATRIX *r;
|
773
|
+
if (NM_STYPE(right) != DENSE_STORE || NM_DTYPE(right) != dtype || NM_SRC(right) != NM_STORAGE(right)) {
|
774
|
+
UnwrapNMatrix( right, r );
|
775
|
+
NMATRIX* ldtype_r = nm_cast_with_ctype_args(r, nm::DENSE_STORE, dtype, NULL);
|
776
|
+
return std::make_pair(ldtype_r,true);
|
777
|
+
} else { // simple case -- right-hand matrix is dense and is not a reference and has same dtype
|
778
|
+
UnwrapNMatrix( right, r );
|
779
|
+
return std::make_pair(r, false);
|
780
|
+
}
|
781
|
+
// Do not set v_alloc = true for either of these. It is the responsibility of r/ldtype_r
|
782
|
+
} else if (TYPE(right) == T_DATA) {
|
783
|
+
rb_raise(rb_eTypeError, "unrecognized type for slice assignment");
|
784
|
+
}
|
785
|
+
|
786
|
+
return std::make_pair<NMATRIX*,bool>(NULL, false);
|
787
|
+
}
|
788
|
+
|
789
|
+
|
790
|
+
namespace dense_storage {
|
682
791
|
|
683
792
|
/////////////////////////
|
684
793
|
// Templated Functions //
|
data/ext/nmatrix/storage/dense.h
CHANGED
@@ -72,7 +72,9 @@ extern "C" {
|
|
72
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
|
-
void nm_dense_storage_mark(
|
75
|
+
void nm_dense_storage_mark(STORAGE*);
|
76
|
+
void nm_dense_storage_register_values(VALUE* values, size_t n);
|
77
|
+
void nm_dense_storage_unregister_values(VALUE* values, size_t n);
|
76
78
|
|
77
79
|
///////////////
|
78
80
|
// Accessors //
|
@@ -83,9 +85,9 @@ VALUE nm_dense_map_pair(VALUE self, VALUE right);
|
|
83
85
|
VALUE nm_dense_map(VALUE self);
|
84
86
|
VALUE nm_dense_each(VALUE nmatrix);
|
85
87
|
VALUE nm_dense_each_with_indices(VALUE nmatrix);
|
86
|
-
void* nm_dense_storage_get(STORAGE* s, SLICE* slice);
|
87
|
-
void* nm_dense_storage_ref(STORAGE* s, SLICE* slice);
|
88
|
-
void
|
88
|
+
void* nm_dense_storage_get(const STORAGE* s, SLICE* slice);
|
89
|
+
void* nm_dense_storage_ref(const STORAGE* s, SLICE* slice);
|
90
|
+
void nm_dense_storage_set(VALUE left, SLICE* slice, VALUE right);
|
89
91
|
|
90
92
|
///////////
|
91
93
|
// Tests //
|
@@ -118,4 +120,8 @@ STORAGE* nm_dense_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_d
|
|
118
120
|
|
119
121
|
} // end of extern "C" block
|
120
122
|
|
123
|
+
namespace nm {
|
124
|
+
std::pair<NMATRIX*,bool> interpret_arg_as_dense_nmatrix(VALUE right, nm::dtype_t dtype);
|
125
|
+
} // end of namespace nm
|
126
|
+
|
121
127
|
#endif // DENSE_H
|
@@ -43,6 +43,7 @@
|
|
43
43
|
|
44
44
|
#include "data/data.h"
|
45
45
|
|
46
|
+
#include "dense.h"
|
46
47
|
#include "common.h"
|
47
48
|
#include "list.h"
|
48
49
|
|
@@ -57,6 +58,11 @@
|
|
57
58
|
* Global Variables
|
58
59
|
*/
|
59
60
|
|
61
|
+
|
62
|
+
extern "C" {
|
63
|
+
static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coords, size_t* lengths, size_t n);
|
64
|
+
}
|
65
|
+
|
60
66
|
namespace nm { namespace list_storage {
|
61
67
|
|
62
68
|
/*
|
@@ -126,7 +132,7 @@ protected:
|
|
126
132
|
|
127
133
|
|
128
134
|
template <typename LDType, typename RDType>
|
129
|
-
static LIST_STORAGE* cast_copy(const LIST_STORAGE* rhs, dtype_t new_dtype);
|
135
|
+
static LIST_STORAGE* cast_copy(const LIST_STORAGE* rhs, nm::dtype_t new_dtype);
|
130
136
|
|
131
137
|
template <typename LDType, typename RDType>
|
132
138
|
static bool eqeq_r(RecurseData& left, RecurseData& right, const LIST* l, const LIST* r, size_t rec);
|
@@ -246,8 +252,171 @@ static void map_merged_stored_r(RecurseData& result, RecurseData& left, RecurseD
|
|
246
252
|
}
|
247
253
|
}
|
248
254
|
|
255
|
+
/*
|
256
|
+
* Recursive function, sets multiple values in a matrix from multiple source values. Also handles removal; returns true
|
257
|
+
* if the recursion results in an empty list at that level (which signals that the current parent should be removed).
|
258
|
+
*/
|
259
|
+
template <typename D>
|
260
|
+
static bool slice_set(LIST_STORAGE* dest, LIST* l, size_t* coords, size_t* lengths, size_t n, D* v, size_t v_size, size_t& v_offset) {
|
261
|
+
using nm::list::node_is_within_slice;
|
262
|
+
using nm::list::remove_by_node;
|
263
|
+
using nm::list::find_preceding_from_list;
|
264
|
+
using nm::list::insert_first_list;
|
265
|
+
using nm::list::insert_first_node;
|
266
|
+
using nm::list::insert_after;
|
267
|
+
size_t* offsets = dest->offset;
|
268
|
+
|
269
|
+
// drill down into the structure
|
270
|
+
NODE* prev = find_preceding_from_list(l, coords[n] + offsets[n]);
|
271
|
+
NODE* node = NULL;
|
272
|
+
if (prev) node = prev->next && node_is_within_slice(prev->next, coords[n] + offsets[n], lengths[n]) ? prev->next : NULL;
|
273
|
+
else node = node_is_within_slice(l->first, coords[n] + offsets[n], lengths[n]) ? l->first : NULL;
|
274
|
+
|
275
|
+
if (dest->dim - n > 1) {
|
276
|
+
size_t i = 0;
|
277
|
+
size_t key = i + offsets[n] + coords[n];
|
278
|
+
|
279
|
+
// Make sure we have an element to work with
|
280
|
+
if (!node) {
|
281
|
+
if (!prev) {
|
282
|
+
node = insert_first_list(l, key, nm::list::create());
|
283
|
+
} else {
|
284
|
+
node = insert_after(prev, key, nm::list::create());
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
// At this point, it's guaranteed that there is a list here matching key.
|
289
|
+
|
290
|
+
while (node) {
|
291
|
+
// Recurse down into the list. If it returns true, it's empty, so we need to delete it.
|
292
|
+
bool remove_parent = slice_set(dest, reinterpret_cast<LIST*>(node->val), coords, lengths, n+1, v, v_size, v_offset);
|
293
|
+
|
294
|
+
if (remove_parent) {
|
295
|
+
xfree(remove_by_node(l, prev, node));
|
296
|
+
if (prev) node = prev->next ? prev->next : NULL;
|
297
|
+
else node = l->first ? l->first : NULL;
|
298
|
+
} else { // move forward
|
299
|
+
prev = node;
|
300
|
+
node = node_is_within_slice(prev->next, key-i, lengths[n]) ? prev->next : NULL;
|
301
|
+
}
|
302
|
+
|
303
|
+
++i; ++key;
|
304
|
+
|
305
|
+
if (i >= lengths[n]) break;
|
306
|
+
|
307
|
+
// Now do we need to insert another node here? Or is there already one?
|
308
|
+
if (!node) {
|
309
|
+
if (!prev) {
|
310
|
+
node = insert_first_list(l, key, nm::list::create());
|
311
|
+
} else {
|
312
|
+
node = insert_after(prev, key, nm::list::create());
|
313
|
+
}
|
314
|
+
}
|
315
|
+
}
|
316
|
+
|
317
|
+
} else {
|
318
|
+
|
319
|
+
size_t i = 0;
|
320
|
+
size_t key = i + offsets[n] + coords[n];
|
321
|
+
|
322
|
+
while (i < lengths[n]) {
|
323
|
+
// Make sure we have an element to work with
|
324
|
+
if (v_offset >= v_size) v_offset %= v_size;
|
325
|
+
|
326
|
+
if (node) {
|
327
|
+
if (node->key == key) {
|
328
|
+
if (v[v_offset] == *reinterpret_cast<D*>(dest->default_val)) { // remove zero value
|
329
|
+
|
330
|
+
xfree(remove_by_node(l, (prev ? prev : l->first), node));
|
331
|
+
|
332
|
+
if (prev) node = prev->next ? prev->next : NULL;
|
333
|
+
else node = l->first ? l->first : NULL;
|
334
|
+
|
335
|
+
} else { // edit directly
|
336
|
+
*reinterpret_cast<D*>(node->val) = v[v_offset];
|
337
|
+
prev = node;
|
338
|
+
node = node->next ? node->next : NULL;
|
339
|
+
}
|
340
|
+
} else if (node->key > key) {
|
341
|
+
D* nv = ALLOC(D); *nv = v[v_offset];
|
342
|
+
if (prev) node = insert_after(prev, key, nv);
|
343
|
+
else node = insert_first_node(l, key, nv, sizeof(D));
|
344
|
+
|
345
|
+
prev = node;
|
346
|
+
node = prev->next ? prev->next : NULL;
|
347
|
+
}
|
348
|
+
} else { // no node -- insert a new one
|
349
|
+
D* nv = ALLOC(D); *nv = v[v_offset];
|
350
|
+
if (prev) node = insert_after(prev, key, nv);
|
351
|
+
else node = insert_first_node(l, key, nv, sizeof(D));
|
352
|
+
|
353
|
+
prev = node;
|
354
|
+
node = prev->next ? prev->next : NULL;
|
355
|
+
}
|
356
|
+
|
357
|
+
++i; ++key;
|
358
|
+
}
|
359
|
+
}
|
360
|
+
|
361
|
+
return (l->first) ? false : true;
|
362
|
+
}
|
363
|
+
|
364
|
+
|
365
|
+
template <typename D>
|
366
|
+
void set(VALUE left, SLICE* slice, VALUE right) {
|
367
|
+
LIST_STORAGE* s = NM_STORAGE_LIST(left);
|
368
|
+
|
369
|
+
std::pair<NMATRIX*,bool> nm_and_free =
|
370
|
+
interpret_arg_as_dense_nmatrix(right, NM_DTYPE(left));
|
371
|
+
|
372
|
+
// Map the data onto D* v.
|
373
|
+
D* v;
|
374
|
+
size_t v_size = 1;
|
375
|
+
|
376
|
+
if (nm_and_free.first) {
|
377
|
+
DENSE_STORAGE* t = reinterpret_cast<DENSE_STORAGE*>(nm_and_free.first->storage);
|
378
|
+
v = reinterpret_cast<D*>(t->elements);
|
379
|
+
v_size = nm_storage_count_max_elements(t);
|
380
|
+
|
381
|
+
} else if (TYPE(right) == T_ARRAY) {
|
382
|
+
v_size = RARRAY_LEN(right);
|
383
|
+
v = ALLOC_N(D, v_size);
|
384
|
+
for (size_t m = 0; m < v_size; ++m) {
|
385
|
+
rubyval_to_cval(rb_ary_entry(right, m), s->dtype, &(v[m]));
|
386
|
+
}
|
387
|
+
} else {
|
388
|
+
v = reinterpret_cast<D*>(rubyobj_to_cval(right, NM_DTYPE(left)));
|
389
|
+
}
|
390
|
+
|
391
|
+
if (v_size == 1 && *v == *reinterpret_cast<D*>(s->default_val)) {
|
392
|
+
nm::list::remove_recursive(s->rows, slice->coords, s->offset, slice->lengths, 0, s->dim);
|
393
|
+
} else if (slice->single) {
|
394
|
+
slice_set_single(s, s->rows, reinterpret_cast<void*>(v), slice->coords, slice->lengths, 0);
|
395
|
+
} else {
|
396
|
+
size_t v_offset = 0;
|
397
|
+
slice_set<D>(s, s->rows, slice->coords, slice->lengths, 0, v, v_size, v_offset);
|
398
|
+
}
|
399
|
+
|
400
|
+
|
401
|
+
// Only free v if it was allocated in this function.
|
402
|
+
if (nm_and_free.first) {
|
403
|
+
if (nm_and_free.second) {
|
404
|
+
nm_delete(nm_and_free.first);
|
405
|
+
}
|
406
|
+
} else xfree(v);
|
407
|
+
}
|
408
|
+
|
409
|
+
/*
|
410
|
+
* Used only to set a default initial value.
|
411
|
+
*/
|
412
|
+
template <typename D>
|
413
|
+
void init_default(LIST_STORAGE* s) {
|
414
|
+
s->default_val = ALLOC(D);
|
415
|
+
*reinterpret_cast<D*>(s->default_val) = 0;
|
416
|
+
}
|
417
|
+
|
249
418
|
|
250
|
-
} // end of namespace list_storage
|
419
|
+
}} // end of namespace list_storage
|
251
420
|
|
252
421
|
extern "C" {
|
253
422
|
|
@@ -260,6 +429,7 @@ extern "C" {
|
|
260
429
|
// Lifecycle //
|
261
430
|
///////////////
|
262
431
|
|
432
|
+
|
263
433
|
/*
|
264
434
|
* Creates a list-of-lists(-of-lists-of-lists-etc) storage framework for a
|
265
435
|
* matrix.
|
@@ -267,7 +437,7 @@ extern "C" {
|
|
267
437
|
* Note: The pointers you pass in for shape and init_val become property of our
|
268
438
|
* new storage. You don't need to free them, and you shouldn't re-use them.
|
269
439
|
*/
|
270
|
-
LIST_STORAGE* nm_list_storage_create(dtype_t dtype, size_t* shape, size_t dim, void* init_val) {
|
440
|
+
LIST_STORAGE* nm_list_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, void* init_val) {
|
271
441
|
LIST_STORAGE* s = ALLOC( LIST_STORAGE );
|
272
442
|
|
273
443
|
s->dim = dim;
|
@@ -277,8 +447,13 @@ LIST_STORAGE* nm_list_storage_create(dtype_t dtype, size_t* shape, size_t dim, v
|
|
277
447
|
s->offset = ALLOC_N(size_t, s->dim);
|
278
448
|
memset(s->offset, 0, s->dim * sizeof(size_t));
|
279
449
|
|
280
|
-
s->rows = list::create();
|
281
|
-
|
450
|
+
s->rows = nm::list::create();
|
451
|
+
if (init_val)
|
452
|
+
s->default_val = init_val;
|
453
|
+
else {
|
454
|
+
DTYPE_TEMPLATE_TABLE(nm::list_storage::init_default, void, LIST_STORAGE*)
|
455
|
+
ttable[dtype](s);
|
456
|
+
}
|
282
457
|
s->count = 1;
|
283
458
|
s->src = s;
|
284
459
|
|
@@ -292,7 +467,7 @@ void nm_list_storage_delete(STORAGE* s) {
|
|
292
467
|
if (s) {
|
293
468
|
LIST_STORAGE* storage = (LIST_STORAGE*)s;
|
294
469
|
if (storage->count-- == 1) {
|
295
|
-
list::del( storage->rows, storage->dim - 1 );
|
470
|
+
nm::list::del( storage->rows, storage->dim - 1 );
|
296
471
|
|
297
472
|
xfree(storage->shape);
|
298
473
|
xfree(storage->offset);
|
@@ -319,12 +494,12 @@ void nm_list_storage_delete_ref(STORAGE* s) {
|
|
319
494
|
/*
|
320
495
|
* Documentation goes here.
|
321
496
|
*/
|
322
|
-
void nm_list_storage_mark(
|
497
|
+
void nm_list_storage_mark(STORAGE* storage_base) {
|
323
498
|
LIST_STORAGE* storage = (LIST_STORAGE*)storage_base;
|
324
499
|
|
325
|
-
if (storage && storage->dtype == RUBYOBJ) {
|
500
|
+
if (storage && storage->dtype == nm::RUBYOBJ) {
|
326
501
|
rb_gc_mark(*((VALUE*)(storage->default_val)));
|
327
|
-
list::mark(storage->rows, storage->dim - 1);
|
502
|
+
nm::list::mark(storage->rows, storage->dim - 1);
|
328
503
|
}
|
329
504
|
}
|
330
505
|
|
@@ -342,7 +517,7 @@ static NODE* list_storage_get_single_node(LIST_STORAGE* s, SLICE* slice)
|
|
342
517
|
NODE* n;
|
343
518
|
|
344
519
|
for (r = 0; r < s->dim; r++) {
|
345
|
-
n = list::find(l, s->offset[r] + slice->coords[r]);
|
520
|
+
n = nm::list::find(l, s->offset[r] + slice->coords[r]);
|
346
521
|
if (n) l = reinterpret_cast<LIST*>(n->val);
|
347
522
|
else return NULL;
|
348
523
|
}
|
@@ -537,41 +712,36 @@ VALUE nm_list_map_merged_stored(VALUE left, VALUE right, VALUE init) {
|
|
537
712
|
// If we are working with a scalar operation
|
538
713
|
if (scalar) nm_list_storage_delete(t);
|
539
714
|
|
540
|
-
return Data_Wrap_Struct(CLASS_OF(left),
|
715
|
+
return Data_Wrap_Struct(CLASS_OF(left), nm_mark, nm_delete, result);
|
541
716
|
}
|
542
717
|
|
543
718
|
|
544
719
|
/*
|
545
720
|
* Copy a slice of a list matrix into a regular list matrix.
|
546
721
|
*/
|
547
|
-
static LIST* slice_copy(const LIST_STORAGE
|
722
|
+
static LIST* slice_copy(const LIST_STORAGE* src, LIST* src_rows, size_t* coords, size_t* lengths, size_t n) {
|
548
723
|
|
549
|
-
NODE *src_node;
|
550
|
-
LIST *dst_rows = NULL;
|
551
724
|
void *val = NULL;
|
552
725
|
int key;
|
553
726
|
|
554
|
-
dst_rows = list::create();
|
555
|
-
src_node = src_rows->first;
|
727
|
+
LIST* dst_rows = nm::list::create();
|
728
|
+
NODE* src_node = src_rows->first;
|
556
729
|
|
557
730
|
while (src_node) {
|
558
731
|
key = src_node->key - (src->offset[n] + coords[n]);
|
559
732
|
|
560
733
|
if (key >= 0 && (size_t)key < lengths[n]) {
|
561
734
|
if (src->dim - n > 1) {
|
562
|
-
val = slice_copy(src,
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
if (val)
|
569
|
-
list::insert_with_copy(dst_rows, key, val, sizeof(LIST));
|
570
|
-
|
571
|
-
}
|
572
|
-
else {
|
573
|
-
list::insert_with_copy(dst_rows, key, src_node->val, DTYPE_SIZES[src->dtype]);
|
735
|
+
val = slice_copy( src,
|
736
|
+
reinterpret_cast<LIST*>(src_node->val),
|
737
|
+
coords,
|
738
|
+
lengths,
|
739
|
+
n + 1 );
|
740
|
+
|
741
|
+
if (val) { nm::list::insert_copy(dst_rows, false, key, val, sizeof(LIST)); }
|
574
742
|
}
|
743
|
+
|
744
|
+
else nm::list::insert_copy(dst_rows, false, key, src_node->val, DTYPE_SIZES[src->dtype]);
|
575
745
|
}
|
576
746
|
|
577
747
|
src_node = src_node->next;
|
@@ -583,7 +753,7 @@ static LIST* slice_copy(const LIST_STORAGE *src, LIST *src_rows, size_t *coords,
|
|
583
753
|
/*
|
584
754
|
* Documentation goes here.
|
585
755
|
*/
|
586
|
-
void* nm_list_storage_get(STORAGE* storage, SLICE* slice) {
|
756
|
+
void* nm_list_storage_get(const STORAGE* storage, SLICE* slice) {
|
587
757
|
LIST_STORAGE* s = (LIST_STORAGE*)storage;
|
588
758
|
LIST_STORAGE* ns = NULL;
|
589
759
|
NODE* n;
|
@@ -609,7 +779,7 @@ void* nm_list_storage_get(STORAGE* storage, SLICE* slice) {
|
|
609
779
|
* Get the contents of some set of coordinates. Note: Does not make a copy!
|
610
780
|
* Don't free!
|
611
781
|
*/
|
612
|
-
void* nm_list_storage_ref(STORAGE* storage, SLICE* slice) {
|
782
|
+
void* nm_list_storage_ref(const STORAGE* storage, SLICE* slice) {
|
613
783
|
LIST_STORAGE* s = (LIST_STORAGE*)storage;
|
614
784
|
LIST_STORAGE* ns = NULL;
|
615
785
|
NODE* n;
|
@@ -642,12 +812,63 @@ void* nm_list_storage_ref(STORAGE* storage, SLICE* slice) {
|
|
642
812
|
}
|
643
813
|
}
|
644
814
|
|
815
|
+
|
645
816
|
/*
|
646
|
-
*
|
817
|
+
* Recursive function, sets multiple values in a matrix from a single source value.
|
818
|
+
*/
|
819
|
+
static void slice_set_single(LIST_STORAGE* dest, LIST* l, void* val, size_t* coords, size_t* lengths, size_t n) {
|
820
|
+
|
821
|
+
// drill down into the structure
|
822
|
+
NODE* node = NULL;
|
823
|
+
if (dest->dim - n > 1) {
|
824
|
+
for (size_t i = 0; i < lengths[n]; ++i) {
|
825
|
+
|
826
|
+
size_t key = i + dest->offset[n] + coords[n];
|
827
|
+
|
828
|
+
if (!node) {
|
829
|
+
node = nm::list::insert(l, false, key, nm::list::create()); // try to insert list
|
830
|
+
} else if (!node->next || (node->next && node->next->key > key)) {
|
831
|
+
node = nm::list::insert_after(node, key, nm::list::create());
|
832
|
+
} else {
|
833
|
+
node = node->next; // correct rank already exists.
|
834
|
+
}
|
835
|
+
|
836
|
+
// cast it to a list and recurse
|
837
|
+
slice_set_single(dest, reinterpret_cast<LIST*>(node->val), val, coords, lengths, n + 1);
|
838
|
+
}
|
839
|
+
} else {
|
840
|
+
for (size_t i = 0; i < lengths[n]; ++i) {
|
841
|
+
|
842
|
+
size_t key = i + dest->offset[n] + coords[n];
|
843
|
+
|
844
|
+
if (!node) {
|
845
|
+
node = nm::list::insert_copy(l, true, key, val, DTYPE_SIZES[dest->dtype]);
|
846
|
+
} else {
|
847
|
+
node = nm::list::replace_insert_after(node, key, val, true, DTYPE_SIZES[dest->dtype]);
|
848
|
+
}
|
849
|
+
}
|
850
|
+
}
|
851
|
+
}
|
852
|
+
|
853
|
+
|
854
|
+
|
855
|
+
/*
|
856
|
+
* Set a value or values in a list matrix.
|
857
|
+
*/
|
858
|
+
void nm_list_storage_set(VALUE left, SLICE* slice, VALUE right) {
|
859
|
+
NAMED_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::set, void, VALUE, SLICE*, VALUE)
|
860
|
+
ttable[NM_DTYPE(left)](left, slice, right);
|
861
|
+
}
|
862
|
+
|
863
|
+
|
864
|
+
/*
|
865
|
+
* Insert an entry directly in a row (not using copy! don't free after).
|
866
|
+
*
|
867
|
+
* Returns a pointer to the insertion location.
|
647
868
|
*
|
648
869
|
* TODO: Allow this function to accept an entire row and not just one value -- for slicing
|
649
870
|
*/
|
650
|
-
|
871
|
+
NODE* nm_list_storage_insert(STORAGE* storage, SLICE* slice, void* val) {
|
651
872
|
LIST_STORAGE* s = (LIST_STORAGE*)storage;
|
652
873
|
// Pretend dims = 2
|
653
874
|
// Then coords is going to be size 2
|
@@ -658,27 +879,23 @@ void* nm_list_storage_insert(STORAGE* storage, SLICE* slice, void* val) {
|
|
658
879
|
|
659
880
|
// drill down into the structure
|
660
881
|
for (r = s->dim; r > 1; --r) {
|
661
|
-
n = list::insert(l, false, s->offset[s->dim - r] + slice->coords[s->dim - r], list::create());
|
882
|
+
n = nm::list::insert(l, false, s->offset[s->dim - r] + slice->coords[s->dim - r], nm::list::create());
|
662
883
|
l = reinterpret_cast<LIST*>(n->val);
|
663
884
|
}
|
664
885
|
|
665
|
-
|
666
|
-
return n->val;
|
886
|
+
return nm::list::insert(l, true, s->offset[s->dim - r] + slice->coords[s->dim - r], val);
|
667
887
|
}
|
668
888
|
|
669
889
|
/*
|
670
|
-
* Remove an item from list storage.
|
890
|
+
* Remove an item or slice from list storage.
|
671
891
|
*/
|
672
|
-
void
|
892
|
+
void nm_list_storage_remove(STORAGE* storage, SLICE* slice) {
|
673
893
|
LIST_STORAGE* s = (LIST_STORAGE*)storage;
|
674
|
-
void* rm = NULL;
|
675
894
|
|
676
895
|
// This returns a boolean, which will indicate whether s->rows is empty.
|
677
896
|
// We can safely ignore it, since we never want to delete s->rows until
|
678
897
|
// it's time to destroy the LIST_STORAGE object.
|
679
|
-
list::remove_recursive(s->rows, slice->coords, s->offset, 0, s->dim
|
680
|
-
|
681
|
-
return rm;
|
898
|
+
nm::list::remove_recursive(s->rows, slice->coords, s->offset, slice->lengths, 0, s->dim);
|
682
899
|
}
|
683
900
|
|
684
901
|
///////////
|
@@ -719,7 +936,7 @@ STORAGE* nm_list_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, siz
|
|
719
936
|
* List storage to Hash conversion. Uses Hashes with default values, so you can continue to pretend
|
720
937
|
* it's a sparse matrix.
|
721
938
|
*/
|
722
|
-
VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const dtype_t dtype) {
|
939
|
+
VALUE nm_list_storage_to_hash(const LIST_STORAGE* s, const nm::dtype_t dtype) {
|
723
940
|
|
724
941
|
// Get the default value for the list storage.
|
725
942
|
VALUE default_value = rubyobj_from_cval(s->default_val, dtype).rval;
|
@@ -807,8 +1024,8 @@ LIST_STORAGE* nm_list_storage_copy(const LIST_STORAGE* rhs)
|
|
807
1024
|
/*
|
808
1025
|
* List storage copy constructor C access with casting.
|
809
1026
|
*/
|
810
|
-
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, dtype_t new_dtype, void* dummy) {
|
811
|
-
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::cast_copy, LIST_STORAGE*, const LIST_STORAGE* rhs, dtype_t new_dtype);
|
1027
|
+
STORAGE* nm_list_storage_cast_copy(const STORAGE* rhs, nm::dtype_t new_dtype, void* dummy) {
|
1028
|
+
NAMED_LR_DTYPE_TEMPLATE_TABLE(ttable, nm::list_storage::cast_copy, LIST_STORAGE*, const LIST_STORAGE* rhs, nm::dtype_t new_dtype);
|
812
1029
|
|
813
1030
|
return (STORAGE*)ttable[new_dtype][rhs->dtype]((LIST_STORAGE*)rhs, new_dtype);
|
814
1031
|
}
|
@@ -831,7 +1048,7 @@ STORAGE* nm_list_storage_copy_transposed(const STORAGE* rhs_base) {
|
|
831
1048
|
/////////////////////////
|
832
1049
|
|
833
1050
|
|
834
|
-
|
1051
|
+
namespace nm {
|
835
1052
|
namespace list_storage {
|
836
1053
|
|
837
1054
|
|
@@ -850,14 +1067,14 @@ static LIST_STORAGE* cast_copy(const LIST_STORAGE* rhs, dtype_t new_dtype) {
|
|
850
1067
|
*default_val = *reinterpret_cast<RDType*>(rhs->default_val);
|
851
1068
|
|
852
1069
|
LIST_STORAGE* lhs = nm_list_storage_create(new_dtype, shape, rhs->dim, default_val);
|
853
|
-
//lhs->rows = list::create();
|
1070
|
+
//lhs->rows = nm::list::create();
|
854
1071
|
|
855
1072
|
// TODO: Needs optimization. When matrix is reference it is copped twice.
|
856
1073
|
if (rhs->src == rhs)
|
857
|
-
list::cast_copy_contents<LDType, RDType>(lhs->rows, rhs->rows, rhs->dim - 1);
|
1074
|
+
nm::list::cast_copy_contents<LDType, RDType>(lhs->rows, rhs->rows, rhs->dim - 1);
|
858
1075
|
else {
|
859
1076
|
LIST_STORAGE *tmp = nm_list_storage_copy(rhs);
|
860
|
-
list::cast_copy_contents<LDType, RDType>(lhs->rows, tmp->rows, rhs->dim - 1);
|
1077
|
+
nm::list::cast_copy_contents<LDType, RDType>(lhs->rows, tmp->rows, rhs->dim - 1);
|
861
1078
|
nm_list_storage_delete(tmp);
|
862
1079
|
}
|
863
1080
|
|