nmatrix 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/History.txt +68 -2
- data/Manifest.txt +1 -0
- data/README.rdoc +8 -7
- data/Rakefile +13 -2
- data/ext/nmatrix/data/complex.h +19 -1
- data/ext/nmatrix/data/data.h +8 -0
- data/ext/nmatrix/data/ruby_object.h +1 -0
- data/ext/nmatrix/extconf.rb +6 -4
- data/ext/nmatrix/nmatrix.cpp +97 -35
- data/ext/nmatrix/nmatrix.h +2 -0
- data/ext/nmatrix/ruby_constants.cpp +11 -1
- data/ext/nmatrix/ruby_constants.h +6 -1
- data/ext/nmatrix/storage/dense.cpp +2 -2
- data/ext/nmatrix/storage/yale.cpp +303 -49
- data/ext/nmatrix/storage/yale.h +3 -0
- data/ext/nmatrix/util/math.cpp +112 -0
- data/ext/nmatrix/util/math.h +372 -72
- data/lib/nmatrix/blas.rb +55 -9
- data/lib/nmatrix/nmatrix.rb +315 -2
- data/lib/nmatrix/nvector.rb +156 -95
- data/lib/nmatrix/version.rb +1 -1
- data/lib/nmatrix/yale_functions.rb +112 -0
- data/spec/blas_spec.rb +11 -0
- data/spec/elementwise_spec.rb +4 -1
- data/spec/io_spec.rb +8 -0
- data/spec/lapack_spec.rb +37 -15
- data/spec/leakcheck.rb +16 -0
- data/spec/math_spec.rb +6 -2
- data/spec/nmatrix_spec.rb +209 -3
- data/spec/nmatrix_yale_spec.rb +55 -0
- data/spec/nvector_spec.rb +33 -14
- data/spec/slice_spec.rb +26 -17
- data/spec/spec_helper.rb +17 -0
- metadata +60 -45
- data/ext/nmatrix/new_extconf.rb +0 -55
data/ext/nmatrix/nmatrix.h
CHANGED
@@ -323,6 +323,8 @@ NM_DEF_STRUCT_POST(NMATRIX); // };
|
|
323
323
|
|
324
324
|
#define NM_CHECK_ALLOC(x) if (!x) rb_raise(rb_eNoMemError, "insufficient memory");
|
325
325
|
|
326
|
+
#define RB_FILE_EXISTS(fn) (rb_funcall(rb_const_get(rb_cObject, rb_intern("File")), rb_intern("exists?"), 1, (fn)) == Qtrue)
|
327
|
+
|
326
328
|
#define CheckNMatrixType(v) if (TYPE(v) != T_DATA || (RDATA(v)->dfree != (RUBY_DATA_FUNC)nm_delete && RDATA(v)->dfree != (RUBY_DATA_FUNC)nm_delete_ref)) rb_raise(rb_eTypeError, "expected NMatrix on left-hand side of operation");
|
327
329
|
|
328
330
|
#define NM_IsNMatrix(obj) \
|
@@ -55,6 +55,9 @@ ID nm_rb_real,
|
|
55
55
|
nm_rb_list,
|
56
56
|
nm_rb_yale,
|
57
57
|
|
58
|
+
nm_rb_row,
|
59
|
+
nm_rb_column,
|
60
|
+
|
58
61
|
nm_rb_add,
|
59
62
|
nm_rb_sub,
|
60
63
|
nm_rb_mul,
|
@@ -68,7 +71,9 @@ ID nm_rb_real,
|
|
68
71
|
nm_rb_eql,
|
69
72
|
nm_rb_neql,
|
70
73
|
nm_rb_gte,
|
71
|
-
nm_rb_lte
|
74
|
+
nm_rb_lte,
|
75
|
+
|
76
|
+
nm_rb_hash;
|
72
77
|
|
73
78
|
VALUE cNMatrix,
|
74
79
|
cNMatrix_IO,
|
@@ -122,4 +127,9 @@ void nm_init_ruby_constants(void) {
|
|
122
127
|
nm_rb_lower = rb_intern("lower");
|
123
128
|
nm_rb_unit = rb_intern("unit");
|
124
129
|
nm_rb_nonunit = rb_intern("nonunit");
|
130
|
+
|
131
|
+
nm_rb_hash = rb_intern("hash");
|
132
|
+
|
133
|
+
nm_rb_column = rb_intern("column");
|
134
|
+
nm_rb_row = rb_intern("row");
|
125
135
|
}
|
@@ -57,6 +57,9 @@ extern ID nm_rb_real,
|
|
57
57
|
nm_rb_dense,
|
58
58
|
nm_rb_list,
|
59
59
|
nm_rb_yale,
|
60
|
+
|
61
|
+
nm_rb_row,
|
62
|
+
nm_rb_column,
|
60
63
|
|
61
64
|
nm_rb_add,
|
62
65
|
nm_rb_sub,
|
@@ -71,7 +74,9 @@ extern ID nm_rb_real,
|
|
71
74
|
nm_rb_eql,
|
72
75
|
nm_rb_neql,
|
73
76
|
nm_rb_gte,
|
74
|
-
nm_rb_lte
|
77
|
+
nm_rb_lte,
|
78
|
+
|
79
|
+
nm_rb_hash;
|
75
80
|
|
76
81
|
extern VALUE cNMatrix,
|
77
82
|
cNMatrix_IO,
|
@@ -253,7 +253,7 @@ VALUE nm_dense_each_with_indices(VALUE nmatrix) {
|
|
253
253
|
|
254
254
|
nm_dense_storage_delete(sliced_dummy);
|
255
255
|
|
256
|
-
return
|
256
|
+
return nmatrix;
|
257
257
|
|
258
258
|
}
|
259
259
|
|
@@ -299,7 +299,7 @@ VALUE nm_dense_each(VALUE nmatrix) {
|
|
299
299
|
|
300
300
|
nm_dense_storage_delete(sliced_dummy);
|
301
301
|
|
302
|
-
return
|
302
|
+
return nmatrix;
|
303
303
|
|
304
304
|
}
|
305
305
|
|
@@ -68,6 +68,11 @@
|
|
68
68
|
#define NM_MIN(a,b) (((a)<(b))?(a):(b))
|
69
69
|
#endif
|
70
70
|
|
71
|
+
#ifndef NM_MAX_ITYPE
|
72
|
+
#define NM_MAX_ITYPE(a,b) ((static_cast<int8_t>(a) > static_cast<int8_t>(b)) ? static_cast<nm::itype_t>(a) : static_cast<nm::itype_t>(b))
|
73
|
+
#define NM_MIN_ITYPE(a,b) ((static_cast<int8_t>(a) < static_cast<int8_t>(b)) ? static_cast<nm::itype_t>(a) : static_cast<nm::itype_t>(b))
|
74
|
+
#endif
|
75
|
+
|
71
76
|
/*
|
72
77
|
* Forward Declarations
|
73
78
|
*/
|
@@ -78,12 +83,16 @@ extern "C" {
|
|
78
83
|
|
79
84
|
/* Ruby-accessible functions */
|
80
85
|
static VALUE nm_size(VALUE self);
|
81
|
-
static VALUE nm_a(VALUE self);
|
82
|
-
static VALUE nm_d(VALUE self);
|
86
|
+
static VALUE nm_a(int argc, VALUE* argv, VALUE self);
|
87
|
+
static VALUE nm_d(int argc, VALUE* argv, VALUE self);
|
83
88
|
static VALUE nm_lu(VALUE self);
|
84
89
|
static VALUE nm_ia(VALUE self);
|
85
90
|
static VALUE nm_ja(VALUE self);
|
86
|
-
static VALUE nm_ija(VALUE self);
|
91
|
+
static VALUE nm_ija(int argc, VALUE* argv, VALUE self);
|
92
|
+
|
93
|
+
static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self);
|
94
|
+
static VALUE nm_vector_insert(int argc, VALUE* argv, VALUE self);
|
95
|
+
|
87
96
|
|
88
97
|
} // end extern "C" block
|
89
98
|
|
@@ -104,11 +113,16 @@ static YALE_STORAGE* copy_alloc_struct(const YALE_STORAGE* rhs, const dtype_t ne
|
|
104
113
|
template <typename IType>
|
105
114
|
static void increment_ia_after(YALE_STORAGE* s, IType ija_size, IType i, IType n);
|
106
115
|
|
116
|
+
template <typename IType>
|
117
|
+
static void c_increment_ia_after(YALE_STORAGE* s, size_t ija_size, size_t i, size_t n) {
|
118
|
+
increment_ia_after<IType>(s, ija_size, i, n);
|
119
|
+
}
|
120
|
+
|
107
121
|
template <typename IType>
|
108
122
|
static IType insert_search(YALE_STORAGE* s, IType left, IType right, IType key, bool* found);
|
109
123
|
|
110
124
|
template <typename DType, typename IType>
|
111
|
-
static char vector_insert(YALE_STORAGE* s, size_t pos, size_t* j,
|
125
|
+
static char vector_insert(YALE_STORAGE* s, size_t pos, size_t* j, void* val_, size_t n, bool struct_only);
|
112
126
|
|
113
127
|
template <typename DType, typename IType>
|
114
128
|
static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t pos, size_t* j, size_t n, bool struct_only);
|
@@ -120,6 +134,27 @@ YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t
|
|
120
134
|
* Functions
|
121
135
|
*/
|
122
136
|
|
137
|
+
/*
|
138
|
+
* Copy a vector from one IType or DType to another.
|
139
|
+
*/
|
140
|
+
template <typename LType, typename RType>
|
141
|
+
static inline void copy_recast_vector(const void* in_, void* out_, size_t length) {
|
142
|
+
const RType* in = reinterpret_cast<const RType*>(in_);
|
143
|
+
LType* out = reinterpret_cast<LType*>(out_);
|
144
|
+
for (size_t i = 0; i < length; ++i) {
|
145
|
+
out[i] = in[i];
|
146
|
+
}
|
147
|
+
out;
|
148
|
+
}
|
149
|
+
|
150
|
+
|
151
|
+
static inline void copy_recast_itype_vector(const void* in, nm::itype_t in_itype, void* out, nm::itype_t out_itype, size_t length) {
|
152
|
+
NAMED_LR_ITYPE_TEMPLATE_TABLE(ttable, copy_recast_vector, void, const void* in_, void* out_, size_t length);
|
153
|
+
|
154
|
+
ttable[out_itype][in_itype](in, out, length);
|
155
|
+
}
|
156
|
+
|
157
|
+
|
123
158
|
/*
|
124
159
|
* Create Yale storage from IA, JA, and A vectors given in Old Yale format (probably from a file, since NMatrix only uses
|
125
160
|
* new Yale for its storage).
|
@@ -647,7 +682,7 @@ YALE_STORAGE* ew_op(const YALE_STORAGE* left, const YALE_STORAGE* right, dtype_t
|
|
647
682
|
|
648
683
|
YALE_STORAGE* dest;
|
649
684
|
|
650
|
-
new_shape = reinterpret_cast<size_t*>(
|
685
|
+
new_shape = reinterpret_cast<size_t*>(ALLOC_N(size_t, 2));
|
651
686
|
new_shape[0] = left->shape[0];
|
652
687
|
new_shape[1] = left->shape[1];
|
653
688
|
|
@@ -932,11 +967,11 @@ static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t po
|
|
932
967
|
|
933
968
|
// Copy all values subsequent to the insertion site to the new IJA and new A, leaving room (size n) for insertion.
|
934
969
|
if (struct_only) {
|
935
|
-
for (size_t i = pos; i < current_size
|
970
|
+
for (size_t i = pos; i < current_size; ++i) {
|
936
971
|
new_ija[i+n] = old_ija[i];
|
937
972
|
}
|
938
973
|
} else {
|
939
|
-
for (size_t i = pos; i < current_size
|
974
|
+
for (size_t i = pos; i < current_size; ++i) {
|
940
975
|
new_ija[i+n] = old_ija[i];
|
941
976
|
new_a[i+n] = old_a[i];
|
942
977
|
}
|
@@ -964,11 +999,13 @@ static char vector_insert_resize(YALE_STORAGE* s, size_t current_size, size_t po
|
|
964
999
|
* question.)
|
965
1000
|
*/
|
966
1001
|
template <typename DType, typename IType>
|
967
|
-
static char vector_insert(YALE_STORAGE* s, size_t pos, size_t* j,
|
1002
|
+
static char vector_insert(YALE_STORAGE* s, size_t pos, size_t* j, void* val_, size_t n, bool struct_only) {
|
968
1003
|
if (pos < s->shape[0]) {
|
969
|
-
rb_raise(rb_eArgError, "vector insert pos is before beginning of ja; this should not happen");
|
1004
|
+
rb_raise(rb_eArgError, "vector insert pos (%d) is before beginning of ja (%d); this should not happen", pos, s->shape[0]);
|
970
1005
|
}
|
971
1006
|
|
1007
|
+
DType* val = reinterpret_cast<DType*>(val_);
|
1008
|
+
|
972
1009
|
size_t size = get_size<IType>(s);
|
973
1010
|
|
974
1011
|
IType* ija = reinterpret_cast<IType*>(s->ija);
|
@@ -1098,6 +1135,7 @@ static inline size_t get_size(const YALE_STORAGE* storage) {
|
|
1098
1135
|
return static_cast<size_t>(reinterpret_cast<IType*>(storage->ija)[ storage->shape[0] ]);
|
1099
1136
|
}
|
1100
1137
|
|
1138
|
+
|
1101
1139
|
/*
|
1102
1140
|
* Allocate for a copy or copy-cast operation, and copy the IJA portion of the
|
1103
1141
|
* matrix (the structure).
|
@@ -1125,7 +1163,7 @@ static YALE_STORAGE* copy_alloc_struct(const YALE_STORAGE* rhs, const dtype_t ne
|
|
1125
1163
|
}
|
1126
1164
|
|
1127
1165
|
template <typename DType, typename IType>
|
1128
|
-
static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector) {
|
1166
|
+
static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector, nm::itype_t result_itype) {
|
1129
1167
|
YALE_STORAGE *left = (YALE_STORAGE*)(casted_storage.left),
|
1130
1168
|
*right = (YALE_STORAGE*)(casted_storage.right);
|
1131
1169
|
|
@@ -1133,24 +1171,49 @@ static STORAGE* matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resu
|
|
1133
1171
|
// same for left and right.
|
1134
1172
|
// int8_t dtype = left->dtype;
|
1135
1173
|
|
1174
|
+
// Massage the IType arrays into the correct form.
|
1175
|
+
|
1176
|
+
IType* ijl;
|
1177
|
+
if (left->itype == result_itype) ijl = reinterpret_cast<IType*>(left->ija);
|
1178
|
+
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
|
+
size_t length = nm_yale_storage_get_size(left);
|
1181
|
+
std::cerr << "length = " << length << std::endl;
|
1182
|
+
ijl = ALLOCA_N(IType, length);
|
1183
|
+
copy_recast_itype_vector(reinterpret_cast<void*>(left->ija), left->itype, reinterpret_cast<void*>(ijl), result_itype, length);
|
1184
|
+
}
|
1185
|
+
|
1186
|
+
IType* ijr;
|
1187
|
+
if (right->itype == result_itype) ijr = reinterpret_cast<IType*>(right->ija);
|
1188
|
+
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
|
+
size_t length = nm_yale_storage_get_size(right);
|
1191
|
+
std::cerr << "length = " << length << std::endl;
|
1192
|
+
ijr = ALLOCA_N(IType, length);
|
1193
|
+
copy_recast_itype_vector(reinterpret_cast<void*>(right->ija), right->itype, reinterpret_cast<void*>(ijr), result_itype, length);
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
// First, count the ndnz of the result.
|
1197
|
+
// TODO: This basically requires running symbmm twice to get the exact ndnz size. That's frustrating. Are there simple
|
1198
|
+
// cases where we can avoid running it?
|
1199
|
+
size_t result_ndnz = nm::math::symbmm<IType>(resulting_shape[0], left->shape[1], resulting_shape[1], ijl, ijl, true, ijr, ijr, true, NULL, true);
|
1200
|
+
|
1136
1201
|
// Create result storage.
|
1137
|
-
|
1138
|
-
YALE_STORAGE* result = nm_yale_storage_create(left->dtype, resulting_shape, 2, left->capacity + right->capacity, result_itype);
|
1202
|
+
YALE_STORAGE* result = nm_yale_storage_create(left->dtype, resulting_shape, 2, result_ndnz, result_itype);
|
1139
1203
|
init<DType,IType>(result);
|
1140
|
-
|
1141
|
-
IType* ijl = reinterpret_cast<IType*>(left->ija);
|
1142
|
-
IType* ijr = reinterpret_cast<IType*>(right->ija);
|
1143
1204
|
IType* ija = reinterpret_cast<IType*>(result->ija);
|
1144
1205
|
|
1145
1206
|
// Symbolic multiplication step (build the structure)
|
1146
|
-
nm::math::symbmm<IType>(
|
1207
|
+
nm::math::symbmm<IType>(resulting_shape[0], left->shape[1], resulting_shape[1], ijl, ijl, true, ijr, ijr, true, ija, true);
|
1147
1208
|
|
1148
1209
|
// Numeric multiplication step (fill in the elements)
|
1149
|
-
|
1210
|
+
|
1211
|
+
nm::math::numbmm<DType,IType>(result->shape[0], left->shape[1], result->shape[1],
|
1150
1212
|
ijl, ijl, reinterpret_cast<DType*>(left->a), true,
|
1151
1213
|
ijr, ijr, reinterpret_cast<DType*>(right->a), true,
|
1152
1214
|
ija, ija, reinterpret_cast<DType*>(result->a), true);
|
1153
1215
|
|
1216
|
+
|
1154
1217
|
// Sort the columns
|
1155
1218
|
nm::math::smmp_sort_columns<DType,IType>(result->shape[0], ija, ija, reinterpret_cast<DType*>(result->a));
|
1156
1219
|
|
@@ -1273,13 +1336,17 @@ void nm_init_yale_functions() {
|
|
1273
1336
|
*/
|
1274
1337
|
cNMatrix_YaleFunctions = rb_define_module_under(cNMatrix, "YaleFunctions");
|
1275
1338
|
|
1276
|
-
rb_define_method(cNMatrix_YaleFunctions, "yale_ija", (METHOD)nm_ija,
|
1277
|
-
rb_define_method(cNMatrix_YaleFunctions, "yale_a", (METHOD)nm_a,
|
1339
|
+
rb_define_method(cNMatrix_YaleFunctions, "yale_ija", (METHOD)nm_ija, -1);
|
1340
|
+
rb_define_method(cNMatrix_YaleFunctions, "yale_a", (METHOD)nm_a, -1);
|
1278
1341
|
rb_define_method(cNMatrix_YaleFunctions, "yale_size", (METHOD)nm_size, 0);
|
1279
1342
|
rb_define_method(cNMatrix_YaleFunctions, "yale_ia", (METHOD)nm_ia, 0);
|
1280
1343
|
rb_define_method(cNMatrix_YaleFunctions, "yale_ja", (METHOD)nm_ja, 0);
|
1281
|
-
rb_define_method(cNMatrix_YaleFunctions, "yale_d", (METHOD)nm_d,
|
1344
|
+
rb_define_method(cNMatrix_YaleFunctions, "yale_d", (METHOD)nm_d, -1);
|
1282
1345
|
rb_define_method(cNMatrix_YaleFunctions, "yale_lu", (METHOD)nm_lu, 0);
|
1346
|
+
|
1347
|
+
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
|
+
|
1283
1350
|
rb_define_const(cNMatrix_YaleFunctions, "YALE_GROWTH_CONSTANT", rb_float_new(nm::yale_storage::GROWTH_CONSTANT));
|
1284
1351
|
}
|
1285
1352
|
|
@@ -1325,6 +1392,25 @@ void* nm_yale_storage_get(STORAGE* storage, SLICE* slice) {
|
|
1325
1392
|
return ttable[casted_storage->dtype][casted_storage->itype](casted_storage, slice);
|
1326
1393
|
}
|
1327
1394
|
|
1395
|
+
/*
|
1396
|
+
* C accessor for yale_storage::vector_insert
|
1397
|
+
*/
|
1398
|
+
static char nm_yale_storage_vector_insert(YALE_STORAGE* s, size_t pos, size_t* js, void* vals, size_t n, bool struct_only, nm::dtype_t dtype, nm::itype_t itype) {
|
1399
|
+
NAMED_LI_DTYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::vector_insert, char, YALE_STORAGE*, size_t, size_t*, void*, size_t, bool);
|
1400
|
+
|
1401
|
+
return ttable[dtype][itype](s, pos, js, vals, n, struct_only);
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
/*
|
1405
|
+
* C accessor for yale_storage::increment_ia_after, typically called after ::vector_insert
|
1406
|
+
*/
|
1407
|
+
static void nm_yale_storage_increment_ia_after(YALE_STORAGE* s, size_t ija_size, size_t i, size_t n, nm::itype_t itype) {
|
1408
|
+
NAMED_ITYPE_TEMPLATE_TABLE(ttable, nm::yale_storage::c_increment_ia_after, void, YALE_STORAGE*, size_t, size_t, size_t);
|
1409
|
+
|
1410
|
+
ttable[itype](s, ija_size, i, n);
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
|
1328
1414
|
/*
|
1329
1415
|
* C accessor for yale_storage::ref, which returns a pointer to the correct location in a YALE_STORAGE object
|
1330
1416
|
* for some set of coordinates.
|
@@ -1403,14 +1489,21 @@ STORAGE* nm_yale_storage_copy_transposed(const STORAGE* rhs_base) {
|
|
1403
1489
|
/*
|
1404
1490
|
* C accessor for multiplying two YALE_STORAGE matrices, which have already been casted to the same dtype.
|
1405
1491
|
*
|
1406
|
-
* FIXME:
|
1492
|
+
* FIXME: There should be some mathematical way to determine the worst-case IType based on the input ITypes. Right now
|
1493
|
+
* it just uses the default.
|
1407
1494
|
*/
|
1408
1495
|
STORAGE* nm_yale_storage_matrix_multiply(const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector) {
|
1409
|
-
LI_DTYPE_TEMPLATE_TABLE(nm::yale_storage::matrix_multiply, STORAGE*, const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector);
|
1496
|
+
LI_DTYPE_TEMPLATE_TABLE(nm::yale_storage::matrix_multiply, STORAGE*, const STORAGE_PAIR& casted_storage, size_t* resulting_shape, bool vector, nm::itype_t resulting_itype);
|
1410
1497
|
|
1411
|
-
YALE_STORAGE*
|
1498
|
+
YALE_STORAGE* left = reinterpret_cast<YALE_STORAGE*>(casted_storage.left);
|
1499
|
+
YALE_STORAGE* right = reinterpret_cast<YALE_STORAGE*>(casted_storage.right);
|
1412
1500
|
|
1413
|
-
|
1501
|
+
// Determine the itype for the matrix that will be returned.
|
1502
|
+
nm::itype_t itype = nm_yale_storage_itype_by_shape(resulting_shape),
|
1503
|
+
max_itype = NM_MAX_ITYPE(left->itype, right->itype);
|
1504
|
+
if (static_cast<int8_t>(itype) < static_cast<int8_t>(max_itype)) itype = max_itype;
|
1505
|
+
|
1506
|
+
return ttable[left->dtype][itype](casted_storage, resulting_shape, vector, itype);
|
1414
1507
|
}
|
1415
1508
|
|
1416
1509
|
/*
|
@@ -1545,6 +1638,7 @@ void nm_yale_storage_init(YALE_STORAGE* s) {
|
|
1545
1638
|
ttable[s->dtype][s->itype](s);
|
1546
1639
|
}
|
1547
1640
|
|
1641
|
+
|
1548
1642
|
/*
|
1549
1643
|
* Ruby GC mark function for YALE_STORAGE. C accessible.
|
1550
1644
|
*/
|
@@ -1615,42 +1709,64 @@ static VALUE nm_size(VALUE self) {
|
|
1615
1709
|
/*
|
1616
1710
|
* call-seq:
|
1617
1711
|
* yale_a -> Array
|
1712
|
+
* yale_d(index) -> ...
|
1618
1713
|
*
|
1619
1714
|
* Get the A array of a Yale matrix (which stores the diagonal and the LU portions of the matrix).
|
1620
1715
|
*/
|
1621
|
-
static VALUE nm_a(VALUE self) {
|
1622
|
-
|
1716
|
+
static VALUE nm_a(int argc, VALUE* argv, VALUE self) {
|
1717
|
+
VALUE idx;
|
1718
|
+
rb_scan_args(argc, argv, "01", &idx);
|
1623
1719
|
|
1720
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1624
1721
|
size_t size = nm_yale_storage_get_size(s);
|
1625
|
-
VALUE* vals = ALLOCA_N(VALUE, size);
|
1626
1722
|
|
1627
|
-
|
1628
|
-
vals
|
1629
|
-
}
|
1630
|
-
VALUE ary = rb_ary_new4(size, vals);
|
1723
|
+
if (idx == Qnil) {
|
1724
|
+
VALUE* vals = ALLOCA_N(VALUE, size);
|
1631
1725
|
|
1632
|
-
|
1633
|
-
|
1726
|
+
for (size_t i = 0; i < size; ++i) {
|
1727
|
+
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*i, s->dtype).rval;
|
1728
|
+
}
|
1729
|
+
VALUE ary = rb_ary_new4(size, vals);
|
1634
1730
|
|
1635
|
-
|
1731
|
+
for (size_t i = size; i < s->capacity; ++i)
|
1732
|
+
rb_ary_push(ary, Qnil);
|
1733
|
+
|
1734
|
+
return ary;
|
1735
|
+
} else {
|
1736
|
+
size_t index = FIX2INT(idx);
|
1737
|
+
if (index >= size) rb_raise(rb_eRangeError, "out of range");
|
1738
|
+
|
1739
|
+
return rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype] * index, s->dtype).rval;
|
1740
|
+
}
|
1636
1741
|
}
|
1637
1742
|
|
1638
1743
|
|
1639
1744
|
/*
|
1640
1745
|
* call-seq:
|
1641
1746
|
* yale_d -> Array
|
1747
|
+
* yale_d(index) -> ...
|
1642
1748
|
*
|
1643
1749
|
* Get the diagonal ("D") portion of the A array of a Yale matrix.
|
1644
1750
|
*/
|
1645
|
-
static VALUE nm_d(VALUE self) {
|
1751
|
+
static VALUE nm_d(int argc, VALUE* argv, VALUE self) {
|
1752
|
+
VALUE idx;
|
1753
|
+
rb_scan_args(argc, argv, "01", &idx);
|
1754
|
+
|
1646
1755
|
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1647
1756
|
|
1648
|
-
|
1757
|
+
if (idx == Qnil) {
|
1758
|
+
VALUE* vals = ALLOCA_N(VALUE, s->shape[0]);
|
1759
|
+
|
1760
|
+
for (size_t i = 0; i < s->shape[0]; ++i) {
|
1761
|
+
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*i, s->dtype).rval;
|
1762
|
+
}
|
1763
|
+
return rb_ary_new4(s->shape[0], vals);
|
1764
|
+
} else {
|
1765
|
+
size_t index = FIX2INT(idx);
|
1766
|
+
if (index >= s->shape[0]) rb_raise(rb_eRangeError, "out of range");
|
1649
1767
|
|
1650
|
-
|
1651
|
-
vals[i] = rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*i, s->dtype).rval;
|
1768
|
+
return rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype] * index, s->dtype).rval;
|
1652
1769
|
}
|
1653
|
-
return rb_ary_new4(s->shape[0], vals);
|
1654
1770
|
}
|
1655
1771
|
|
1656
1772
|
/*
|
@@ -1726,26 +1842,164 @@ static VALUE nm_ja(VALUE self) {
|
|
1726
1842
|
/*
|
1727
1843
|
* call-seq:
|
1728
1844
|
* yale_ija -> Array
|
1845
|
+
* yale_ija(index) -> ...
|
1729
1846
|
*
|
1730
|
-
* Get the IJA array of a Yale matrix.
|
1847
|
+
* Get the IJA array of a Yale matrix (or a component of the IJA array).
|
1731
1848
|
*/
|
1732
|
-
static VALUE nm_ija(VALUE self) {
|
1733
|
-
|
1849
|
+
static VALUE nm_ija(int argc, VALUE* argv, VALUE self) {
|
1850
|
+
VALUE idx;
|
1851
|
+
rb_scan_args(argc, argv, "01", &idx);
|
1734
1852
|
|
1853
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1735
1854
|
size_t size = nm_yale_storage_get_size(s);
|
1736
1855
|
|
1737
|
-
|
1856
|
+
if (idx == Qnil) {
|
1738
1857
|
|
1739
|
-
|
1740
|
-
|
1858
|
+
VALUE* vals = ALLOCA_N(VALUE, size);
|
1859
|
+
|
1860
|
+
for (size_t i = 0; i < size; ++i) {
|
1861
|
+
vals[i] = rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[s->itype]*i, s->itype).rval;
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
VALUE ary = rb_ary_new4(size, vals);
|
1865
|
+
|
1866
|
+
for (size_t i = size; i < s->capacity; ++i)
|
1867
|
+
rb_ary_push(ary, Qnil);
|
1868
|
+
|
1869
|
+
return ary;
|
1870
|
+
|
1871
|
+
} else {
|
1872
|
+
size_t index = FIX2INT(idx);
|
1873
|
+
if (index >= size) rb_raise(rb_eRangeError, "out of range");
|
1874
|
+
|
1875
|
+
return rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[s->itype] * index, s->itype).rval;
|
1741
1876
|
}
|
1877
|
+
}
|
1742
1878
|
|
1743
|
-
VALUE ary = rb_ary_new4(size, vals);
|
1744
1879
|
|
1745
|
-
|
1746
|
-
|
1880
|
+
/*
|
1881
|
+
* call-seq:
|
1882
|
+
* yale_nd_row -> ...
|
1883
|
+
*
|
1884
|
+
* 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 :array, but defaults
|
1886
|
+
* to :hash. If :array is given, it will only return the Hash keys (the column indices).
|
1887
|
+
*
|
1888
|
+
* This function is meant to accomplish its purpose as efficiently as possible. It does not check for appropriate
|
1889
|
+
* range.
|
1890
|
+
*
|
1891
|
+
* FIXME: :array doesn't make sense. This should be :keys or :values to indicate which array we want.
|
1892
|
+
*/
|
1893
|
+
static VALUE nm_nd_row(int argc, VALUE* argv, VALUE self) {
|
1894
|
+
VALUE i_, as;
|
1895
|
+
rb_scan_args(argc, argv, "11", &i_, &as);
|
1747
1896
|
|
1748
|
-
|
1897
|
+
bool array = false;
|
1898
|
+
if (as != Qnil && rb_to_id(as) != nm_rb_hash) array = true;
|
1899
|
+
|
1900
|
+
size_t i = FIX2INT(i_);
|
1901
|
+
|
1902
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1903
|
+
nm::dtype_t dtype = NM_DTYPE(self);
|
1904
|
+
nm::itype_t itype = NM_ITYPE(self);
|
1905
|
+
|
1906
|
+
// get the position as a size_t
|
1907
|
+
// TODO: Come up with a faster way to get this than transforming to a Ruby object first.
|
1908
|
+
size_t pos = FIX2INT(rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[itype]*i, itype).rval);
|
1909
|
+
size_t nextpos = FIX2INT(rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[itype]*(i+1), itype).rval);
|
1910
|
+
size_t diff = nextpos - pos;
|
1911
|
+
|
1912
|
+
//std::cerr << "diff = " << diff << "\tpos = " << pos << "\tnextpos = " << nextpos << std::endl;
|
1913
|
+
|
1914
|
+
VALUE ret; // HERE
|
1915
|
+
if (array) {
|
1916
|
+
ret = rb_ary_new3(diff);
|
1917
|
+
|
1918
|
+
for (size_t idx = pos; idx < nextpos; ++idx) {
|
1919
|
+
rb_ary_store(ret, idx - pos, rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[s->itype]*idx, s->itype).rval);
|
1920
|
+
}
|
1921
|
+
|
1922
|
+
} else {
|
1923
|
+
ret = rb_hash_new();
|
1924
|
+
|
1925
|
+
for (size_t idx = pos; idx < nextpos; ++idx) {
|
1926
|
+
rb_hash_aset(ret, rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[s->itype]*idx, s->itype).rval,
|
1927
|
+
rubyobj_from_cval((char*)(s->a) + DTYPE_SIZES[s->dtype]*idx, s->dtype).rval);
|
1928
|
+
}
|
1929
|
+
}
|
1930
|
+
|
1931
|
+
return ret;
|
1932
|
+
}
|
1933
|
+
|
1934
|
+
/*
|
1935
|
+
* call-seq:
|
1936
|
+
* yale_vector_insert -> Fixnum
|
1937
|
+
*
|
1938
|
+
* Insert at position pos an array of non-diagonal elements with column indices given. Note that the column indices and values
|
1939
|
+
* must be storage-contiguous -- that is, you can't insert them around existing elements in some row, only amid some
|
1940
|
+
* elements in some row. You *can* insert them around a diagonal element, since this is stored separately. This function
|
1941
|
+
* may not be used for the insertion of diagonal elements in most cases, as these are already present in the data
|
1942
|
+
* structure and are typically modified by replacement rather than insertion.
|
1943
|
+
*
|
1944
|
+
* The last argument, pos, may be nil if you want to insert at the beginning of a row. Otherwise it needs to be provided.
|
1945
|
+
* Don't expect this function to know the difference. It really does very little checking, because its goal is to make
|
1946
|
+
* multiple contiguous insertion as quick as possible.
|
1947
|
+
*
|
1948
|
+
* You should also not attempt to insert values which are the default (0). These are not supposed to be stored, and may
|
1949
|
+
* lead to undefined behavior.
|
1950
|
+
*
|
1951
|
+
* Example:
|
1952
|
+
* m.yale_vector_insert(3, [0,3,4], [1,1,1], 15)
|
1953
|
+
*
|
1954
|
+
* 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
|
+
* corresponds to row 3).
|
1956
|
+
*
|
1957
|
+
* Example:
|
1958
|
+
* next = m.yale_vector_insert(3, [0,3,4], [1,1,1])
|
1959
|
+
*
|
1960
|
+
* This example determines that i=3 is at position 15 automatically. The value returned, next, is the position where the
|
1961
|
+
* next value(s) should be inserted.
|
1962
|
+
*/
|
1963
|
+
static VALUE nm_vector_insert(int argc, VALUE* argv, VALUE self) { //, VALUE i_, VALUE jv, VALUE vv, VALUE pos_) {
|
1964
|
+
|
1965
|
+
// i, jv, vv are mandatory; pos is optional; thus "31"
|
1966
|
+
VALUE i_, jv, vv, pos_;
|
1967
|
+
rb_scan_args(argc, argv, "31", &i_, &jv, &vv, &pos_);
|
1968
|
+
|
1969
|
+
size_t len = RARRAY_LEN(jv); // need length in order to read the arrays in
|
1970
|
+
size_t vvlen = RARRAY_LEN(vv);
|
1971
|
+
if (len != vvlen)
|
1972
|
+
rb_raise(rb_eArgError, "lengths must match between j array (%d) and value array (%d)", len, vvlen);
|
1973
|
+
|
1974
|
+
YALE_STORAGE* s = NM_STORAGE_YALE(self);
|
1975
|
+
nm::dtype_t dtype = NM_DTYPE(self);
|
1976
|
+
nm::itype_t itype = NM_ITYPE(self);
|
1977
|
+
|
1978
|
+
size_t i = FIX2INT(i_); // get the row
|
1979
|
+
|
1980
|
+
// get the position as a size_t
|
1981
|
+
// TODO: Come up with a faster way to get this than transforming to a Ruby object first.
|
1982
|
+
if (pos_ == Qnil) pos_ = rubyobj_from_cval_by_itype((char*)(s->ija) + ITYPE_SIZES[itype]*i, itype).rval;
|
1983
|
+
size_t pos = FIX2INT(pos_);
|
1984
|
+
|
1985
|
+
// Allocate the j array and the values array
|
1986
|
+
size_t* j = ALLOCA_N(size_t, len);
|
1987
|
+
void* vals = ALLOCA_N(char, DTYPE_SIZES[dtype] * len);
|
1988
|
+
|
1989
|
+
// Copy array contents
|
1990
|
+
for (size_t idx = 0; idx < len; ++idx) {
|
1991
|
+
j[idx] = FIX2INT(rb_ary_entry(jv, idx));
|
1992
|
+
rubyval_to_cval(rb_ary_entry(vv, idx), dtype, (char*)vals + idx * DTYPE_SIZES[dtype]);
|
1993
|
+
}
|
1994
|
+
|
1995
|
+
char ins_type = nm_yale_storage_vector_insert(s, pos, j, vals, len, false, dtype, itype);
|
1996
|
+
nm_yale_storage_increment_ia_after(s, s->shape[0], i, len, itype);
|
1997
|
+
s->ndnz += len;
|
1998
|
+
|
1999
|
+
// Return the updated position
|
2000
|
+
pos += len;
|
2001
|
+
return INT2FIX(pos);
|
1749
2002
|
}
|
1750
2003
|
|
2004
|
+
|
1751
2005
|
} // end of extern "C" block
|