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,427 @@
1
+ #include "../kmat.h"
2
+
3
+ // freeze `self' and all submatricies of `self'
4
+ // `self' must be a full-matrix (can't deep_freeze submatrix)
5
+ static void
6
+ km_mat_deep_freeze_func(VALUE *ent, void *null)
7
+ {
8
+ if ( rb_respond_to(*ent, id_deep_freeze) ) {
9
+ rb_funcall(*ent, id_deep_freeze, 0);
10
+ } else {
11
+ rb_obj_freeze(*ent);
12
+ }
13
+ }
14
+ static void
15
+ km_mat_deep_freeze0(VALUE self)
16
+ {
17
+ SMAT *smat = km_mat2smat(self);
18
+ if ( smat->vtype == VT_VALUE ) {
19
+ km_smat_each_v(smat, km_mat_deep_freeze_func, NULL);
20
+ }
21
+ }
22
+ VALUE
23
+ kmm_mat_deep_freeze(VALUE self)
24
+ {
25
+ SMAT *smat = km_mat2smat(self);
26
+ if ( smat->stype != ST_FULL ) {
27
+ rb_raise(km_eShare, "can't deep_freeze submatricies directory. deep_freeze supermatrix instead");
28
+ }
29
+ if ( smat->may_have_sub ) {
30
+ VALUE subs = kmm_mat_submatricies(self);
31
+ for ( long i=0; i<RARRAY_LEN(subs); i++ ) {
32
+ km_mat_deep_freeze0(rb_ary_entry(subs, i));
33
+ }
34
+ }
35
+ km_mat_deep_freeze0(self);
36
+ return self;
37
+ }
38
+
39
+ typedef int each_obj_callback(void *, void *, size_t, void *);
40
+ void rb_objspace_each_objects(each_obj_callback *callback, void *data);
41
+ int rb_objspace_internal_object_p(VALUE obj);
42
+
43
+ // return true if `self' has at least one submatrix, otherwise, return false
44
+ struct km_have_sub {
45
+ bool found;
46
+ VALUE target;
47
+ };
48
+ static int
49
+ km_have_sub_p(void *vstart, void *vend, size_t stride, void *data)
50
+ {
51
+ struct km_have_sub *have_sub = (struct km_have_sub *)data;
52
+ for (VALUE v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
53
+ if (!rb_objspace_internal_object_p(v)) {
54
+ if (rb_obj_is_kind_of(v, km_cMat)) {
55
+ SMAT *smat = km_mat2smat(v);
56
+ if ( have_sub->target == smat->parent ) {
57
+ have_sub->found = true;
58
+ return 1;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ return 0;
64
+ }
65
+ VALUE
66
+ kmm_mat_have_submatrix_p(VALUE self)
67
+ {
68
+ SMAT *smat = km_mat2smat(self);
69
+ if ( smat->may_have_sub ) {
70
+ struct km_have_sub data = {false, self};
71
+ rb_objspace_each_objects(km_have_sub_p, (void *)&data);
72
+ if ( data.found ) {
73
+ return Qtrue;
74
+ } else {
75
+ smat->may_have_sub = false;
76
+ return Qfalse;
77
+ }
78
+ } else {
79
+ return Qfalse;
80
+ }
81
+ }
82
+
83
+ // the SMAT version of above
84
+ bool
85
+ km_smat_have_submatrix_p(SMAT *smat)
86
+ {
87
+ if ( smat->may_have_sub ) {
88
+ VALUE v = km_smat_find_value(smat);
89
+ if ( v == Qnil ) {
90
+ rb_raise(km_eInternal, "km_smat_have_submatrix_p has been called with out-of-ruby-controlled Mat struct");
91
+ } else {
92
+ return (kmm_mat_have_submatrix_p(v) != Qfalse);
93
+ }
94
+ } else {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ // find VALUE of `smat' from ObjectSpace.each_object
100
+ // return Qnil if not found
101
+ struct km_find_value {
102
+ SMAT *target;
103
+ VALUE out;
104
+ };
105
+ static int
106
+ km_find_value(void *vstart, void *vend, size_t stride, void *data)
107
+ {
108
+ struct km_find_value *fv = (struct km_find_value *)data;
109
+ for (VALUE v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
110
+ if (!rb_objspace_internal_object_p(v)) {
111
+ if ( rb_obj_is_kind_of(v, km_cMat) && km_mat2smat(v) == fv->target ) {
112
+ fv->out = v;
113
+ return 1;
114
+ }
115
+ }
116
+ }
117
+ return 0;
118
+ }
119
+ VALUE
120
+ km_smat_find_value(SMAT *smat)
121
+ {
122
+ struct km_find_value data = {smat, Qnil};
123
+ rb_objspace_each_objects(km_find_value, (void *)&data);
124
+ return data.out;
125
+ }
126
+
127
+ // return an Array submatricies of `self'
128
+ // the return will be nil if `self' is a submatrix (submatrix cannot have a submatrix of itself)
129
+ // the return will be an empty Array ([]) if `self' is full-matrix but does not have any submatricies
130
+ struct km_submx {
131
+ VALUE parent;
132
+ VALUE list;
133
+ };
134
+ static int
135
+ km_mat_submx(void *vstart, void *vend, size_t stride, void *data)
136
+ {
137
+ struct km_submx *sm = (struct km_submx *)data;
138
+ for ( VALUE v = (VALUE)vstart; v != (VALUE)vend; v += stride ) {
139
+ if (!rb_objspace_internal_object_p(v)) {
140
+ if ( rb_obj_is_kind_of(v, km_cMat) && km_mat2smat(v)->parent == sm->parent ) {
141
+ rb_ary_push(sm->list, v);
142
+ }
143
+ }
144
+ }
145
+ return 0;
146
+ }
147
+ VALUE
148
+ kmm_mat_submatricies(VALUE self)
149
+ {
150
+ SMAT *smat = km_mat2smat(self);
151
+ if ( smat->stype != ST_FULL ) {
152
+ return Qnil;
153
+ } else if ( !smat->may_have_sub ) {
154
+ return rb_ary_new();
155
+ }
156
+ struct km_submx data = {self, rb_ary_new()};
157
+ rb_objspace_each_objects(km_mat_submx, (void *)&data);
158
+ if ( RARRAY_LEN(data.list) == 0 ) {
159
+ smat->may_have_sub = false;
160
+ }
161
+ return data.list;
162
+ }
163
+
164
+ // return supermatrix of `self'
165
+ // the return will be nil if `self' is full-matrix
166
+ VALUE
167
+ kmm_mat_supermatrix(VALUE self)
168
+ {
169
+ SMAT *data = km_mat2smat(self);
170
+ return data->parent;
171
+ }
172
+
173
+ // if `self' is a supermatrix of some submatricies, detach all the submatricies by replacing them by copied full-matrix
174
+ // if `self' is a submatrix of a supermatrix, replace `self' by a copied full-matrix of 'self'
175
+ // return self if at least a matrix is replaced, otherwise, return nil
176
+ VALUE
177
+ kmm_mat_detach(int argc, VALUE *argv, VALUE self)
178
+ {
179
+ rb_check_arity(argc, 0, 1);
180
+ bool check_other = ( ( argc == 1 ) && RTEST(argv[0]) );
181
+ SMAT *smat = km_mat2smat(self);
182
+ if ( smat->stype == ST_FULL ) {
183
+ VALUE list = kmm_mat_submatricies(self);
184
+ if ( !smat->may_have_sub ) {
185
+ return Qnil;
186
+ }
187
+ for (long i=0; i<RARRAY_LEN(list); i++) {
188
+ VALUE elm = rb_ary_entry(list, i);
189
+ kmm_mat_replace(elm, rb_obj_dup(elm));
190
+ }
191
+ smat->may_have_sub = false;
192
+ return self;
193
+ } else {
194
+ VALUE old_parent = smat->parent;
195
+ kmm_mat_replace(self, rb_obj_dup(self));
196
+ if ( check_other ) {
197
+ kmm_mat_submatricies(old_parent);
198
+ }
199
+ return self;
200
+ }
201
+ }
202
+
203
+ // if `self' is a supermatrix of some submatricies, detach all the submatricies by replacing them by (0, 0)-matrix
204
+ // if `self' is a submatrix of a supermatrix, detach from the supermatrix
205
+ // in any case, `self' is replaced by (0, 0)-matrix, and return `self'
206
+ static VALUE
207
+ km_kill_func(VALUE elm, VALUE nil, VALUE self)
208
+ {
209
+ SMAT *ssub = km_mat2smat(elm);
210
+ if ( ssub->stype != ST_SSUB ) {
211
+ ruby_xfree(ssub->body);
212
+ }
213
+ ssub->stype = ST_FULL;
214
+ ssub->body = NULL;
215
+ ssub->m = 0; ssub->n = 0; ssub->ld = 0;
216
+ ssub->parent = Qnil;
217
+ return elm;
218
+ }
219
+ VALUE
220
+ kmm_mat__kill(VALUE self)
221
+ {
222
+ km_check_frozen(self);
223
+ SMAT *smat = km_mat2smat(self);
224
+ if ( smat->stype == ST_FULL ) {
225
+ VALUE list = kmm_mat_submatricies(self);
226
+ rb_iterate(rb_ary_each, list, km_kill_func, Qnil);
227
+ }
228
+ if ( smat->stype != ST_SSUB ) {
229
+ ruby_xfree(smat->body);
230
+ }
231
+ smat->stype = ST_FULL;
232
+ smat->body = NULL;
233
+ smat->m = 0; smat->n = 0; smat->ld = 0;
234
+ smat->may_have_sub = false; smat->parent = Qnil;
235
+ return self;
236
+ }
237
+
238
+ // replace the substance of `self' by `val'
239
+ // if `val' is a submatrix, `self' is a submatrix of the same supermatrix
240
+ // if `val' is a full-matrix, `self' is a copy of it (submatricies are not succeeded)
241
+ VALUE
242
+ kmm_mat_replace(VALUE self, VALUE val)
243
+ {
244
+ km_check_frozen(self);
245
+ SMAT *dest = km_mat2smat(self);
246
+ SMAT *src = km_mat2smat(val);
247
+ if ( kmm_mat_have_submatrix_p(self) ) {
248
+ rb_raise(km_eShare, "can't replace supermatrix. try detach before replacing");
249
+ }
250
+ if ( src->stype == ST_FULL ) {
251
+ switch ( dest->stype ) {
252
+ case ST_RSUB:
253
+ ruby_xfree(dest->body);
254
+ // FALL THROUGH
255
+ case ST_SSUB:
256
+ dest->vtype = VT_END;
257
+ dest->stype = ST_FULL;
258
+ dest->parent = Qnil;
259
+ dest->may_have_sub = false;
260
+ dest->body = NULL;
261
+ break;
262
+ default:
263
+ break;
264
+ }
265
+ km_smat_copy(dest, src);
266
+ } else if ( src->stype == ST_SSUB ) {
267
+ if ( dest->stype != ST_SSUB ) {
268
+ ruby_xfree(dest->body);
269
+ }
270
+ dest->body = src->body;
271
+ dest->ld = src->ld; dest->m = src->m; dest->n = src->n;
272
+ dest->vtype = src->vtype; dest->stype = ST_SSUB;
273
+ dest->trans = src->trans;
274
+ dest->parent = src->parent;
275
+ } else if ( src->stype == ST_RSUB ) {
276
+ if ( dest->stype != ST_RSUB || LENGTH(dest) != LENGTH(src) ) {
277
+ if ( dest->stype != ST_SSUB ) {
278
+ ruby_xfree(dest->body);
279
+ }
280
+ dest->body = ruby_xcalloc(LENGTHs(src), sizeof(void*));
281
+ }
282
+ memcpy(dest->body, src->body, sizeof(void*)*LENGTHs(src));
283
+ dest->ld = src->ld; dest->m = src->m; dest->n = src->n;
284
+ dest->vtype = src->vtype; dest->stype = ST_RSUB;
285
+ dest->trans = src->trans;
286
+ dest->parent = src->parent;
287
+ } else {
288
+ rb_raise(km_eInternal, "unknown storage type");
289
+ }
290
+ return self;
291
+ }
292
+
293
+ VALUE
294
+ km_Mat_ssub(int i, int j, int m, int n, VALUE super)
295
+ {
296
+ SMAT *ssup = km_mat2smat(super);
297
+ if ( ssup->m < i+m || ssup->n < j+n ) {
298
+ rb_raise(rb_eIndexError, "given index+size (%d+%d, %d+%d) is out of range (%d, %d)", i, m, j, n, ssup->m, ssup->n);
299
+ }
300
+ SMAT *sret;
301
+ if ( ssup->stype == ST_FULL ) {
302
+ VT_SWITCH( ssup->vtype,
303
+ sret = km_smat_alloc_with(m, n, VT_DOUBLE, ssup->dbody+INDEX(ssup, i, j));,
304
+ sret = km_smat_alloc_with(m, n, VT_COMPLEX, ssup->zbody+INDEX(ssup, i, j));,
305
+ sret = km_smat_alloc_with(m, n, VT_INT, ssup->ibody+INDEX(ssup, i, j));,
306
+ sret = km_smat_alloc_with(m, n, VT_BOOL, ssup->bbody+INDEX(ssup, i, j));,
307
+ sret = km_smat_alloc_with(m, n, VT_VALUE, ssup->vbody+INDEX(ssup, i, j));
308
+ );
309
+ sret->parent = super;
310
+ ssup->may_have_sub = true;
311
+ } else if ( ssup->stype == ST_SSUB ) {
312
+ VT_SWITCH( ssup->vtype,
313
+ sret = km_smat_alloc_with(m, n, VT_DOUBLE, ssup->dbody+INDEX(ssup, i, j));,
314
+ sret = km_smat_alloc_with(m, n, VT_COMPLEX, ssup->zbody+INDEX(ssup, i, j));,
315
+ sret = km_smat_alloc_with(m, n, VT_INT, ssup->ibody+INDEX(ssup, i, j));,
316
+ sret = km_smat_alloc_with(m, n, VT_BOOL, ssup->bbody+INDEX(ssup, i, j));,
317
+ sret = km_smat_alloc_with(m, n, VT_VALUE, ssup->vbody+INDEX(ssup, i, j));
318
+ );
319
+ sret->parent = ssup->parent;
320
+ } else if ( ssup->stype == ST_RSUB ) {
321
+ int is[m]; int js[n];
322
+ for ( int k=0; k<m; k++ ) { is[k] = i+k; }
323
+ for ( int k=0; k<n; k++ ) { js[k] = j+k; }
324
+ return km_Mat_rsub1(m, n, is, js, super);
325
+ } else {
326
+ rb_raise(km_eInternal, "unknown storage type");
327
+ }
328
+ sret->trans=ssup->trans; sret->ld = ssup->ld; sret->stype = ST_SSUB;
329
+ VALUE ret = TypedData_Wrap_Struct(km_cMat, &km_mat_data_type, sret);
330
+ km_infect_frozen(super, ret);
331
+ return ret;
332
+ }
333
+
334
+ static void
335
+ km_rsub_check_range(SMAT *ssup, int ii, int jj)
336
+ {
337
+ if ( ii < 0 || ssup->m <= ii || jj < 0 || ssup->n <= jj ) {
338
+ rb_raise(rb_eIndexError, "given index (%d, %d) is out of range (%d, %d)", ii, jj, ssup->m, ssup->n);
339
+ }
340
+ }
341
+ #define RSUB1_LOOPr(id) for ( int i=0; i<m; i++ ) { for ( int j=0; j<n; j++ ) { \
342
+ km_rsub_check_range(ssup, is[i], js[j]); \
343
+ sret->id##pbody[i+j*m] = ssup->id##pbody[INDEX(ssup, is[i], js[j])]; \
344
+ } }
345
+ #define RSUB1_LOOP(id) for ( int i=0; i<m; i++ ) { for ( int j=0; j<n; j++ ) { \
346
+ km_rsub_check_range(ssup, is[i], js[j]); \
347
+ sret->id##pbody[i+j*m] = ssup->id##body + INDEX(ssup, is[i], js[j]); \
348
+ } }
349
+ VALUE
350
+ km_Mat_rsub1(int m, int n, int *is, int *js, VALUE super)
351
+ {
352
+ km_check_positive(m, n);
353
+ VALUE ret = km_Mat_alloc(km_cMat);
354
+ SMAT *ssup = km_mat2smat(super);
355
+ SMAT *sret = km_mat2smat(ret);
356
+ km_smat_alloc_pbody(sret, m, n, ssup->vtype);
357
+ if ( ssup->stype == ST_RSUB ) {
358
+ VT_SWITCH( ssup->vtype,
359
+ RSUB1_LOOPr(d);,
360
+ RSUB1_LOOPr(z);,
361
+ RSUB1_LOOPr(i);,
362
+ RSUB1_LOOPr(b);,
363
+ RSUB1_LOOPr(v);
364
+ );
365
+ sret->parent = ssup->parent;
366
+ } else {
367
+ VT_SWITCH( ssup->vtype,
368
+ RSUB1_LOOP(d);,
369
+ RSUB1_LOOP(z);,
370
+ RSUB1_LOOP(i);,
371
+ RSUB1_LOOP(b);,
372
+ RSUB1_LOOP(v);
373
+ );
374
+ if ( ssup->stype == ST_FULL ) {
375
+ sret->parent = super;
376
+ ssup->may_have_sub = true;
377
+ } else {
378
+ sret->parent = ssup->parent;
379
+ }
380
+ }
381
+ km_infect_frozen(super, ret);
382
+ return ret;
383
+ }
384
+
385
+ #define RSUB2_LOOPr(id) for( int i=0; i<m; i++ ) { for ( int j=0; j<n; j++ ) { \
386
+ km_rsub_check_range(ssup, is[i+j*m], js[i+j*m]); \
387
+ sret->id##pbody[i+j*m] = ssup->id##pbody[INDEX(ssup, is[i+j*m], js[i+j*m])]; \
388
+ } }
389
+ #define RSUB2_LOOP(id) for( int i=0; i<m; i++ ) { for ( int j=0; j<n; j++ ) { \
390
+ km_rsub_check_range(ssup, is[i+j*m], js[i+j*m]); \
391
+ sret->id##pbody[i+j*m] = ssup->id##body+INDEX(ssup, is[i+j*m], js[i+j*m]); \
392
+ } }
393
+ VALUE
394
+ km_Mat_rsub2(int m, int n, int *is, int *js, VALUE super)
395
+ {
396
+ km_check_positive(m, n);
397
+ VALUE ret = km_Mat_alloc(km_cMat);
398
+ SMAT *ssup = km_mat2smat(super);
399
+ SMAT *sret = km_mat2smat(ret);
400
+ km_smat_alloc_pbody(sret, m, n, ssup->vtype);
401
+ if ( ssup->stype == ST_RSUB ) {
402
+ VT_SWITCH( ssup->vtype,
403
+ RSUB2_LOOPr(d);,
404
+ RSUB2_LOOPr(z);,
405
+ RSUB2_LOOPr(i);,
406
+ RSUB2_LOOPr(b);,
407
+ RSUB2_LOOPr(v);
408
+ );
409
+ sret->parent = ssup->parent;
410
+ } else {
411
+ VT_SWITCH( ssup->vtype,
412
+ RSUB2_LOOP(d);,
413
+ RSUB2_LOOP(z);,
414
+ RSUB2_LOOP(i);,
415
+ RSUB2_LOOP(b);,
416
+ RSUB2_LOOP(v);
417
+ );
418
+ if ( ssup->stype == ST_FULL ) {
419
+ sret->parent = super;
420
+ ssup->may_have_sub = true;
421
+ } else {
422
+ sret->parent = ssup->parent;
423
+ }
424
+ }
425
+ km_infect_frozen(super, ret);
426
+ return ret;
427
+ }
@@ -0,0 +1,530 @@
1
+ #include "../kmat.h"
2
+
3
+ static void
4
+ km_rb_gc_mark_wrap(VALUE *obj, void *null)
5
+ {
6
+ rb_gc_mark(*obj);
7
+ }
8
+ static void
9
+ km_smat_mark(void *_data)
10
+ {
11
+ SMAT *data = (SMAT *)_data;
12
+ rb_gc_mark(data->parent);
13
+ if ( data->vtype == VT_VALUE && data->body != NULL ) {
14
+ km_smat_each_v(data, km_rb_gc_mark_wrap, NULL);
15
+ }
16
+ }
17
+
18
+ static void
19
+ km_smat_free(void *_data)
20
+ {
21
+ SMAT *data = (SMAT *)_data;
22
+ if ( data != NULL ) {
23
+ if ( data->stype != ST_SSUB && data->body != NULL ) {
24
+ ruby_xfree(data->body);
25
+ }
26
+ ruby_xfree(data);
27
+ }
28
+ }
29
+
30
+ static size_t
31
+ km_smat_size(const void *_data)
32
+ {
33
+ const SMAT *data = (const SMAT *)_data;
34
+ if ( data != NULL ) {
35
+ size_t ret = sizeof(SMAT);
36
+ if ( data->body != NULL ) {
37
+ if ( data->stype == ST_FULL ) {
38
+ ret += km_sizeof_vt(data->vtype)*int2size_t(data->m*data->n);
39
+ } else if ( data->stype == ST_RSUB ) {
40
+ ret += sizeof(void *)*int2size_t(data->m*data->n);
41
+ }
42
+ }
43
+ return ret;
44
+ } else {
45
+ return (size_t)0;
46
+ }
47
+ }
48
+
49
+ // functions for allocation
50
+ const rb_data_type_t km_mat_data_type = {
51
+ "kmat-Mat",
52
+ {
53
+ km_smat_mark,
54
+ km_smat_free,
55
+ km_smat_size,
56
+ { (void *)0, (void *)0 }
57
+ },
58
+ (rb_data_type_t *)0,
59
+ (void *)0,
60
+ (VALUE)0
61
+ };
62
+ VALUE
63
+ km_Mat_alloc(VALUE klass)
64
+ {
65
+ return TypedData_Wrap_Struct(klass, &km_mat_data_type, km_smat_alloc_with(0, 0, VT_END, NULL));
66
+ }
67
+
68
+ // calloc a side of SMAT
69
+ // return->body is the argument `body'
70
+ SMAT *
71
+ km_smat_alloc_with(int m, int n, VTYPE vt, void *body)
72
+ {
73
+ km_check_positive(m, n);
74
+ SMAT *data = ZALLOC(SMAT);
75
+ data->body = body; data->ld = data->m = m; data->n = n;
76
+ data->vtype = vt; data->stype = ST_FULL; data->trans = false;
77
+ data->may_have_sub = false; data->parent = Qnil;
78
+ return data;
79
+ }
80
+
81
+ SMAT *
82
+ km_smat_alloc(int m, int n, VTYPE vt)
83
+ {
84
+ km_check_positive(m, n);
85
+ void *body = ruby_xcalloc(int2size_t(n*m), km_sizeof_vt(vt));
86
+ return km_smat_alloc_with(m, n, vt, body);
87
+ }
88
+
89
+ // calloc a SMAT of (m, n)-matrix
90
+ // return->body will be calloc-ed
91
+ void
92
+ km_smat_alloc_body(SMAT *data, int m, int n, VTYPE vt)
93
+ {
94
+ km_check_positive(m, n);
95
+ if ( data->stype != ST_FULL ) {
96
+ rb_raise(km_eShare, "can't re-alloc submatrix body");
97
+ } else if ( km_smat_have_submatrix_p(data) ) {
98
+ rb_raise(km_eShare, "can't re-alloc supermatrix body");
99
+ }
100
+ data->ld = data->m = m; data->n = n; data->vtype = vt; data->stype = ST_FULL;
101
+ ruby_xfree(data->body);
102
+ data->body = ruby_xcalloc(int2size_t(n*m), km_sizeof_vt(vt));
103
+ }
104
+ void
105
+ km_smat_alloc_pbody(SMAT *data, int m, int n, VTYPE vt)
106
+ {
107
+ km_check_positive(m, n);
108
+ if ( data->stype != ST_FULL ) {
109
+ rb_raise(km_eShare, "can't re-alloc submatrix body");
110
+ } else if ( km_smat_have_submatrix_p(data) ) {
111
+ rb_raise(km_eShare, "can't re-alloc supermatrix body");
112
+ }
113
+ data->ld = data->m = m; data->n = n; data->vtype = vt; data->stype = ST_RSUB;
114
+ ruby_xfree(data->body);
115
+ data->body = ruby_xcalloc(int2size_t(n*m), sizeof(void*));
116
+ }
117
+
118
+
119
+ // extract and return SMAT from mat_obj
120
+ SMAT *
121
+ km_mat2smat(VALUE mat_obj)
122
+ {
123
+ SMAT *data;
124
+ if ( !rb_obj_is_kind_of(mat_obj, km_cMat) ) {
125
+ rb_raise(rb_eTypeError, "Mat is expected, not %s", rb_obj_classname(mat_obj));
126
+ }
127
+ TypedData_Get_Struct(mat_obj, SMAT, &km_mat_data_type, data);
128
+ return data;
129
+ }
130
+
131
+ // copy the content of SMAT
132
+ // if the size are not same, calloc before copying
133
+ #define DEFINE_SMAT_COPY(id, type) static void \
134
+ km_smat_copy_##id(type *ed, const type *es, void *null) \
135
+ { \
136
+ *ed = *es; \
137
+ }
138
+ DEFINE_SMAT_COPY(d, double)
139
+ DEFINE_SMAT_COPY(z, COMPLEX)
140
+ DEFINE_SMAT_COPY(i, int)
141
+ DEFINE_SMAT_COPY(b, bool)
142
+ DEFINE_SMAT_COPY(v, VALUE)
143
+ void
144
+ km_smat_copy(SMAT *dest, const SMAT *src)
145
+ {
146
+ if ( src->body == NULL ) {
147
+ ruby_xfree(dest->body);
148
+ dest->body = NULL;
149
+ } else {
150
+ if ( dest->vtype != src->vtype || LENGTH(dest) != LENGTH(src) ) { // re-calloc
151
+ if ( dest->stype != ST_FULL ) { // the destination must not be a submatrix
152
+ rb_raise(km_eShare, "can't copy to value-type mismatched or dimension mismatched submatrix");
153
+ }
154
+ ruby_xfree(dest->body);
155
+ dest->body = ruby_xcalloc(LENGTHs(src), km_sizeof_vt(src->vtype));
156
+ dest->ld = src->m; dest->vtype = src->vtype;
157
+ } else if ( dest->m != src->m ) { // need not to resize but reshape is needed
158
+ if ( dest->stype != ST_FULL ) { // the destination must not be a submatrix
159
+ rb_raise(km_eShare, "can't reshape submatrix");
160
+ }
161
+ dest->ld = src->m;
162
+ }
163
+ dest->m = src->m; dest->n = src->n;
164
+ if ( dest->stype==ST_FULL && src->stype==ST_FULL ) {
165
+ dest->ld = src->ld; dest->trans = src->trans;
166
+ memcpy(dest->body, src->body, km_sizeof_vt(src->vtype)*LENGTHs(src));
167
+ } else {
168
+ VT_SWITCH( dest->vtype,
169
+ km_smat_each2_dcd(dest, src, km_smat_copy_d, NULL);,
170
+ km_smat_each2_zcz(dest, src, km_smat_copy_z, NULL);,
171
+ km_smat_each2_ici(dest, src, km_smat_copy_i, NULL);,
172
+ km_smat_each2_bcb(dest, src, km_smat_copy_b, NULL);,
173
+ km_smat_each2_vcv(dest, src, km_smat_copy_v, NULL);
174
+ );
175
+ }
176
+ }
177
+ }
178
+
179
+ // Mat#marhsal_dump/load for Marshal.dump/load
180
+ // return an Array with 2 elements
181
+ // the first element is a bytes (String) which contains shape and value type
182
+ // the second element is `self'.to_ary if the value type is ruby-object
183
+ // otherwise, the second element is a bytes (String) which is the same as `self'->body
184
+ // the supermatrix-submatrix information will not be saved
185
+ VALUE
186
+ kmm_mat_marshal_dump(VALUE self)
187
+ {
188
+ SMAT *smat = km_mat2smat(self);
189
+ if ( smat->stype != ST_FULL ) {
190
+ smat = km_mat2smat(rb_obj_dup(self));
191
+ }
192
+ VALUE headder = rb_str_new((char *)&(smat->vtype), sizeof(VTYPE));
193
+ VALUE body;
194
+ if ( smat->vtype == VT_VALUE ) {
195
+ body = kmm_mat_to_ary(self);
196
+ } else {
197
+ rb_str_cat(headder, (char *)&(smat->m), sizeof(int));
198
+ rb_str_cat(headder, (char *)&(smat->n), sizeof(int));
199
+ rb_str_cat(headder, (char *)&(smat->trans), sizeof(bool));
200
+ body = rb_str_new((char *)(smat->body), (long)km_sizeof_vt(smat->vtype)*LENGTH(smat));
201
+ }
202
+ return rb_ary_new3(2, headder, body);
203
+ }
204
+ VALUE
205
+ kmm_mat_marshal_load(VALUE self, VALUE dump)
206
+ {
207
+ SMAT *smat = km_mat2smat(self);
208
+ char *hptr = RSTRING_PTR(rb_ary_entry(dump, 0));
209
+ VALUE body = rb_ary_entry(dump, 1);
210
+ memcpy(&(smat->vtype), hptr, sizeof(VTYPE));
211
+ if ( smat->vtype == VT_VALUE ) {
212
+ km_smat_copy(smat, km_mat2smat(kmm_ary_to_omat(body)));
213
+ } else {
214
+ hptr += sizeof(VTYPE);
215
+ int m, n; bool t;
216
+ memcpy(&m, hptr, sizeof(int)); hptr += sizeof(int);
217
+ memcpy(&n, hptr, sizeof(int)); hptr += sizeof(int);
218
+ memcpy(&t, hptr, sizeof(bool)); hptr += sizeof(bool);
219
+ km_smat_alloc_body(smat, m, n, smat->vtype);
220
+ smat->trans = t;
221
+ size_t sb = km_sizeof_vt(smat->vtype)*LENGTHs(smat);
222
+ if ( RSTRING_LEN(body) != (long)sb ) {
223
+ rb_raise(rb_eArgError, "wrong object given");
224
+ }
225
+ memcpy(smat->body, RSTRING_PTR(body), sb);
226
+ }
227
+ return self;
228
+ }
229
+
230
+ // call `func'(&element, `data') for each elements of `smat'
231
+ #define DEFINE_KM_SMAT_EACH_ID(id, type) void \
232
+ km_smat_each_##id(SMAT *smat, void (*func)(type *, void *), void *data) \
233
+ { \
234
+ if ( smat->stype == ST_RSUB ) { \
235
+ if ( smat->trans ) { \
236
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
237
+ func(smat->id##pbody[j+i*(smat->ld)], data); \
238
+ } } \
239
+ } else { \
240
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
241
+ func(smat->id##pbody[i+j*(smat->ld)], data); \
242
+ } } \
243
+ } \
244
+ } else { \
245
+ if ( smat->trans ) { \
246
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
247
+ func(&(smat->id##body[j+i*(smat->ld)]), data); \
248
+ } } \
249
+ } else { \
250
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
251
+ func(&(smat->id##body[i+j*(smat->ld)]), data); \
252
+ } } \
253
+ } \
254
+ } \
255
+ }
256
+ DEFINE_KM_SMAT_EACH_ID(d, double)
257
+ DEFINE_KM_SMAT_EACH_ID(z, COMPLEX)
258
+ DEFINE_KM_SMAT_EACH_ID(i, int)
259
+ DEFINE_KM_SMAT_EACH_ID(b, bool)
260
+ DEFINE_KM_SMAT_EACH_ID(v, VALUE)
261
+
262
+ // call `func'(&element, `data', i, j) for each elements of `smat'
263
+ #define DEFINE_KM_SMAT_EACH_WI_ID(id, type) void \
264
+ km_smat_each_with_index_##id(SMAT *smat, void (*func)(type *, int, int, void *), void *data) \
265
+ { \
266
+ if ( smat->stype == ST_RSUB ) { \
267
+ if ( smat->trans ) { \
268
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
269
+ func(smat->id##pbody[j+i*(smat->ld)], i, j, data); \
270
+ } } \
271
+ } else { \
272
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
273
+ func(smat->id##pbody[i+j*(smat->ld)], i, j, data); \
274
+ } } \
275
+ } \
276
+ } else { \
277
+ if ( smat->trans ) { \
278
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
279
+ func(&(smat->id##body[j+i*(smat->ld)]), i, j, data); \
280
+ } } \
281
+ } else { \
282
+ for ( int i=0; i<smat->m; i++ ) { for ( int j=0; j<smat->n; j++ ) { \
283
+ func(&(smat->id##body[i+j*(smat->ld)]), i, j, data); \
284
+ } } \
285
+ } \
286
+ } \
287
+ }
288
+ DEFINE_KM_SMAT_EACH_WI_ID(d, double)
289
+ DEFINE_KM_SMAT_EACH_WI_ID(z, COMPLEX)
290
+ DEFINE_KM_SMAT_EACH_WI_ID(i, int)
291
+ DEFINE_KM_SMAT_EACH_WI_ID(b, bool)
292
+ DEFINE_KM_SMAT_EACH_WI_ID(v, VALUE)
293
+
294
+ // call `func'(&(element of sa), &(element of sb), `data') for each elements of `sa'
295
+ // you must check the shape of `sb' is the same as that of `sa'
296
+ // SEGV will occur if `sb' is smaller than `sa'
297
+ #define KM_SMAT_EACH2_BLOOP(elma, id) if ( sb->stype == ST_RSUB ) { \
298
+ if ( sb->trans ) { \
299
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
300
+ func(elma, sb->id##pbody[j+i*(sb->ld)], data); \
301
+ } } \
302
+ } else { \
303
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
304
+ func(elma, sb->id##pbody[i+j*(sb->ld)], data); \
305
+ } } \
306
+ } \
307
+ } else { \
308
+ if ( sb->trans ) { \
309
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
310
+ func(elma, &(sb->id##body[j+i*(sb->ld)]), data); \
311
+ } } \
312
+ } else { \
313
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
314
+ func(elma, &(sb->id##body[i+j*(sb->ld)]), data); \
315
+ } } \
316
+ } \
317
+ }
318
+ #define DEFINE_KM_SMAT_EACH2_ID(id, type) void \
319
+ km_smat_each2_##id(SMAT *sa, SMAT *sb, void (*func)(type *, type *, void *), void *data) \
320
+ { \
321
+ if ( sa->stype == ST_RSUB ) { \
322
+ if ( sa->trans ) { \
323
+ KM_SMAT_EACH2_BLOOP(sa->id##pbody[j+i*(sa->ld)], id) \
324
+ } else { \
325
+ KM_SMAT_EACH2_BLOOP(sa->id##pbody[i+j*(sa->ld)], id) \
326
+ } \
327
+ } else { \
328
+ if ( sa->trans ) { \
329
+ KM_SMAT_EACH2_BLOOP(&(sa->id##body[j+i*(sa->ld)]), id) \
330
+ } else { \
331
+ KM_SMAT_EACH2_BLOOP(&(sa->id##body[i+j*(sa->ld)]), id) \
332
+ } \
333
+ } \
334
+ }
335
+ #define DEFINE_KM_SMAT_EACH2_ID_CONST_ID(id, type, id2, type2) void \
336
+ km_smat_each2_##id##c##id2(SMAT *sa, const SMAT *sb, void (*func)(type *, const type2 *, void *), void *data) \
337
+ { \
338
+ if ( sa->stype == ST_RSUB ) { \
339
+ if ( sa->trans ) { \
340
+ KM_SMAT_EACH2_BLOOP(sa->id##pbody[j+i*(sa->ld)], id2) \
341
+ } else { \
342
+ KM_SMAT_EACH2_BLOOP(sa->id##pbody[i+j*(sa->ld)], id2) \
343
+ } \
344
+ } else { \
345
+ if ( sa->trans ) { \
346
+ KM_SMAT_EACH2_BLOOP(&(sa->id##body[j+i*(sa->ld)]), id2) \
347
+ } else { \
348
+ KM_SMAT_EACH2_BLOOP(&(sa->id##body[i+j*(sa->ld)]), id2) \
349
+ } \
350
+ } \
351
+ }
352
+ DEFINE_KM_SMAT_EACH2_ID(d, double)
353
+ DEFINE_KM_SMAT_EACH2_ID(z, COMPLEX)
354
+ DEFINE_KM_SMAT_EACH2_ID(i, int)
355
+ DEFINE_KM_SMAT_EACH2_ID(b, bool)
356
+ DEFINE_KM_SMAT_EACH2_ID(v, VALUE)
357
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(d, double, d, double)
358
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(z, COMPLEX, z, COMPLEX)
359
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(i, int, i, int)
360
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(b, bool, b, bool)
361
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(v, VALUE, v, VALUE)
362
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(d, double, b, bool)
363
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(z, COMPLEX, b, bool)
364
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(i, int, b, bool)
365
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(v, VALUE, b, bool)
366
+ DEFINE_KM_SMAT_EACH2_ID_CONST_ID(d, double, z, COMPLEX)
367
+
368
+ // call `func'(&(element of sa), &(element of sb), &(element of sc), `data') for each elements of `sa'
369
+ // you must check the shape of `sb' and that of `sc' are the same as that of `sa'
370
+ // SEGV will occur if `sb' or `sc' is smaller than `sa'
371
+ #define KM_SMAT_EACH3_CLOOP(elma, elmb, id) if ( sc->stype == ST_RSUB ) { \
372
+ if ( sc->trans ) { \
373
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
374
+ func(elma, elmb, sc->id##pbody[j+i*(sc->ld)], data); \
375
+ } } \
376
+ } else { \
377
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
378
+ func(elma, elmb, sc->id##pbody[i+j*(sc->ld)], data); \
379
+ } } \
380
+ } \
381
+ } else { \
382
+ if ( sc->trans ) { \
383
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
384
+ func(elma, elmb, &(sc->id##body[j+i*(sc->ld)]), data); \
385
+ } } \
386
+ } else { \
387
+ for ( int i=0; i<sa->m; i++ ) { for ( int j=0; j<sa->n; j++ ) { \
388
+ func(elma, elmb, &(sc->id##body[i+j*(sc->ld)]), data); \
389
+ } } \
390
+ } \
391
+ }
392
+ #define KM_SMAT_EACH3_BLOOP(elma, id) if ( sb->stype == ST_RSUB ) { \
393
+ if ( sb->trans ) { \
394
+ KM_SMAT_EACH3_CLOOP(elma, sb->id##pbody[j+i*(sb->ld)], id) \
395
+ } else { \
396
+ KM_SMAT_EACH3_CLOOP(elma, sb->id##pbody[i+j*(sb->ld)], id) \
397
+ } \
398
+ } else { \
399
+ if ( sb->trans ) { \
400
+ KM_SMAT_EACH3_CLOOP(elma, &(sb->id##body[j+i*(sb->ld)]), id) \
401
+ } else { \
402
+ KM_SMAT_EACH3_CLOOP(elma, &(sb->id##body[i+j*(sb->ld)]), id) \
403
+ } \
404
+ }
405
+ #define DEFINE_KM_SMAT_EACH3_ID(id, type) void \
406
+ km_smat_each3_##id(SMAT *sa, SMAT *sb, SMAT *sc, void (*func)(type *, type *, type *, void *), void *data) \
407
+ { \
408
+ if ( sa->stype == ST_RSUB ) { \
409
+ if ( sa->trans ) { \
410
+ KM_SMAT_EACH3_BLOOP(sa->id##pbody[j+i*(sa->ld)], id) \
411
+ } else { \
412
+ KM_SMAT_EACH3_BLOOP(sa->id##pbody[i+j*(sa->ld)], id) \
413
+ } \
414
+ } else { \
415
+ if ( sa->trans ) { \
416
+ KM_SMAT_EACH3_BLOOP(&(sa->id##body[j+i*(sa->ld)]), id) \
417
+ } else { \
418
+ KM_SMAT_EACH3_BLOOP(&(sa->id##body[i+j*(sa->ld)]), id) \
419
+ } \
420
+ } \
421
+ }
422
+ // DEFINE_KM_SMAT_EACH3_ID(d, double)
423
+ // DEFINE_KM_SMAT_EACH3_ID(z, COMPLEX)
424
+ // DEFINE_KM_SMAT_EACH3_ID(i, int)
425
+ // DEFINE_KM_SMAT_EACH3_ID(b, bool)
426
+ // DEFINE_KM_SMAT_EACH3_ID(v, VALUE)
427
+ void
428
+ km_smat_each3_zcdcd(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(COMPLEX *, const double *, const double *, void *), void *data)
429
+ {
430
+ if ( sa->stype == ST_RSUB ) {
431
+ if ( sa->trans ) {
432
+ KM_SMAT_EACH3_BLOOP(sa->zpbody[j+i*(sa->ld)], d)
433
+ } else {
434
+ KM_SMAT_EACH3_BLOOP(sa->zpbody[i+j*(sa->ld)], d)
435
+ }
436
+ } else {
437
+ if ( sa->trans ) {
438
+ KM_SMAT_EACH3_BLOOP(&(sa->zbody[j+i*(sa->ld)]), d)
439
+ } else {
440
+ KM_SMAT_EACH3_BLOOP(&(sa->zbody[i+j*(sa->ld)]), d)
441
+ }
442
+ }
443
+ }
444
+
445
+ void
446
+ km_smat_each3_bcdcd(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(bool *, const double *, const double *, void *), void *data)
447
+ {
448
+ if ( sa->stype == ST_RSUB ) {
449
+ if ( sa->trans ) {
450
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[j+i*(sa->ld)], d)
451
+ } else {
452
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[i+j*(sa->ld)], d)
453
+ }
454
+ } else {
455
+ if ( sa->trans ) {
456
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[j+i*(sa->ld)]), d)
457
+ } else {
458
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[i+j*(sa->ld)]), d)
459
+ }
460
+ }
461
+ }
462
+ void
463
+ km_smat_each3_bczcz(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(bool *, const COMPLEX *, const COMPLEX *, void *), void *data)
464
+ {
465
+ if ( sa->stype == ST_RSUB ) {
466
+ if ( sa->trans ) {
467
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[j+i*(sa->ld)], z)
468
+ } else {
469
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[i+j*(sa->ld)], z)
470
+ }
471
+ } else {
472
+ if ( sa->trans ) {
473
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[j+i*(sa->ld)]), z)
474
+ } else {
475
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[i+j*(sa->ld)]), z)
476
+ }
477
+ }
478
+ }
479
+ void
480
+ km_smat_each3_bcici(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(bool *, const int *, const int *, void *), void *data)
481
+ {
482
+ if ( sa->stype == ST_RSUB ) {
483
+ if ( sa->trans ) {
484
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[j+i*(sa->ld)], i)
485
+ } else {
486
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[i+j*(sa->ld)], i)
487
+ }
488
+ } else {
489
+ if ( sa->trans ) {
490
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[j+i*(sa->ld)]), i)
491
+ } else {
492
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[i+j*(sa->ld)]), i)
493
+ }
494
+ }
495
+ }
496
+ void
497
+ km_smat_each3_bcbcb(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(bool *, const bool *, const bool *, void *), void *data)
498
+ {
499
+ if ( sa->stype == ST_RSUB ) {
500
+ if ( sa->trans ) {
501
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[j+i*(sa->ld)], b)
502
+ } else {
503
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[i+j*(sa->ld)], b)
504
+ }
505
+ } else {
506
+ if ( sa->trans ) {
507
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[j+i*(sa->ld)]), b)
508
+ } else {
509
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[i+j*(sa->ld)]), b)
510
+ }
511
+ }
512
+ }
513
+ void
514
+ km_smat_each3_bcvcv(SMAT *sa, const SMAT *sb, const SMAT *sc, void (*func)(bool *, const VALUE *, const VALUE *, void *), void *data)
515
+ {
516
+ if ( sa->stype == ST_RSUB ) {
517
+ if ( sa->trans ) {
518
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[j+i*(sa->ld)], v)
519
+ } else {
520
+ KM_SMAT_EACH3_BLOOP(sa->bpbody[i+j*(sa->ld)], v)
521
+ }
522
+ } else {
523
+ if ( sa->trans ) {
524
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[j+i*(sa->ld)]), v)
525
+ } else {
526
+ KM_SMAT_EACH3_BLOOP(&(sa->bbody[i+j*(sa->ld)]), v)
527
+ }
528
+ }
529
+ }
530
+