nmatrix 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +3 -5
- data/Guardfile +6 -0
- data/History.txt +33 -0
- data/Manifest.txt +41 -38
- data/README.rdoc +88 -11
- data/Rakefile +35 -53
- data/ext/nmatrix/data/complex.h +372 -0
- data/ext/nmatrix/data/data.cpp +275 -0
- data/ext/nmatrix/data/data.h +707 -0
- data/ext/nmatrix/data/rational.h +421 -0
- data/ext/nmatrix/data/ruby_object.h +446 -0
- data/ext/nmatrix/extconf.rb +101 -51
- data/ext/nmatrix/new_extconf.rb +56 -0
- data/ext/nmatrix/nmatrix.cpp +1609 -0
- data/ext/nmatrix/nmatrix.h +265 -849
- data/ext/nmatrix/ruby_constants.cpp +134 -0
- data/ext/nmatrix/ruby_constants.h +103 -0
- data/ext/nmatrix/storage/common.cpp +70 -0
- data/ext/nmatrix/storage/common.h +170 -0
- data/ext/nmatrix/storage/dense.cpp +665 -0
- data/ext/nmatrix/storage/dense.h +116 -0
- data/ext/nmatrix/storage/list.cpp +1088 -0
- data/ext/nmatrix/storage/list.h +129 -0
- data/ext/nmatrix/storage/storage.cpp +658 -0
- data/ext/nmatrix/storage/storage.h +99 -0
- data/ext/nmatrix/storage/yale.cpp +1601 -0
- data/ext/nmatrix/storage/yale.h +208 -0
- data/ext/nmatrix/ttable_helper.rb +126 -0
- data/ext/nmatrix/{yale/smmp1_header.template.c → types.h} +36 -9
- data/ext/nmatrix/util/io.cpp +295 -0
- data/ext/nmatrix/util/io.h +117 -0
- data/ext/nmatrix/util/lapack.h +1175 -0
- data/ext/nmatrix/util/math.cpp +557 -0
- data/ext/nmatrix/util/math.h +1363 -0
- data/ext/nmatrix/util/sl_list.cpp +475 -0
- data/ext/nmatrix/util/sl_list.h +255 -0
- data/ext/nmatrix/util/util.h +78 -0
- data/lib/nmatrix/blas.rb +70 -0
- data/lib/nmatrix/io/mat5_reader.rb +567 -0
- data/lib/nmatrix/io/mat_reader.rb +162 -0
- data/lib/{string.rb → nmatrix/monkeys.rb} +49 -2
- data/lib/nmatrix/nmatrix.rb +199 -0
- data/lib/nmatrix/nvector.rb +103 -0
- data/lib/nmatrix/version.rb +27 -0
- data/lib/nmatrix.rb +22 -230
- data/nmatrix.gemspec +59 -0
- data/scripts/mac-brew-gcc.sh +47 -0
- data/spec/4x4_sparse.mat +0 -0
- data/spec/4x5_dense.mat +0 -0
- data/spec/blas_spec.rb +47 -0
- data/spec/elementwise_spec.rb +164 -0
- data/spec/io_spec.rb +60 -0
- data/spec/lapack_spec.rb +52 -0
- data/spec/math_spec.rb +96 -0
- data/spec/nmatrix_spec.rb +93 -89
- data/spec/nmatrix_yale_spec.rb +52 -36
- data/spec/nvector_spec.rb +1 -1
- data/spec/slice_spec.rb +257 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/utm5940.mtx +83844 -0
- metadata +113 -71
- data/.autotest +0 -23
- data/.gemtest +0 -0
- data/ext/nmatrix/cblas.c +0 -150
- data/ext/nmatrix/dense/blas_header.template.c +0 -52
- data/ext/nmatrix/dense/elementwise.template.c +0 -107
- data/ext/nmatrix/dense/gemm.template.c +0 -159
- data/ext/nmatrix/dense/gemv.template.c +0 -130
- data/ext/nmatrix/dense/rationalmath.template.c +0 -68
- data/ext/nmatrix/dense.c +0 -307
- data/ext/nmatrix/depend +0 -18
- data/ext/nmatrix/generator/syntax_tree.rb +0 -481
- data/ext/nmatrix/generator.rb +0 -594
- data/ext/nmatrix/list.c +0 -774
- data/ext/nmatrix/nmatrix.c +0 -1977
- data/ext/nmatrix/rational.c +0 -98
- data/ext/nmatrix/yale/complexmath.template.c +0 -71
- data/ext/nmatrix/yale/elementwise.template.c +0 -46
- data/ext/nmatrix/yale/elementwise_op.template.c +0 -73
- data/ext/nmatrix/yale/numbmm.template.c +0 -94
- data/ext/nmatrix/yale/smmp1.template.c +0 -21
- data/ext/nmatrix/yale/smmp2.template.c +0 -43
- data/ext/nmatrix/yale/smmp2_header.template.c +0 -46
- data/ext/nmatrix/yale/sort_columns.template.c +0 -56
- data/ext/nmatrix/yale/symbmm.template.c +0 -54
- data/ext/nmatrix/yale/transp.template.c +0 -68
- data/ext/nmatrix/yale.c +0 -726
- data/lib/array.rb +0 -67
- data/spec/syntax_tree_spec.rb +0 -46
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
|
|
3
|
+
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
|
|
4
|
+
//
|
|
5
|
+
// Please see LICENSE.txt for additional copyright notices.
|
|
6
|
+
//
|
|
7
|
+
// == Contributing
|
|
8
|
+
//
|
|
9
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
|
10
|
+
// our Contributor Agreement:
|
|
11
|
+
//
|
|
12
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
|
13
|
+
//
|
|
14
|
+
// == sl_list.cpp
|
|
15
|
+
//
|
|
16
|
+
// Singly-linked list implementation
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Standard Includes
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#include <ruby.h>
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* Project Includes
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
#include "types.h"
|
|
29
|
+
|
|
30
|
+
#include "data/data.h"
|
|
31
|
+
|
|
32
|
+
#include "sl_list.h"
|
|
33
|
+
|
|
34
|
+
namespace nm { namespace list {
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* Macros
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
* Global Variables
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* Forward Declarations
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Functions
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
////////////////
|
|
54
|
+
// Lifecycle //
|
|
55
|
+
///////////////
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* Creates an empty linked list.
|
|
59
|
+
*/
|
|
60
|
+
LIST* create(void) {
|
|
61
|
+
LIST* list;
|
|
62
|
+
|
|
63
|
+
//if (!(list = malloc(sizeof(LIST)))) return NULL;
|
|
64
|
+
list = ALLOC( LIST );
|
|
65
|
+
|
|
66
|
+
//fprintf(stderr, " create_list LIST: %p\n", list);
|
|
67
|
+
|
|
68
|
+
list->first = NULL;
|
|
69
|
+
return list;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* Deletes the linked list and all of its contents. If you want to delete a
|
|
74
|
+
* list inside of a list, set recursions to 1. For lists inside of lists inside
|
|
75
|
+
* of the list, set it to 2; and so on. Setting it to 0 is for no recursions.
|
|
76
|
+
*/
|
|
77
|
+
void del(LIST* list, size_t recursions) {
|
|
78
|
+
NODE* next;
|
|
79
|
+
NODE* curr = list->first;
|
|
80
|
+
|
|
81
|
+
while (curr != NULL) {
|
|
82
|
+
next = curr->next;
|
|
83
|
+
|
|
84
|
+
if (recursions == 0) {
|
|
85
|
+
//fprintf(stderr, " free_val: %p\n", curr->val);
|
|
86
|
+
free(curr->val);
|
|
87
|
+
|
|
88
|
+
} else {
|
|
89
|
+
//fprintf(stderr, " free_list: %p\n", list);
|
|
90
|
+
del((LIST*)curr->val, recursions - 1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
free(curr);
|
|
94
|
+
curr = next;
|
|
95
|
+
}
|
|
96
|
+
//fprintf(stderr, " free_list: %p\n", list);
|
|
97
|
+
free(list);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/*
|
|
101
|
+
* Documentation goes here.
|
|
102
|
+
*/
|
|
103
|
+
void mark(LIST* list, size_t recursions) {
|
|
104
|
+
NODE* next;
|
|
105
|
+
NODE* curr = list->first;
|
|
106
|
+
|
|
107
|
+
while (curr != NULL) {
|
|
108
|
+
next = curr->next;
|
|
109
|
+
|
|
110
|
+
if (recursions == 0) {
|
|
111
|
+
rb_gc_mark(*((VALUE*)(curr->val)));
|
|
112
|
+
|
|
113
|
+
} else {
|
|
114
|
+
mark((LIST*)curr->val, recursions - 1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
curr = next;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
///////////////
|
|
122
|
+
// Accessors //
|
|
123
|
+
///////////////
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
* Given a list and a key/value-ptr pair, create a node (and return that node).
|
|
127
|
+
* If NULL is returned, it means insertion failed.
|
|
128
|
+
* If the key already exists in the list, replace tells it to delete the old
|
|
129
|
+
* value and put in your new one. !replace means delete the new value.
|
|
130
|
+
*/
|
|
131
|
+
NODE* insert(LIST* list, bool replace, size_t key, void* val) {
|
|
132
|
+
NODE *ins;
|
|
133
|
+
|
|
134
|
+
if (list->first == NULL) {
|
|
135
|
+
// List is empty
|
|
136
|
+
|
|
137
|
+
//if (!(ins = malloc(sizeof(NODE)))) return NULL;
|
|
138
|
+
ins = ALLOC(NODE);
|
|
139
|
+
ins->next = NULL;
|
|
140
|
+
ins->val = val;
|
|
141
|
+
ins->key = key;
|
|
142
|
+
list->first = ins;
|
|
143
|
+
|
|
144
|
+
return ins;
|
|
145
|
+
|
|
146
|
+
} else if (key < list->first->key) {
|
|
147
|
+
// Goes at the beginning of the list
|
|
148
|
+
|
|
149
|
+
//if (!(ins = malloc(sizeof(NODE)))) return NULL;
|
|
150
|
+
ins = ALLOC(NODE);
|
|
151
|
+
ins->next = list->first;
|
|
152
|
+
ins->val = val;
|
|
153
|
+
ins->key = key;
|
|
154
|
+
list->first = ins;
|
|
155
|
+
|
|
156
|
+
return ins;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Goes somewhere else in the list.
|
|
160
|
+
ins = find_nearest_from(list->first, key);
|
|
161
|
+
|
|
162
|
+
if (ins->key == key) {
|
|
163
|
+
// key already exists
|
|
164
|
+
if (replace) {
|
|
165
|
+
free(ins->val);
|
|
166
|
+
ins->val = val;
|
|
167
|
+
|
|
168
|
+
} else {
|
|
169
|
+
free(val);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return ins;
|
|
173
|
+
|
|
174
|
+
} else {
|
|
175
|
+
return insert_after(ins, key, val);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Documentation goes here.
|
|
181
|
+
*/
|
|
182
|
+
NODE* insert_after(NODE* node, size_t key, void* val) {
|
|
183
|
+
NODE* ins;
|
|
184
|
+
|
|
185
|
+
//if (!(ins = malloc(sizeof(NODE)))) return NULL;
|
|
186
|
+
ins = ALLOC(NODE);
|
|
187
|
+
|
|
188
|
+
// insert 'ins' between 'node' and 'node->next'
|
|
189
|
+
ins->next = node->next;
|
|
190
|
+
node->next = ins;
|
|
191
|
+
|
|
192
|
+
// initialize our new node
|
|
193
|
+
ins->key = key;
|
|
194
|
+
ins->val = val;
|
|
195
|
+
|
|
196
|
+
return ins;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/*
|
|
200
|
+
* Analog functions list_insert but this insert copy of value.
|
|
201
|
+
*/
|
|
202
|
+
NODE* insert_with_copy(LIST *list, size_t key, void *val, size_t size) {
|
|
203
|
+
void *copy_val = ALLOC_N(char, size);
|
|
204
|
+
memcpy(copy_val, val, size);
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
return insert(list, false, key, copy_val);
|
|
208
|
+
}
|
|
209
|
+
/*
|
|
210
|
+
* Returns the value pointer (not the node) for some key. Note that it doesn't
|
|
211
|
+
* free the memory for the value stored in the node -- that pointer gets
|
|
212
|
+
* returned! Only the node is destroyed.
|
|
213
|
+
*/
|
|
214
|
+
void* remove(LIST* list, size_t key) {
|
|
215
|
+
NODE *f, *rm;
|
|
216
|
+
void* val;
|
|
217
|
+
|
|
218
|
+
if (!list->first || list->first->key > key) { // empty list or def. not present
|
|
219
|
+
return NULL;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (list->first->key == key) {
|
|
223
|
+
val = list->first->val;
|
|
224
|
+
rm = list->first;
|
|
225
|
+
|
|
226
|
+
list->first = rm->next;
|
|
227
|
+
free(rm);
|
|
228
|
+
|
|
229
|
+
return val;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
f = find_preceding_from(list->first, key);
|
|
233
|
+
if (!f || !f->next) { // not found, end of list
|
|
234
|
+
return NULL;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (f->next->key == key) {
|
|
238
|
+
// remove the node
|
|
239
|
+
rm = f->next;
|
|
240
|
+
f->next = rm->next;
|
|
241
|
+
|
|
242
|
+
// get the value and free the memory for the node
|
|
243
|
+
val = rm->val;
|
|
244
|
+
free(rm);
|
|
245
|
+
|
|
246
|
+
return val;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return NULL; // not found, middle of list
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* Recursive removal of lists that may contain sub-lists. Stores the value ultimately removed in rm.
|
|
255
|
+
*
|
|
256
|
+
* FIXME: Could be made slightly faster by using a variety of find which also returns the previous node. This way,
|
|
257
|
+
* FIXME: we can remove directly instead of calling remove() and doing the search over again.
|
|
258
|
+
*/
|
|
259
|
+
bool remove_recursive(LIST* list, const size_t* coords, const size_t* offset, size_t r, const size_t& dim, void* rm) {
|
|
260
|
+
|
|
261
|
+
if (r < dim-1) { // nodes here are lists
|
|
262
|
+
// find the current coordinates in the list
|
|
263
|
+
NODE* n = find(list, coords[r] + offset[r]);
|
|
264
|
+
|
|
265
|
+
if (n) {
|
|
266
|
+
// from that sub-list, call remove_recursive.
|
|
267
|
+
bool remove_parent = remove_recursive(reinterpret_cast<LIST*>(n->val), coords, offset, r+1, dim, rm);
|
|
268
|
+
|
|
269
|
+
if (remove_parent) { // now empty -- so remove the sub-list
|
|
270
|
+
free(remove(list, coords[r] + offset[r]));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
} else { // nodes here are not lists, but actual values
|
|
275
|
+
rm = remove(list, coords[r] + offset[r]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!list->first) return true; // if current list is now empty, signal its removal
|
|
279
|
+
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
///////////
|
|
284
|
+
// Tests //
|
|
285
|
+
///////////
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
/////////////
|
|
289
|
+
// Utility //
|
|
290
|
+
/////////////
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* Find some element in the list and return the node ptr for that key.
|
|
294
|
+
*/
|
|
295
|
+
NODE* find(LIST* list, size_t key) {
|
|
296
|
+
NODE* f;
|
|
297
|
+
if (!list->first) {
|
|
298
|
+
// empty list -- does not exist
|
|
299
|
+
return NULL;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// see if we can find it.
|
|
303
|
+
f = find_nearest_from(list->first, key);
|
|
304
|
+
|
|
305
|
+
if (!f || f->key == key) {
|
|
306
|
+
return f;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return NULL;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/*
|
|
313
|
+
* Finds the node that should go before whatever key we request, whether or not
|
|
314
|
+
* that key is present.
|
|
315
|
+
*/
|
|
316
|
+
NODE* find_preceding_from(NODE* prev, size_t key) {
|
|
317
|
+
NODE* curr = prev->next;
|
|
318
|
+
|
|
319
|
+
if (!curr || key <= curr->key) {
|
|
320
|
+
return prev;
|
|
321
|
+
|
|
322
|
+
} else {
|
|
323
|
+
return find_preceding_from(curr, key);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/*
|
|
328
|
+
* Finds the node or, if not present, the node that it should follow. NULL
|
|
329
|
+
* indicates no preceding node.
|
|
330
|
+
*/
|
|
331
|
+
NODE* find_nearest(LIST* list, size_t key) {
|
|
332
|
+
return find_nearest_from(list->first, key);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/*
|
|
336
|
+
* Finds a node or the one immediately preceding it if it doesn't exist.
|
|
337
|
+
*/
|
|
338
|
+
NODE* find_nearest_from(NODE* prev, size_t key) {
|
|
339
|
+
NODE* f;
|
|
340
|
+
|
|
341
|
+
if (prev && prev->key == key) {
|
|
342
|
+
return prev;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
f = find_preceding_from(prev, key);
|
|
346
|
+
|
|
347
|
+
if (!f->next) {
|
|
348
|
+
return f;
|
|
349
|
+
|
|
350
|
+
} else if (key == f->next->key) {
|
|
351
|
+
return f->next;
|
|
352
|
+
|
|
353
|
+
} else {
|
|
354
|
+
return prev;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/////////////////////////
|
|
359
|
+
// Copying and Casting //
|
|
360
|
+
/////////////////////////
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
/*
|
|
364
|
+
* Copy the contents of a list.
|
|
365
|
+
*/
|
|
366
|
+
template <typename LDType, typename RDType>
|
|
367
|
+
void cast_copy_contents(LIST* lhs, const LIST* rhs, size_t recursions) {
|
|
368
|
+
NODE *lcurr, *rcurr;
|
|
369
|
+
|
|
370
|
+
if (rhs->first) {
|
|
371
|
+
// copy head node
|
|
372
|
+
rcurr = rhs->first;
|
|
373
|
+
lcurr = lhs->first = ALLOC( NODE );
|
|
374
|
+
|
|
375
|
+
while (rcurr) {
|
|
376
|
+
lcurr->key = rcurr->key;
|
|
377
|
+
|
|
378
|
+
if (recursions == 0) {
|
|
379
|
+
// contents is some kind of value
|
|
380
|
+
|
|
381
|
+
lcurr->val = ALLOC( LDType );
|
|
382
|
+
|
|
383
|
+
*reinterpret_cast<LDType*>(lcurr->val) = *reinterpret_cast<RDType*>( rcurr->val );
|
|
384
|
+
|
|
385
|
+
} else {
|
|
386
|
+
// contents is a list
|
|
387
|
+
|
|
388
|
+
lcurr->val = ALLOC( LIST );
|
|
389
|
+
|
|
390
|
+
cast_copy_contents<LDType, RDType>(
|
|
391
|
+
reinterpret_cast<LIST*>(lcurr->val),
|
|
392
|
+
reinterpret_cast<LIST*>(rcurr->val),
|
|
393
|
+
recursions-1
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (rcurr->next) {
|
|
398
|
+
lcurr->next = ALLOC( NODE );
|
|
399
|
+
|
|
400
|
+
} else {
|
|
401
|
+
lcurr->next = NULL;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
lcurr = lcurr->next;
|
|
405
|
+
rcurr = rcurr->next;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
} else {
|
|
409
|
+
lhs->first = NULL;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
}} // end of namespace nm::list
|
|
414
|
+
|
|
415
|
+
extern "C" {
|
|
416
|
+
|
|
417
|
+
/*
|
|
418
|
+
* C access for copying the contents of a list.
|
|
419
|
+
*/
|
|
420
|
+
void nm_list_cast_copy_contents(LIST* lhs, const LIST* rhs, dtype_t lhs_dtype, dtype_t rhs_dtype, size_t recursions) {
|
|
421
|
+
LR_DTYPE_TEMPLATE_TABLE(nm::list::cast_copy_contents, void, LIST*, const LIST*, size_t);
|
|
422
|
+
|
|
423
|
+
ttable[lhs_dtype][rhs_dtype](lhs, rhs, recursions);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/*
|
|
427
|
+
* Sets up a hash with an appropriate default values. That means that if recursions == 0, the default value is default_value,
|
|
428
|
+
* but if recursions == 1, the default value is going to be a hash with default value of default_value, and if recursions == 2,
|
|
429
|
+
* the default value is going to be a hash with default value of hash with default value of default_value, and so on.
|
|
430
|
+
* In other words, it's recursive.
|
|
431
|
+
*/
|
|
432
|
+
static VALUE empty_list_to_hash(const dtype_t dtype, size_t recursions, VALUE default_value) {
|
|
433
|
+
VALUE h = rb_hash_new();
|
|
434
|
+
if (recursions) {
|
|
435
|
+
RHASH_IFNONE(h) = empty_list_to_hash(dtype, recursions-1, default_value);
|
|
436
|
+
} else {
|
|
437
|
+
RHASH_IFNONE(h) = default_value;
|
|
438
|
+
}
|
|
439
|
+
return h;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
* Copy a list to a Ruby Hash
|
|
445
|
+
*/
|
|
446
|
+
VALUE nm_list_copy_to_hash(const LIST* l, const dtype_t dtype, size_t recursions, VALUE default_value) {
|
|
447
|
+
|
|
448
|
+
// Create a hash with default values appropriately specified for a sparse matrix.
|
|
449
|
+
VALUE h = empty_list_to_hash(dtype, recursions, default_value);
|
|
450
|
+
|
|
451
|
+
if (l->first) {
|
|
452
|
+
NODE* curr = l->first;
|
|
453
|
+
|
|
454
|
+
while (curr) {
|
|
455
|
+
|
|
456
|
+
size_t key = curr->key;
|
|
457
|
+
|
|
458
|
+
if (recursions == 0) { // content is some kind of value
|
|
459
|
+
rb_hash_aset(h, INT2FIX(key), rubyobj_from_cval(curr->val, dtype).rval);
|
|
460
|
+
} else { // content is a list
|
|
461
|
+
rb_hash_aset(h, INT2FIX(key), nm_list_copy_to_hash(reinterpret_cast<const LIST*>(curr->val), dtype, recursions-1, default_value));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
curr = curr->next;
|
|
465
|
+
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return h;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
} // end of extern "C" block
|
|
475
|
+
|