nmatrix 0.0.4 → 0.0.5
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 +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
|