kmat 0.0.3

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +3 -0
  3. data/.gitignore +15 -0
  4. data/CHANGELOG.md +15 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.md +675 -0
  7. data/README.md +224 -0
  8. data/Rakefile +26 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/ext/kmat/arith/binary.c +1121 -0
  12. data/ext/kmat/arith/logical.c +332 -0
  13. data/ext/kmat/arith/math.c +34 -0
  14. data/ext/kmat/arith/statistics.c +173 -0
  15. data/ext/kmat/arith/unary.c +165 -0
  16. data/ext/kmat/auto_collect.rb +118 -0
  17. data/ext/kmat/elementwise_function.rb +149 -0
  18. data/ext/kmat/extconf.rb +75 -0
  19. data/ext/kmat/id.txt +80 -0
  20. data/ext/kmat/id_sym.rb +40 -0
  21. data/ext/kmat/km_util.h +97 -0
  22. data/ext/kmat/kmat.h +96 -0
  23. data/ext/kmat/lapack_headers/blas.h +354 -0
  24. data/ext/kmat/lapack_headers/lapacke.h +19455 -0
  25. data/ext/kmat/lapack_headers/lapacke_config.h +119 -0
  26. data/ext/kmat/lapack_headers/lapacke_mangling.h +17 -0
  27. data/ext/kmat/lapack_headers/lapacke_utils.h +579 -0
  28. data/ext/kmat/linalg/dla.c +1629 -0
  29. data/ext/kmat/linalg/linalg.c +267 -0
  30. data/ext/kmat/linalg/norm.c +727 -0
  31. data/ext/kmat/linalg/vla.c +102 -0
  32. data/ext/kmat/linalg/working.c +240 -0
  33. data/ext/kmat/main.c +95 -0
  34. data/ext/kmat/smat/accessor.c +719 -0
  35. data/ext/kmat/smat/array.c +108 -0
  36. data/ext/kmat/smat/boxmuller.c +72 -0
  37. data/ext/kmat/smat/constructer.c +302 -0
  38. data/ext/kmat/smat/convert.c +375 -0
  39. data/ext/kmat/smat/elem.c +171 -0
  40. data/ext/kmat/smat/fund.c +702 -0
  41. data/ext/kmat/smat/share.c +427 -0
  42. data/ext/kmat/smat/smat.c +530 -0
  43. data/ext/kmat/smat/sort.c +1156 -0
  44. data/ext/kmat/sym.txt +34 -0
  45. data/kmat.gemspec +46 -0
  46. data/lib/kmat.rb +20 -0
  47. data/lib/kmat/accessor.rb +164 -0
  48. data/lib/kmat/arith.rb +189 -0
  49. data/lib/kmat/linalg.rb +279 -0
  50. data/lib/kmat/logical.rb +150 -0
  51. data/lib/kmat/misc.rb +122 -0
  52. data/lib/kmat/random.rb +106 -0
  53. data/lib/kmat/statistics.rb +98 -0
  54. data/lib/kmat/version.rb +3 -0
  55. metadata +156 -0
