nmatrix 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|