@@ -0,0 +1,702 @@
1
+ #include "../kmat.h"
2
+
3
+ // make a (m, n)-matrix with value type vt
4
+ VALUE
5
+ km_Mat(int m, int n, VTYPE vt)
6
+ {
7
+ VALUE ret = km_Mat_alloc(km_cMat);
8
+ SMAT *smat = km_mat2smat(ret);
9
+ km_smat_alloc_body(smat, m, n, vt);
10
+ return ret;
11
+ }
12
+
13
+ // Mat#initialize
14
+ // the arguments specifies the shape and the value type
15
+ // if the value type is ruby-object, it is filled by nil
16
+ // otherwise, the return is filled by 0
17
+ // if a block given, the (i, j)-th element is a return of yield(i, j)
18
+ #define DEFINE_INIT_LOOP_FUNC(id, type, func) static void \
19
+ km_initialize_loop_func_##id(type *elm, int i, int j, void *null) \
20
+ {\
21
+ *elm = func( rb_yield( rb_ary_new3(2, INT2NUM(i), INT2NUM(j)) ) ); \
22
+ }
23
+ DEFINE_INIT_LOOP_FUNC(d, double, NUM2DBL)
24
+ DEFINE_INIT_LOOP_FUNC(z, COMPLEX, km_v2c)
25
+ DEFINE_INIT_LOOP_FUNC(i, int, NUM2INT)
26
+ DEFINE_INIT_LOOP_FUNC(b, bool, RTEST)
27
+ DEFINE_INIT_LOOP_FUNC(v, VALUE, ITSELF)
28
+ struct km_initialize_loop_arg {
29
+ SMAT *smat;
30
+ VALUE *argv;
31
+ VTYPE vt;
32
+ };
33
+ static VALUE
34
+ km_initialize_loop(VALUE varg)
35
+ {
36
+ struct km_initialize_loop_arg *arg = (struct km_initialize_loop_arg *)varg;
37
+ km_smat_alloc_body(arg->smat, NUM2INT(arg->argv[0]), NUM2INT(arg->argv[1]), arg->vt);
38
+ if ( rb_block_given_p() ) {
39
+ VT_SWITCH( arg->vt,
40
+ km_smat_each_with_index_d(arg->smat, km_initialize_loop_func_d, NULL);,
41
+ km_smat_each_with_index_z(arg->smat, km_initialize_loop_func_z, NULL);,
42
+ km_smat_each_with_index_i(arg->smat, km_initialize_loop_func_i, NULL);,
43
+ km_smat_each_with_index_b(arg->smat, km_initialize_loop_func_b, NULL);,
44
+ km_smat_each_with_index_v(arg->smat, km_initialize_loop_func_v, NULL);
45
+ );
46
+ } else {
47
+ if ( arg->vt == VT_VALUE ) {
48
+ for ( int i=0; i<arg->smat->m; i++ ) {
49
+ for ( int j=0; j<arg->smat->n; j++ ) {
50
+ arg->smat->vbody[i+j*arg->smat->ld] = Qnil;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ return Qnil;
56
+ }
57
+ VALUE
58
+ kmm_mat_initialize(int argc, VALUE *argv, VALUE self)
59
+ {
60
+ rb_check_arity(argc, 2, 3);
61
+ SMAT *smat = km_mat2smat(self); VTYPE vt;
62
+ if ( smat->stype != ST_FULL ) {
63
+ rb_raise(km_eShare, "can't re-initialize submatrix. try detach before re-initializing");
64
+ } else if ( kmm_mat_have_submatrix_p(self) ) {
65
+ rb_raise(km_eShare, "can't re-initialize supermatrix. try detach before re-initializing");
66
+ }
67
+ if ( argc == 2 ) {
68
+ vt = VT_DOUBLE;
69
+ } else {
70
+ vt = km_sym2vt(argv[2]);
71
+ }
72
+ struct km_initialize_loop_arg arg;
73
+ arg.smat = smat; arg.argv = argv; arg.vt = vt;
74
+ km_gc_escape(km_initialize_loop, (VALUE)&arg);
75
+ return self;
76
+ }
77
+
78
+ // Mat#initialize_copy. this will used by Mat#dup or Mat#clone
79
+ // copy shape, value type and the elements from `obj'
80
+ // `self' will be a full-matrix even if `obj' is a submatrix
81
+ VALUE
82
+ kmm_mat_initialize_copy(VALUE self, VALUE obj)
83
+ {
84
+ rb_obj_init_copy(self, obj);
85
+ SMAT *ss = km_mat2smat(obj);
86
+ SMAT *sd = km_mat2smat(self);
87
+ if ( sd->stype != ST_FULL ) {
88
+ rb_raise(km_eShare, "can't re-initialize submatrix. try detach before re-initializing");
89
+ } else if ( kmm_mat_have_submatrix_p(self) ) {
90
+ rb_raise(km_eShare, "can't re-initialize supermatrix. try detach before re-initializing");
91
+ }
92
+ sd->vtype = VT_END;
93
+ ruby_xfree(sd->body);
94
+ km_smat_copy(sd, ss);
95
+ return self;
96
+ }
97
+
98
+ // reshpae to (`vm', `vn')-matrix `vm'*`vn' must be the same as `self'.row_size*'self'.col_size
99
+ VALUE
100
+ kmm_mat_reshape(VALUE self, VALUE vm, VALUE vn)
101
+ {
102
+ km_check_frozen(self);
103
+ SMAT *smat = km_mat2smat(self);
104
+ if ( smat->stype == ST_SSUB ) {
105
+ rb_raise(km_eShare, "can't reshape submatrix. try detach before reshaping");
106
+ }
107
+ int m = NUM2INT(vm), n = NUM2INT(vn);
108
+ km_check_positive(m, n);
109
+ if ( m*n == LENGTH(smat) ) {
110
+ smat->trans = false;
111
+ smat->m = m; smat->n = n;
112
+ smat->ld = m;
113
+ return self;
114
+ } else {
115
+ rb_raise(km_eDim, "the length of the matrix must no be changed, (%d, %d) -> (%d, %d) is unavailable",
116
+ smat->m, smat->n, m, n);
117
+ }
118
+ }
119
+
120
+ // change shape to (`vm', `vn')
121
+ // calloc() will by called if needed
122
+ VALUE
123
+ kmm_mat_resize(VALUE self, VALUE vm, VALUE vn)
124
+ {
125
+ km_check_frozen(self);
126
+ SMAT *smat = km_mat2smat(self);
127
+ if ( smat->stype != ST_FULL ) {
128
+ rb_raise(km_eShare, "can't resize submatrix. try detach before reshaping");
129
+ } else if ( kmm_mat_have_submatrix_p(self) ) {
130
+ rb_raise(km_eShare, "can't resize supermatrix. try detach before reshaping");
131
+ }
132
+ int m = NUM2INT(vm), n = NUM2INT(vn);
133
+ if ( m*n == LENGTH(smat) ) {
134
+ return kmm_mat_reshape(self, vm, vn);
135
+ } else {
136
+ VALUE argv[3] = {vm, vn, kmm_mat_vtype(self)};
137
+ return kmm_mat_initialize(3, argv, self);
138
+ }
139
+ }
140
+
141
+ // transpose `self'
142
+ // alias t
143
+ VALUE
144
+ kmm_mat_transpose_dest(VALUE self)
145
+ {
146
+ km_check_frozen(self);
147
+ SMAT *smat = km_mat2smat(self);
148
+ smat->trans = !(smat->trans);
149
+ SWAP(int, smat->m, smat->n);
150
+ return self;
151
+ }
152
+
153
+ // fill elements of `self' by `val'
154
+ #define DEFINE_FILL_FUNC(id, type) static void \
155
+ km_fill_func_##id(type *elm, void *data) \
156
+ {\
157
+ *elm = *(type *)data; \
158
+ }
159
+ DEFINE_FILL_FUNC(d, double)
160
+ DEFINE_FILL_FUNC(z, COMPLEX)
161
+ DEFINE_FILL_FUNC(i, int)
162
+ DEFINE_FILL_FUNC(b, bool)
163
+ DEFINE_FILL_FUNC(v, VALUE)
164
+ VALUE
165
+ kmm_mat_fill(VALUE self, VALUE val)
166
+ {
167
+ km_check_frozen(self);
168
+ SMAT *smat = km_mat2smat(self);
169
+ VT_SWITCH( smat->vtype,
170
+ double data=NUM2DBL(val); km_smat_each_d(smat, km_fill_func_d, (void *)&data);,
171
+ COMPLEX data=km_v2c(val); km_smat_each_z(smat, km_fill_func_z, (void *)&data);,
172
+ int data=NUM2INT(val); km_smat_each_i(smat, km_fill_func_i, (void *)&data);,
173
+ bool data=RTEST(val); km_smat_each_b(smat, km_fill_func_b, (void *)&data);,
174
+ VALUE data=val; km_smat_each_v(smat, km_fill_func_v, (void *)&data);
175
+ );
176
+ return self;
177
+ }
178
+
179
+ // fill elements of `self' by 0
180
+ // if `self' is a boolean matrix, the filler is false
181
+ // if `self' is a ruby-object matrix, the filler is 0, an instance of Integer
182
+ VALUE
183
+ kmm_mat_zero(VALUE self)
184
+ {
185
+ km_check_frozen(self);
186
+ SMAT *smat = km_mat2smat(self);
187
+ VT_SWITCH( smat->vtype,
188
+ double data=0.0; km_smat_each_d(smat, km_fill_func_d, (void *)&data);,
189
+ COMPLEX data=cpack(0.0, 0.0); km_smat_each_z(smat, km_fill_func_z, (void *)&data);,
190
+ int data=0; km_smat_each_i(smat, km_fill_func_i, (void *)&data);,
191
+ bool data=false; km_smat_each_b(smat, km_fill_func_b, (void *)&data);,
192
+ VALUE data=INT2NUM(0); km_smat_each_v(smat, km_fill_func_v, (void *)&data);
193
+ );
194
+ return self;
195
+ }
196
+
197
+ // fill elements of `self' by eye()
198
+ #define DEFINE_EYE_FUNC(id, type) struct km_eye_##id { \
199
+ type zero; \
200
+ type one; \
201
+ }; \
202
+ static void \
203
+ km_eye_func_##id(type *elm, int i, int j, void *data_) \
204
+ {\
205
+ struct km_eye_##id *data = (struct km_eye_##id *)data_; \
206
+ if ( i == j ) { \
207
+ *elm = data->one; \
208
+ } else { \
209
+ *elm = data->zero; \
210
+ } \
211
+ }
212
+ DEFINE_EYE_FUNC(d, double)
213
+ DEFINE_EYE_FUNC(z, COMPLEX)
214
+ DEFINE_EYE_FUNC(i, int)
215
+ DEFINE_EYE_FUNC(b, bool)
216
+ DEFINE_EYE_FUNC(v, VALUE)
217
+ VALUE
218
+ kmm_mat_eye(VALUE self)
219
+ {
220
+ km_check_frozen(self);
221
+ SMAT *smat = km_mat2smat(self);
222
+ if ( smat->vtype == VT_DOUBLE ) {
223
+ struct km_eye_d data = {0.0, 1.0};
224
+ km_smat_each_with_index_d(smat, km_eye_func_d, (void *)&data);
225
+ } else if ( smat->vtype == VT_COMPLEX ) {
226
+ struct km_eye_z data = {cpack(0.0, 0.0), cpack(1.0, 0.0)};
227
+ km_smat_each_with_index_z(smat, km_eye_func_z, (void *)&data);
228
+ } else if ( smat->vtype == VT_INT ) {
229
+ struct km_eye_i data = {0, 1};
230
+ km_smat_each_with_index_i(smat, km_eye_func_i, (void *)&data);
231
+ } else if ( smat->vtype == VT_BOOL ) {
232
+ struct km_eye_b data = {false, true};
233
+ km_smat_each_with_index_b(smat, km_eye_func_b, (void *)&data);
234
+ } else if ( smat->vtype == VT_VALUE ) {
235
+ struct km_eye_v data = {INT2NUM(0), INT2NUM(1)};
236
+ km_smat_each_with_index_v(smat, km_eye_func_v, (void *)&data);
237
+ } else {
238
+ rb_raise(km_eInternal, "unknown value type");
239
+ }
240
+ return self;
241
+ }
242
+
243
+ // fill the elements of `self' by kmat_vt_rand()
244
+ // float, object: U(0, 1), U(0...max), U(range)
245
+ // int: U({0, 1}), U({0...max}), U({range}), "1 with probability arg and 0 with probability 1-arg"
246
+ // bool: U({false, true}), "true with probability arg and false with probability 1-arg"
247
+ struct km_rand_arg {
248
+ VALUE random;
249
+ VALUE arg;
250
+ };
251
+ #define DEFINE_RAND_FUNC(id, type, cast_func) static void \
252
+ km_rand_func_##id(type *elm, void *data_) \
253
+ {\
254
+ struct km_rand_arg *data = (struct km_rand_arg *)data_; \
255
+ *elm = cast_func(rb_funcall(data->random, id__kmat_rand_##id, 1, data->arg)); \
256
+ }
257
+ DEFINE_RAND_FUNC(d, double, NUM2DBL)
258
+ DEFINE_RAND_FUNC(z, COMPLEX, km_v2c)
259
+ DEFINE_RAND_FUNC(i, int, NUM2INT)
260
+ DEFINE_RAND_FUNC(b, bool, RTEST)
261
+ DEFINE_RAND_FUNC(v, VALUE, ITSELF)
262
+ VALUE
263
+ kmm_mat__rand0(VALUE self, VALUE random, VALUE arg)
264
+ {
265
+ km_check_frozen(self);
266
+ SMAT *smat = km_mat2smat(self);
267
+ struct km_rand_arg data = {random, arg};
268
+ VT_SWITCH( smat->vtype,
269
+ km_smat_each_d(smat, km_rand_func_d, (void *)&data);,
270
+ km_smat_each_z(smat, km_rand_func_z, (void *)&data);,
271
+ km_smat_each_i(smat, km_rand_func_i, (void *)&data);,
272
+ km_smat_each_b(smat, km_rand_func_b, (void *)&data);,
273
+ km_smat_each_v(smat, km_rand_func_v, (void *)&data);
274
+ );
275
+ return self;
276
+ }
277
+
278
+ // fill the elments of `self' by random values with follows N(0, 1)
279
+ static void
280
+ km_randn_func(double *elm, void *data)
281
+ {
282
+ *elm = km_rand_normal(*(VALUE *)data);
283
+ }
284
+ VALUE
285
+ kmm_mat__randn0(VALUE self, VALUE random)
286
+ {
287
+ km_check_frozen(self);
288
+ SMAT *smat = km_mat2smat(self);
289
+ if ( smat->vtype != VT_DOUBLE ) {
290
+ rb_raise(km_eVT, "Mat#randn is available for float matricies, change value-type before call this");
291
+ }
292
+ if ( smat->stype == ST_FULL ) {
293
+ km_fill_normal(LENGTH(smat), smat->dbody, random);
294
+ } else if ( smat->stype == ST_SSUB ) {
295
+ if ( smat->trans ) {
296
+ for ( int i=0; i<smat->m; i++ ) {
297
+ km_fill_normal(smat->n, smat->dbody+i*smat->ld, random);
298
+ }
299
+ } else {
300
+ for ( int i=0; i<smat->n; i++ ) {
301
+ km_fill_normal(smat->m, smat->dbody+i*smat->ld, random);
302
+ }
303
+ }
304
+ } else if ( smat->stype == ST_RSUB ) {
305
+ VALUE data = random;
306
+ km_smat_each_d(smat, km_randn_func, (void *)&data);
307
+ } else {
308
+ rb_raise(km_eInternal, "unknown storage type");
309
+ }
310
+ return self;
311
+ }
312
+
313
+ // invoke yield(element) for all the elements
314
+ #define DEFINE_EACH_FUNC(id, type, func) static void \
315
+ km_each_func_##id(type *elm, void *null) \
316
+ { \
317
+ rb_yield(func(*elm)); \
318
+ }
319
+ DEFINE_EACH_FUNC(d, double, rb_float_new)
320
+ DEFINE_EACH_FUNC(z, COMPLEX, km_c2v)
321
+ DEFINE_EACH_FUNC(i, int, INT2NUM)
322
+ DEFINE_EACH_FUNC(b, bool, TF2V)
323
+ DEFINE_EACH_FUNC(v, VALUE, ITSELF)
324
+ VALUE
325
+ kmm_mat_each(VALUE self)
326
+ {
327
+ if ( rb_block_given_p() ) {
328
+ SMAT *smat = km_mat2smat(self);
329
+ VT_SWITCH( smat->vtype,
330
+ km_smat_each_d(smat, km_each_func_d, NULL);,
331
+ km_smat_each_z(smat, km_each_func_z, NULL);,
332
+ km_smat_each_i(smat, km_each_func_i, NULL);,
333
+ km_smat_each_b(smat, km_each_func_b, NULL);,
334
+ km_smat_each_v(smat, km_each_func_v, NULL);
335
+ );
336
+ return self;
337
+ } else {
338
+ return rb_enumeratorize(self, sym_each, 0, NULL);
339
+ }
340
+ }
341
+
342
+ // invoke yield(element, i, j) for all the elements
343
+ #define DEFINE_EACH_WI2_FUNC(id, type, func) static void \
344
+ km_each_with_index2_func_##id(type *elm, int i, int j, void *null) \
345
+ { \
346
+ rb_yield(rb_ary_new3(3, func(*elm), INT2NUM(i), INT2NUM(j))); \
347
+ }
348
+ DEFINE_EACH_WI2_FUNC(d, double, rb_float_new)
349
+ DEFINE_EACH_WI2_FUNC(z, COMPLEX, km_c2v)
350
+ DEFINE_EACH_WI2_FUNC(i, int, INT2NUM)
351
+ DEFINE_EACH_WI2_FUNC(b, bool, TF2V)
352
+ DEFINE_EACH_WI2_FUNC(v, VALUE, ITSELF)
353
+ // alias each_with_index
354
+ VALUE
355
+ kmm_mat_each_with_index2(VALUE self)
356
+ {
357
+ if ( rb_block_given_p() ) {
358
+ SMAT *smat = km_mat2smat(self);
359
+ VT_SWITCH( smat->vtype,
360
+ km_smat_each_with_index_d(smat, km_each_with_index2_func_d, NULL);,
361
+ km_smat_each_with_index_z(smat, km_each_with_index2_func_z, NULL);,
362
+ km_smat_each_with_index_i(smat, km_each_with_index2_func_i, NULL);,
363
+ km_smat_each_with_index_b(smat, km_each_with_index2_func_b, NULL);,
364
+ km_smat_each_with_index_v(smat, km_each_with_index2_func_v, NULL);
365
+ );
366
+ return self;
367
+ } else {
368
+ return rb_enumeratorize(self, sym_each_with_index2, 0, NULL);
369
+ }
370
+ }
371
+
372
+ // invoke yield(element) and replace the element by the return for all the elements
373
+ #define DEFINE_MMAP_FUNC(id, type, func, func2) static void \
374
+ km_mmap_func_##id(type *elm, void *null) \
375
+ { \
376
+ *elm = func2(rb_yield(func(*elm))); \
377
+ }
378
+ DEFINE_MMAP_FUNC(d, double, rb_float_new, NUM2DBL)
379
+ DEFINE_MMAP_FUNC(z, COMPLEX, km_c2v, km_v2c)
380
+ DEFINE_MMAP_FUNC(i, int, INT2NUM, NUM2INT)
381
+ DEFINE_MMAP_FUNC(b, bool, TF2V, RTEST)
382
+ DEFINE_MMAP_FUNC(v, VALUE, ITSELF, ITSELF)
383
+ // alias map
384
+ VALUE
385
+ kmm_mat_mmap_dest(VALUE self)
386
+ {
387
+ if ( rb_block_given_p() ) {
388
+ SMAT *smat = km_mat2smat(self);
389
+ VT_SWITCH( smat->vtype,
390
+ km_smat_each_d(smat, km_mmap_func_d, NULL);,
391
+ km_smat_each_z(smat, km_mmap_func_z, NULL);,
392
+ km_smat_each_i(smat, km_mmap_func_i, NULL);,
393
+ km_smat_each_b(smat, km_mmap_func_b, NULL);,
394
+ km_smat_each_v(smat, km_mmap_func_v, NULL);
395
+ );
396
+ return self;
397
+ } else {
398
+ return rb_enumeratorize(self, sym_mmap, 0, NULL);
399
+ }
400
+ }
401
+
402
+ // invoke yield(element, i, j) and replace the element by the return for all the elements
403
+ #define DEFINE_MMAP_WI2_FUNC(id, type, func, func2) static void \
404
+ km_mmap_with_index2_func_##id(type *elm, int i, int j, void *null) \
405
+ { \
406
+ *elm = func2(rb_yield(rb_ary_new3(3, func(*elm), INT2NUM(i), INT2NUM(j)))); \
407
+ }
408
+ DEFINE_MMAP_WI2_FUNC(d, double, rb_float_new, NUM2DBL)
409
+ DEFINE_MMAP_WI2_FUNC(z, COMPLEX, km_c2v, km_v2c)
410
+ DEFINE_MMAP_WI2_FUNC(i, int, INT2NUM, NUM2INT)
411
+ DEFINE_MMAP_WI2_FUNC(b, bool, TF2V, RTEST)
412
+ DEFINE_MMAP_WI2_FUNC(v, VALUE, ITSELF, ITSELF)
413
+ // alias map_with_index
414
+ VALUE
415
+ kmm_mat_mmap_with_index2_dest(VALUE self)
416
+ {
417
+ if ( rb_block_given_p() ) {
418
+ SMAT *smat = km_mat2smat(self);
419
+ VT_SWITCH( smat->vtype,
420
+ km_smat_each_with_index_d(smat, km_mmap_with_index2_func_d, NULL);,
421
+ km_smat_each_with_index_z(smat, km_mmap_with_index2_func_z, NULL);,
422
+ km_smat_each_with_index_i(smat, km_mmap_with_index2_func_i, NULL);,
423
+ km_smat_each_with_index_b(smat, km_mmap_with_index2_func_b, NULL);,
424
+ km_smat_each_with_index_v(smat, km_mmap_with_index2_func_v, NULL);
425
+ );
426
+ return Qnil;
427
+ } else {
428
+ return rb_enumeratorize(self, sym_mmap_with_index2, 0, NULL);
429
+ }
430
+ }
431
+
432
+ // make a row-major Array of Arrays (Mat#to_a is Enumerable#to_a and it is not the same as this)
433
+ #define TA_LOOP(id, func) for ( int i=0; i<smat->m; i++ ) { \
434
+ VALUE row = rb_ary_new2(smat->n); \
435
+ for ( int j=0; j<smat->n; j++ ) { \
436
+ rb_ary_push(row, func(smat->id##body[INDEX(smat, i, j)])); \
437
+ } \
438
+ rb_ary_push(ret, row); \
439
+ }
440
+ VALUE
441
+ kmm_mat_to_ary(VALUE self)
442
+ {
443
+ SMAT *smat = km_mat2smat(self);
444
+ VALUE ret = rb_ary_new2(smat->m);
445
+ VT_SWITCH( smat->vtype,
446
+ TA_LOOP(d, rb_float_new),
447
+ TA_LOOP(z, km_c2v),
448
+ TA_LOOP(i, INT2NUM),
449
+ TA_LOOP(b, TF2V),
450
+ TA_LOOP(v, ITSELF)
451
+ );
452
+ return ret;
453
+ }
454
+
455
+ // make a String
456
+ #define TS_LOOP(tid, func) for ( int i=0; i<smat->m; i++ ) { \
457
+ VALUE row = rb_ary_new2(smat->n); \
458
+ for ( int j=0; j<smat->n; j++ ) { \
459
+ rb_ary_push(row, rb_funcall(func(ENTITY(smat, tid, i, j)), id, 0)); \
460
+ } \
461
+ rb_str_cat2(ret, " ["); \
462
+ rb_str_concat(ret, rb_funcall(row, id_join, 1, sep)); \
463
+ rb_str_cat2(ret, "],\n"); \
464
+ }
465
+ static VALUE
466
+ km_smat_to_s(const SMAT *smat, ID id, VALUE vtsym, VALUE stsym)
467
+ {
468
+ VALUE ret = rb_utf8_str_new_cstr("Mat[\n");
469
+ VALUE sep = rb_utf8_str_new_cstr(", ");
470
+ VT_SWITCH( smat->vtype,
471
+ TS_LOOP(d, rb_float_new),
472
+ TS_LOOP(z, km_c2v),
473
+ TS_LOOP(i, INT2NUM),
474
+ TS_LOOP(b, TF2V),
475
+ TS_LOOP(v, ITSELF)
476
+ );
477
+ rb_str_cat2(ret, "] (");
478
+ rb_str_concat(ret, rb_funcall(vtsym, id_inspect, 0));
479
+ rb_str_cat2(ret, ", ");
480
+ rb_str_concat(ret, rb_funcall(stsym, id_inspect, 0));
481
+ rb_str_cat2(ret, ")");
482
+ return ret;
483
+ }
484
+ #define TSP_LOOP(tid, func) for ( int i=0; i<smat->m; i++ ) { \
485
+ VALUE row = rb_ary_new2(smat->n); \
486
+ for ( int j=0; j<smat->n; j++ ) { \
487
+ rb_ary_push(row, rb_funcall(format, id_op_percent, 1, func(ENTITY(smat, tid, i, j)))); \
488
+ } \
489
+ rb_str_cat2(ret, " ["); \
490
+ rb_str_concat(ret, rb_funcall(row, id_join, 1, sep)); \
491
+ rb_str_cat2(ret, "],\n"); \
492
+ }
493
+ static VALUE
494
+ km_smat_to_s_percent(const SMAT *smat, VALUE vtsym, VALUE stsym, VALUE format)
495
+ {
496
+ VALUE ret = rb_utf8_str_new_cstr("Mat[\n");
497
+ VALUE sep = rb_utf8_str_new_cstr(", ");
498
+ VT_SWITCH( smat->vtype,
499
+ TSP_LOOP(d, rb_float_new),
500
+ TSP_LOOP(z, km_c2v),
501
+ TSP_LOOP(i, INT2NUM),
502
+ TSP_LOOP(b, TF2V),
503
+ TSP_LOOP(v, ITSELF)
504
+ );
505
+ rb_str_cat2(ret, "] (");
506
+ rb_str_concat(ret, rb_funcall(vtsym, id_inspect, 0));
507
+ rb_str_cat2(ret, ", ");
508
+ rb_str_concat(ret, rb_funcall(stsym, id_inspect, 0));
509
+ rb_str_cat2(ret, ")");
510
+ return ret;
511
+ }
512
+ // alias to_str
513
+ VALUE
514
+ kmm_mat_to_s(int argc, VALUE *argv, VALUE self)
515
+ {
516
+ rb_check_arity(argc, 0, 1);
517
+ if ( argc == 0 ) {
518
+ return km_smat_to_s(km_mat2smat(self), id_to_s, kmm_mat_vtype(self), kmm_mat_stype(self));
519
+ } else {
520
+ return km_smat_to_s_percent(km_mat2smat(self), kmm_mat_vtype(self), kmm_mat_stype(self), argv[0]);
521
+ }
522
+ }
523
+ VALUE
524
+ kmm_mat_inspect(VALUE self)
525
+ {
526
+ return km_smat_to_s(km_mat2smat(self), id_inspect, kmm_mat_vtype(self), kmm_mat_stype(self));
527
+ }
528
+
529
+ // symmetrize `self' by (A+A')/2 where A is `self' on entry
530
+ VALUE
531
+ kmm_mat_symmetrize_dest(VALUE self)
532
+ {
533
+ km_check_frozen(self);
534
+ SMAT *smat = km_mat2smat(self);
535
+ if ( smat->m != smat->n ) {
536
+ rb_raise(km_eDim, "non-square matrix cannot be symmetrized");
537
+ }
538
+ if ( smat->vtype == VT_DOUBLE ) {
539
+ for ( int i=0; i<smat->m-1; i++ ) {
540
+ for ( int j=i+1; j<smat->m; j++ ) {
541
+ smat->dbody[i+j*smat->ld] = ( smat->dbody[i+j*smat->ld] + smat->dbody[j+i*smat->ld] ) * 0.5;
542
+ smat->dbody[j+i*smat->ld] = smat->dbody[i+j*smat->ld];
543
+ }
544
+ }
545
+ } else if ( smat->vtype == VT_COMPLEX ) {
546
+ for ( int i=0; i<smat->m-1; i++ ) {
547
+ for ( int j=i+1; j<smat->m; j++ ) {
548
+ smat->zbody[i+j*smat->ld] = ( smat->zbody[i+j*smat->ld] + smat->zbody[j+i*smat->ld] ) * 0.5;
549
+ smat->zbody[j+i*smat->ld] = smat->zbody[i+j*smat->ld];
550
+ }
551
+ }
552
+ } else {
553
+ rb_raise(km_eVT, "symmetrize is available only for float or complex matricies");
554
+ }
555
+ return self;
556
+ }
557
+
558
+ // judge whether `self' is symmetric or not
559
+ // if the argument is true `self' will be completely symmetric by Mat#symmetrize!
560
+ // float, complex: consider that a is sufficiently near to b iff |a-b|/(|a|+|b|) < eps*8
561
+ // int, bool: a is equal to b iff a == b
562
+ // object: consider that a is sufficiently near to b iff a.respond_to?(:near?) ? a.near?(b) : a==b
563
+ static bool
564
+ km_near_rel_d(double a, double b)
565
+ {
566
+ if ( a == b ) {
567
+ return true;
568
+ } else {
569
+ return ( fabs(a-b)/(fabs(a)+fabs(b)) < DBL_EPSILON*8.0 );
570
+ }
571
+ }
572
+ static bool
573
+ km_near_rel_z(COMPLEX a, COMPLEX b)
574
+ {
575
+ if ( a == b ) {
576
+ return true;
577
+ } else {
578
+ return ( cabs(a-b)/(cabs(a)+cabs(b)) < DBL_EPSILON*8.0 );
579
+ }
580
+ }
581
+ static bool
582
+ km_near_v(VALUE a, VALUE b)
583
+ {
584
+ if ( rb_respond_to(a, id_near_p) ) {
585
+ return RTEST(rb_funcall(a, id_near_p, 1, b));
586
+ } else {
587
+ return RTEST(rb_funcall(a, id_op_eq, 1, b));
588
+ }
589
+ }
590
+ #define SYM_BODY(id, func) for ( int i=0; i<(smat->n)-1; i++ ) { \
591
+ for ( int j=i+1; j<(smat->n); j++ ) { \
592
+ if ( !func(smat->id##body[i+j*(smat->ld)], smat->id##body[j+i*(smat->ld)]) ) { \
593
+ return Qfalse; \
594
+ } \
595
+ } \
596
+ }
597
+ VALUE
598
+ kmm_mat_symmetry_p(int argc, VALUE *argv, VALUE self)
599
+ {
600
+ rb_check_arity(argc, 0, 1);
601
+ bool symmetrize;
602
+ if ( argc == 0 ) {
603
+ symmetrize = false;
604
+ } else {
605
+ symmetrize = RTEST(argv[0]);
606
+ }
607
+ SMAT *smat = km_mat2smat(self);
608
+ if ( smat->m != smat->n ) {
609
+ return Qfalse;
610
+ }
611
+ VT_SWITCH( smat->vtype,
612
+ SYM_BODY(d, km_near_rel_d)
613
+ if ( symmetrize ) { kmm_mat_symmetrize_dest(self); },
614
+ SYM_BODY(z, km_near_rel_z)
615
+ if ( symmetrize ) { kmm_mat_symmetrize_dest(self); },
616
+ SYM_BODY(i, SAME),
617
+ SYM_BODY(b, SAME),
618
+ SYM_BODY(v, km_near_v)
619
+ );
620
+ return Qtrue;
621
+ }
622
+
623
+ // judge whether `self' is near to `other'
624
+ // consider a is near to b iff |a-b| < tol
625
+ // the default value of tol is (maximub absolute value of each element) * max(m, n) * eps
626
+ static bool
627
+ km_near_abs_d(double a, double b, double tol)
628
+ {
629
+ if ( a == b ) {
630
+ return true;
631
+ } else {
632
+ return ( fabs(a-b) < tol );
633
+ }
634
+ }
635
+ static bool
636
+ km_near_abs_z(COMPLEX a, COMPLEX b, double tol)
637
+ {
638
+ if ( a == b ) {
639
+ return true;
640
+ } else {
641
+ return ( cabs(a-b) < tol );
642
+ }
643
+ }
644
+ struct km_near_arg {
645
+ bool ret;
646
+ double tol;
647
+ };
648
+ static void
649
+ km_near_func_d(double *a, double *b, void *data)
650
+ {
651
+ struct km_near_arg *arg = (struct km_near_arg *)data;
652
+ arg->ret = (arg->ret && km_near_abs_d(*a, *b, arg->tol));
653
+ }
654
+ static void
655
+ km_near_func_z(COMPLEX *a, COMPLEX *b, void *data)
656
+ {
657
+ struct km_near_arg *arg = (struct km_near_arg *)data;
658
+ arg->ret = (arg->ret && km_near_abs_z(*a, *b, arg->tol));
659
+ }
660
+ static void
661
+ km_near_func_i(int *a, int *b, void *data)
662
+ {
663
+ struct km_near_arg *arg = (struct km_near_arg *)data;
664
+ arg->ret = (arg->ret && *a==*b);
665
+ }
666
+ static void
667
+ km_near_func_b(bool *a, bool *b, void *data)
668
+ {
669
+ struct km_near_arg *arg = (struct km_near_arg *)data;
670
+ arg->ret = (arg->ret && *a==*b);
671
+ }
672
+ static void
673
+ km_near_func_v(VALUE *a, VALUE *b, void *data)
674
+ {
675
+ struct km_near_arg *arg = (struct km_near_arg *)data;
676
+ arg->ret = (arg->ret && km_near_v(*a, *b));
677
+ }
678
+ VALUE
679
+ kmm_mat_near_p(int argc, VALUE *argv, VALUE self)
680
+ {
681
+ rb_check_arity(argc, 1, 2);
682
+ SMAT *ss = km_mat2smat(self);
683
+ SMAT *so = km_mat2smat(argv[0]);
684
+ if ( ss->vtype != so->vtype || ss->m != so->m || ss->n != so->n ) {
685
+ return Qfalse;
686
+ }
687
+ struct km_near_arg data = {true, 0.0};
688
+ if ( argc == 1 ) {
689
+ double ns = NUM2DBL(kmm_mat_norm_einf(self)), no = NUM2DBL(kmm_mat_norm_einf(argv[0]));
690
+ data.tol = MAX(ns, no) * MAX(ss->m, ss->n) * DBL_EPSILON;
691
+ } else {
692
+ data.tol = NUM2DBL(argv[1]);
693
+ }
694
+ VT_SWITCH( ss->vtype,
695
+ km_smat_each2_d(ss, so, km_near_func_d, (void *)&data);,
696
+ km_smat_each2_z(ss, so, km_near_func_z, (void *)&data);,
697
+ km_smat_each2_i(ss, so, km_near_func_i, (void *)&data);,
698
+ km_smat_each2_b(ss, so, km_near_func_b, (void *)&data);,
699
+ km_smat_each2_v(ss, so, km_near_func_v, (void *)&data);
700
+ );
701
+ return data.ret;
702
+ }