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,1156 @@
1
+ #include "../kmat.h"
2
+
3
+ // sort rows or columns by ascending order
4
+ static int
5
+ km_int_comp(const void *a, const void *b)
6
+ {
7
+ return *(int *)a-*(int *)b;
8
+ }
9
+ static int
10
+ km_bool_comp(const void *a, const void *b)
11
+ {
12
+ if ( *(bool *)a ) {
13
+ if ( *(bool *)b ) {
14
+ return 0;
15
+ } else {
16
+ return 1;
17
+ }
18
+ } else {
19
+ if ( *(bool *)b ) {
20
+ return -1;
21
+ } else {
22
+ return 0;
23
+ }
24
+ }
25
+ }
26
+ static int
27
+ km_value_comp(const void *a, const void *b)
28
+ {
29
+ return NUM2INT(rb_funcall(*(VALUE *)a, id_op_comp, 1, *(VALUE *)b));
30
+ }
31
+ static void
32
+ km_sort_seg(int size_seg, int ld, int num_seg, void *body, VTYPE vt)
33
+ {
34
+ if ( vt == VT_DOUBLE ) {
35
+ for ( int i=0; i<num_seg; i++ ) {
36
+ int info; char id[] = "I";
37
+ dlasrt_(id, &size_seg, ((double *)body)+(i*ld), &info);
38
+ }
39
+ } else if ( vt == VT_INT ) {
40
+ for ( int i=0; i<num_seg; i++ ) {
41
+ qsort(((int *)body)+(i*ld), int2size_t(size_seg), sizeof(int), km_int_comp);
42
+ }
43
+ } else if ( vt == VT_BOOL ) {
44
+ for ( int i=0; i<num_seg; i++ ) {
45
+ qsort(((bool *)body)+(i*ld), int2size_t(size_seg), sizeof(bool), km_bool_comp);
46
+ }
47
+ } else {
48
+ for ( int i=0; i<num_seg; i++ ) {
49
+ qsort(((VALUE *)body)+(i*ld), int2size_t(size_seg), sizeof(VALUE), km_value_comp);
50
+ }
51
+ }
52
+ }
53
+ #define SKEWER(type) type *b = (type *)body; type *b2 = ZALLOC_N(type, size_sk*num_sk); \
54
+ for ( int i=0; i<size_sk; i++ ) { \
55
+ for ( int j=0; j<num_sk; j++ ) { \
56
+ b2[i+j*size_sk] = b[j+i*ld]; \
57
+ } \
58
+ } \
59
+ km_sort_seg(size_sk, size_sk, num_sk, b2, vt); \
60
+ for ( int i=0; i<size_sk; i++ ) { \
61
+ for ( int j=0; j<num_sk; j++ ) { \
62
+ b[j+i*ld] = b2[i+j*size_sk]; \
63
+ } \
64
+ } \
65
+ ruby_xfree(b2)
66
+
67
+ static void
68
+ km_sort_skewer(int size_sk, int ld, int num_sk, void *body, VTYPE vt)
69
+ {
70
+ if ( vt == VT_DOUBLE ) {
71
+ SKEWER(double);
72
+ } else if ( vt == VT_INT ) {
73
+ SKEWER(int);
74
+ } else {
75
+ SKEWER(VALUE);
76
+ }
77
+ }
78
+ static void
79
+ km_smat_sort(SMAT *smat, VALUE asym)
80
+ {
81
+ if ( rb_respond_to(asym, id_to_sym) ) {
82
+ asym = rb_funcall(asym, id_to_sym, 0);
83
+ }
84
+ if ( asym == sym_col || asym == sym_c || asym == sym_column ) {
85
+ if ( smat->trans ) {
86
+ km_sort_skewer(smat->m, smat->ld, smat->n, smat->body, smat->vtype);
87
+ } else {
88
+ km_sort_seg(smat->m, smat->ld, smat->n, smat->body, smat->vtype);
89
+ }
90
+ } else if ( asym == sym_row || asym == sym_r ) {
91
+ if ( smat->trans ) {
92
+ km_sort_seg(smat->n, smat->ld, smat->m, smat->body, smat->vtype);
93
+ } else {
94
+ km_sort_skewer(smat->n, smat->ld, smat->m, smat->body, smat->vtype);
95
+ }
96
+ } else if ( asym == sym_none || asym == sym_n ) {
97
+ return;
98
+ } else {
99
+ rb_raise(rb_eArgError, "unknown axis name");
100
+ }
101
+ }
102
+ VALUE
103
+ kmm_mat_sort_destl(VALUE self, VALUE asym)
104
+ {
105
+ km_check_frozen(self);
106
+ VALUE foo=self;
107
+ SMAT *smat = km_mat2smat(self);
108
+ if ( smat->vtype != VT_COMPLEX ) {
109
+ if ( smat->stype == ST_RSUB ) {
110
+ foo = rb_obj_dup(self);
111
+ smat = km_mat2smat(foo);
112
+ }
113
+ } else {
114
+ foo = kmm_mat_to_omat(self);
115
+ smat = km_mat2smat(foo);
116
+ }
117
+ km_smat_sort(smat, asym);
118
+ if ( foo != self ) {
119
+ kmm_mat_copy_from(self, foo);
120
+ }
121
+ return self;
122
+ }
123
+ VALUE
124
+ kmm_mat_sort(VALUE self, VALUE asym)
125
+ {
126
+ SMAT *smat = km_mat2smat(self);
127
+ VALUE ret;
128
+ if ( smat->vtype != VT_COMPLEX ) {
129
+ ret = rb_obj_dup(self);
130
+ } else {
131
+ ret = kmm_mat_to_omat(self);
132
+ }
133
+ km_smat_sort(km_mat2smat(ret), asym);
134
+ if ( smat->vtype == VT_COMPLEX ) {
135
+ return kmm_mat_to_cmat(ret);
136
+ } else {
137
+ return ret;
138
+ }
139
+ }
140
+
141
+ // sort rows or columns by descending order
142
+ static int
143
+ km_int_rcomp(const void *a, const void *b)
144
+ {
145
+ return *(int *)b-*(int *)a;
146
+ }
147
+ static int
148
+ km_bool_rcomp(const void *a, const void *b)
149
+ {
150
+ if ( *(bool *)a ) {
151
+ if ( *(bool *)b ) {
152
+ return 0;
153
+ } else {
154
+ return -1;
155
+ }
156
+ } else {
157
+ if ( *(bool *)b ) {
158
+ return 1;
159
+ } else {
160
+ return 0;
161
+ }
162
+ }
163
+ }
164
+ static int
165
+ km_value_rcomp(const void *a, const void *b)
166
+ {
167
+ return NUM2INT(rb_funcall(*(VALUE *)b, id_op_comp, 1, *(VALUE *)a));
168
+ }
169
+ static void
170
+ km_rsort_seg(int size_seg, int ld, int num_seg, void *body, VTYPE vt)
171
+ {
172
+ if ( vt == VT_DOUBLE ) {
173
+ for ( int i=0; i<num_seg; i++ ) {
174
+ int info; char id[] = "D";
175
+ dlasrt_(id, &size_seg, ((double *)body)+(i*ld), &info);
176
+ }
177
+ } else if ( vt == VT_INT ) {
178
+ for ( int i=0; i<num_seg; i++ ) {
179
+ qsort(((int *)body)+(i*ld), int2size_t(size_seg), sizeof(int), km_int_rcomp);
180
+ }
181
+ } else if ( vt == VT_BOOL ) {
182
+ for ( int i=0; i<num_seg; i++ ) {
183
+ qsort(((bool *)body)+(i*ld), int2size_t(size_seg), sizeof(bool), km_bool_rcomp);
184
+ }
185
+ } else {
186
+ for ( int i=0; i<num_seg; i++ ) {
187
+ qsort(((VALUE *)body)+(i*ld), int2size_t(size_seg), sizeof(VALUE), km_value_rcomp);
188
+ }
189
+ }
190
+ }
191
+ #define rSKEWER(type) type *b = (type *)body; type *b2 = ZALLOC_N(type, size_sk*num_sk); \
192
+ for ( int i=0; i<size_sk; i++ ) { \
193
+ for ( int j=0; j<num_sk; j++ ) { \
194
+ b2[i+j*size_sk] = b[j+i*ld]; \
195
+ } \
196
+ } \
197
+ km_rsort_seg(size_sk, size_sk, num_sk, b2, vt); \
198
+ for ( int i=0; i<size_sk; i++ ) { \
199
+ for ( int j=0; j<num_sk; j++ ) { \
200
+ b[j+i*ld] = b2[i+j*size_sk]; \
201
+ } \
202
+ } \
203
+ ruby_xfree(b2)
204
+
205
+ static void
206
+ km_rsort_skewer(int size_sk, int ld, int num_sk, void *body, VTYPE vt)
207
+ {
208
+ if ( vt == VT_DOUBLE ) {
209
+ rSKEWER(double);
210
+ } else if ( vt == VT_INT ) {
211
+ rSKEWER(int);
212
+ } else {
213
+ rSKEWER(VALUE);
214
+ }
215
+ }
216
+ static void
217
+ km_smat_rsort(SMAT *smat, VALUE asym)
218
+ {
219
+ if ( rb_respond_to(asym, id_to_sym) ) {
220
+ asym = rb_funcall(asym, id_to_sym, 0);
221
+ }
222
+ if ( asym == sym_col || asym == sym_c || asym == sym_column ) {
223
+ if ( smat->trans ) {
224
+ km_rsort_skewer(smat->m, smat->ld, smat->n, smat->body, smat->vtype);
225
+ } else {
226
+ km_rsort_seg(smat->m, smat->ld, smat->n, smat->body, smat->vtype);
227
+ }
228
+ } else if ( asym == sym_row || asym == sym_r ) {
229
+ if ( smat->trans ) {
230
+ km_rsort_seg(smat->n, smat->ld, smat->m, smat->body, smat->vtype);
231
+ } else {
232
+ km_rsort_skewer(smat->n, smat->ld, smat->m, smat->body, smat->vtype);
233
+ }
234
+ } else if ( asym == sym_none || asym == sym_n ) {
235
+ return;
236
+ } else {
237
+ rb_raise(rb_eArgError, "unknown axis name");
238
+ }
239
+ }
240
+ VALUE
241
+ kmm_mat_rsort_destl(VALUE self, VALUE asym)
242
+ {
243
+ km_check_frozen(self);
244
+ VALUE foo=self;
245
+ SMAT *smat = km_mat2smat(self);
246
+ if ( smat->vtype != VT_COMPLEX ) {
247
+ if ( smat->stype == ST_RSUB ) {
248
+ foo = rb_obj_dup(self);
249
+ smat = km_mat2smat(foo);
250
+ }
251
+ } else {
252
+ foo = kmm_mat_to_omat(self);
253
+ smat = km_mat2smat(foo);
254
+ }
255
+ km_smat_rsort(smat, asym);
256
+ if ( foo != self ) {
257
+ kmm_mat_copy_from(self, foo);
258
+ }
259
+ return self;
260
+ }
261
+ VALUE
262
+ kmm_mat_rsort(VALUE self, VALUE asym)
263
+ {
264
+ SMAT *smat = km_mat2smat(self);
265
+ VALUE ret;
266
+ if ( smat->vtype != VT_COMPLEX ) {
267
+ ret = rb_obj_dup(self);
268
+ } else {
269
+ ret = kmm_mat_to_omat(self);
270
+ }
271
+ km_smat_rsort(km_mat2smat(ret), asym);
272
+ if ( smat->vtype == VT_COMPLEX ) {
273
+ return kmm_mat_to_cmat(ret);
274
+ } else if ( smat->vtype == VT_BOOL ) {
275
+ return kmm_mat_to_bmat(ret);
276
+ } else {
277
+ return ret;
278
+ }
279
+ }
280
+
281
+ // if `self' is a row vector, `self' is replaced by a vector which satisfy `A'[`p', `self'] is sorted row vector
282
+ // if `self' is a column vector, `self' is replaced by a vector which satisfy `A'[`self', `p'] is sorted column vector
283
+ static union {
284
+ double *d;
285
+ int *i;
286
+ bool *b;
287
+ VALUE *v;
288
+ } as_body;
289
+ static int as_step;
290
+ static int
291
+ as_dcomp(const void *a, const void *b)
292
+ {
293
+ return (int)copysign(1.0, as_body.d[(*(int *)a)*as_step]-as_body.d[(*(int *)b)*as_step]);
294
+ }
295
+ static int
296
+ as_icomp(const void *a, const void *b)
297
+ {
298
+ return as_body.i[(*(int *)a)*as_step] - as_body.i[(*(int *)b)*as_step];
299
+ }
300
+ static int
301
+ as_bcomp(const void *a, const void *b)
302
+ {
303
+ if ( as_body.b[(*(int *)a)*as_step] ) {
304
+ if ( as_body.b[(*(int *)b)*as_step] ) {
305
+ return 0;
306
+ } else {
307
+ return 1;
308
+ }
309
+ } else {
310
+ if ( as_body.b[(*(int *)b)*as_step] ) {
311
+ return -1;
312
+ } else {
313
+ return 0;
314
+ }
315
+ }
316
+ }
317
+ static int
318
+ as_vcomp(const void *a, const void *b)
319
+ {
320
+ return NUM2INT(rb_funcall(as_body.v[(*(int *)a)*as_step], id_op_comp, 1, as_body.v[(*(int *)b)*as_step]));
321
+ }
322
+ VALUE
323
+ kmm_mat_argsort_destl(VALUE self, VALUE va, VALUE vp)
324
+ {
325
+ km_check_frozen(self);
326
+ SMAT *si = km_mat2smat(self), *sa = km_mat2smat(va);
327
+ if ( si->vtype != VT_INT || si->stype != ST_FULL || !VECTOR_P(si) ) {
328
+ rb_raise(rb_eRuntimeError, "self must be an int full vector");
329
+ }
330
+ si->trans = false; si->ld = si->m; // this is available because si is a vector
331
+ int *idx = si->ibody, p=NUM2INT(vp), offset;
332
+ if ( si->m == sa->m && si->n == 1 ) {
333
+ if ( p < 0 || sa->n <= p ) { rb_raise(rb_eIndexError, "p is out of range"); }
334
+ for ( int i=0; i<si->m; i++ ) { idx[i] = i; }
335
+ if ( sa->trans ) {
336
+ offset = p; as_step = sa->ld;
337
+ } else {
338
+ offset = p*si->ld; as_step = 1;
339
+ }
340
+ } else if ( si->m == 1 && si->n == sa->n ) {
341
+ if ( p < 0 || sa->m <= p ) { rb_raise(rb_eIndexError, "p is out of range"); }
342
+ for ( int i=0; i<si->n; i++ ) { idx[i] = i; }
343
+ if ( sa->trans ) {
344
+ offset = p*si->ld; as_step = 1;
345
+ } else {
346
+ offset = p; as_step = sa->ld;
347
+ }
348
+ } else {
349
+ rb_raise(km_eDim, "dimension mismatched");
350
+ }
351
+ if ( sa->vtype == VT_DOUBLE ) {
352
+ as_body.d = sa->dbody; as_body.d += offset;
353
+ qsort(idx, LENGTHs(si), sizeof(int), as_dcomp);
354
+ } else if ( sa->vtype == VT_INT ) {
355
+ as_body.i = sa->ibody; as_body.i += offset;
356
+ qsort(idx, LENGTHs(si), sizeof(int), as_icomp);
357
+ } else if ( sa->vtype == VT_BOOL ) {
358
+ as_body.b = sa->bbody; as_body.b += offset;
359
+ qsort(idx, LENGTHs(si), sizeof(int), as_bcomp);
360
+ } else if ( sa->vtype == VT_VALUE ) {
361
+ as_body.v = sa->vbody; as_body.v += offset;
362
+ qsort(idx, LENGTHs(si), sizeof(int), as_vcomp);
363
+ } else {
364
+ SMAT *sa2 = km_mat2smat(kmm_mat_to_omat(va));
365
+ as_body.v = sa2->vbody; as_body.v += offset;
366
+ qsort(idx, LENGTHs(si), sizeof(int), as_vcomp);
367
+ }
368
+ return self;
369
+ }
370
+ // select column-sort or row-sort by the argument Symbol
371
+ // the argument can be omitted only if `self' is a vector
372
+ VALUE
373
+ kmm_mat_argsort(int argc, VALUE *argv, VALUE va)
374
+ {
375
+ rb_check_arity(argc, 0, 2);
376
+ if ( argc == 0 ) {
377
+ SMAT *sa = km_mat2smat(va);
378
+ if ( sa->n == 1 ) {
379
+ return kmm_mat_argsort_destl(km_Mat(sa->m, 1, VT_INT), va, INT2NUM(0));
380
+ } else if ( sa->m == 1 ) {
381
+ return kmm_mat_argsort_destl(km_Mat(1, sa->n, VT_INT), va, INT2NUM(0));
382
+ } else {
383
+ rb_raise(rb_eArgError, "argsort without arguments is available only for vectors");
384
+ }
385
+ } else if ( argc == 2 ) {
386
+ VALUE asym = argv[0];
387
+ if ( rb_respond_to(asym, id_to_sym) ) {
388
+ asym = rb_funcall(asym, id_to_sym, 0);
389
+ }
390
+ SMAT *sa = km_mat2smat(va);
391
+ if ( asym == sym_col || asym == sym_c || asym == sym_column ) {
392
+ return kmm_mat_argsort_destl(km_Mat(sa->m, 1, VT_INT), va, argv[1]);
393
+ } else if ( asym == sym_row || asym == sym_c ) {
394
+ return kmm_mat_argsort_destl(km_Mat(1, sa->n, VT_INT), va, argv[1]);
395
+ } else {
396
+ rb_raise(rb_eArgError, "unknown axis name");
397
+ }
398
+ } else {
399
+ rb_raise(rb_eArgError, "argsort with 1 argument is not available");
400
+ }
401
+ }
402
+
403
+ // reversed argsort
404
+ static int
405
+ ras_dcomp(const void *a, const void *b)
406
+ {
407
+ return (int)copysign(1.0, as_body.d[(*(int *)a)*as_step]-as_body.d[(*(int *)b)*as_step]);
408
+ }
409
+ static int
410
+ ras_icomp(const void *a, const void *b)
411
+ {
412
+ return as_body.i[(*(int *)a)*as_step] - as_body.i[(*(int *)b)*as_step];
413
+ }
414
+ static int
415
+ ras_bcomp(const void *a, const void *b)
416
+ {
417
+ if ( as_body.b[(*(int *)a)*as_step] ) {
418
+ if ( as_body.b[(*(int *)b)*as_step] ) {
419
+ return 0;
420
+ } else {
421
+ return -1;
422
+ }
423
+ } else {
424
+ if ( as_body.b[(*(int *)b)*as_step] ) {
425
+ return 1;
426
+ } else {
427
+ return 0;
428
+ }
429
+ }
430
+ }
431
+ static int
432
+ ras_vcomp(const void *a, const void *b)
433
+ {
434
+ return NUM2INT(rb_funcall(as_body.v[(*(int *)a)*as_step], id_op_comp, 1, as_body.v[(*(int *)b)*as_step]));
435
+ }
436
+ VALUE
437
+ kmm_mat_rargsort_destl(VALUE self, VALUE va, VALUE vp)
438
+ {
439
+ km_check_frozen(self);
440
+ SMAT *si = km_mat2smat(self), *sa = km_mat2smat(va);
441
+ if ( si->vtype != VT_INT || si->stype != ST_FULL || !VECTOR_P(si) ) {
442
+ rb_raise(rb_eRuntimeError, "self must be an int full vector");
443
+ }
444
+ si->trans = false; si->ld = si->m; // this is available because si is a vector
445
+ int *idx = si->ibody, p=NUM2INT(vp), offset;
446
+ if ( si->m == sa->m && si->n == 1 ) {
447
+ if ( p < 0 || sa->n <= p ) { rb_raise(rb_eIndexError, "p is out of range"); }
448
+ for ( int i=0; i<si->m; i++ ) { idx[i] = i; }
449
+ if ( sa->trans ) {
450
+ offset = p; as_step = sa->ld;
451
+ } else {
452
+ offset = p*si->ld; as_step = 1;
453
+ }
454
+ } else if ( si->m == 1 && si->n == sa->n ) {
455
+ if ( p < 0 || sa->m <= p ) { rb_raise(rb_eIndexError, "p is out of range"); }
456
+ for ( int i=0; i<si->n; i++ ) { idx[i] = i; }
457
+ if ( sa->trans ) {
458
+ offset = p*si->ld; as_step = 1;
459
+ } else {
460
+ offset = p; as_step = sa->ld;
461
+ }
462
+ } else {
463
+ rb_raise(km_eDim, "dimension mismatched");
464
+ }
465
+ if ( sa->vtype == VT_DOUBLE ) {
466
+ as_body.d = sa->dbody; as_body.d += offset;
467
+ qsort(idx, LENGTHs(si), sizeof(int), ras_dcomp);
468
+ } else if ( sa->vtype == VT_INT ) {
469
+ as_body.i = sa->ibody; as_body.i += offset;
470
+ qsort(idx, LENGTHs(si), sizeof(int), ras_icomp);
471
+ } else if ( sa->vtype == VT_BOOL ) {
472
+ as_body.b = sa->bbody; as_body.b += offset;
473
+ qsort(idx, LENGTHs(si), sizeof(int), ras_bcomp);
474
+ } else if ( sa->vtype == VT_VALUE ) {
475
+ as_body.v = sa->vbody; as_body.v += offset;
476
+ qsort(idx, LENGTHs(si), sizeof(int), ras_vcomp);
477
+ } else {
478
+ SMAT *sa2 = km_mat2smat(kmm_mat_to_omat(va));
479
+ as_body.v = sa2->vbody; as_body.v += offset;
480
+ qsort(idx, LENGTHs(si), sizeof(int), ras_vcomp);
481
+ }
482
+ return self;
483
+ }
484
+ VALUE
485
+ kmm_mat_rargsort(int argc, VALUE *argv, VALUE va)
486
+ {
487
+ rb_check_arity(argc, 0, 2);
488
+ if ( argc == 0 ) {
489
+ SMAT *sa = km_mat2smat(va);
490
+ if ( sa->n == 1 ) {
491
+ return kmm_mat_rargsort_destl(km_Mat(sa->m, 1, VT_INT), va, INT2NUM(0));
492
+ } else if ( sa->m == 1 ) {
493
+ return kmm_mat_rargsort_destl(km_Mat(1, sa->n, VT_INT), va, INT2NUM(0));
494
+ } else {
495
+ rb_raise(rb_eArgError, "argsort without arguments is available only for vectors");
496
+ }
497
+ } else if ( argc == 2 ) {
498
+ VALUE asym = argv[0];
499
+ if ( rb_respond_to(asym, id_to_sym) ) {
500
+ asym = rb_funcall(asym, id_to_sym, 0);
501
+ }
502
+ SMAT *sa = km_mat2smat(va);
503
+ if ( asym == sym_col || asym == sym_c || asym == sym_column ) {
504
+ return kmm_mat_rargsort_destl(km_Mat(sa->m, 1, VT_INT), va, argv[1]);
505
+ } else if ( asym == sym_row || asym == sym_c ) {
506
+ return kmm_mat_rargsort_destl(km_Mat(1, sa->n, VT_INT), va, argv[1]);
507
+ } else {
508
+ rb_raise(rb_eArgError, "unknown axis name");
509
+ }
510
+ } else {
511
+ rb_raise(rb_eArgError, "argsort with 1 argument is not available");
512
+ }
513
+ }
514
+
515
+ // store the maximum/minimum elements of `self' to the argument
516
+ // the axis is selcted by the shape of the argument
517
+ // if the argument is (1, 1)-matrix, return argument[0, 0]
518
+ // otherwise return the argument
519
+ static void
520
+ km_max_func_d(double *ea, void *data)
521
+ {
522
+ double *r = (double *)data;
523
+ if ( *r < *ea ) { *r = *ea; }
524
+ }
525
+ static void
526
+ km_max_func_i(int *ea, void *data)
527
+ {
528
+ int *r = (int *)data;
529
+ if ( *r < *ea ) { *r = *ea; }
530
+ }
531
+ static void
532
+ km_max_func_b(bool *ea, void *data)
533
+ {
534
+ bool *r = (bool *)data;
535
+ if ( *ea ) { *r = true; }
536
+ }
537
+ static void
538
+ km_max_func_v(VALUE *ea, void *data)
539
+ {
540
+ VALUE *r = (VALUE *)data;
541
+ if ( RTEST(rb_funcall(*r, id_op_lt, 1, *ea)) ) {
542
+ *r = *ea;
543
+ }
544
+ }
545
+ static void
546
+ km_min_func_d(double *ea, void *data)
547
+ {
548
+ double *r = (double *)data;
549
+ if ( *r > *ea ) { *r = *ea; }
550
+ }
551
+ static void
552
+ km_min_func_i(int *ea, void *data)
553
+ {
554
+ int *r = (int *)data;
555
+ if ( *r > *ea ) { *r = *ea; }
556
+ }
557
+ static void
558
+ km_min_func_b(bool *ea, void *data)
559
+ {
560
+ bool *r = (bool *)data;
561
+ if ( !*ea ) { *r = false; }
562
+ }
563
+ static void
564
+ km_min_func_v(VALUE *ea, void *data)
565
+ {
566
+ VALUE *r = (VALUE *)data;
567
+ if ( RTEST(rb_funcall(*r, id_op_gt, 1, *ea)) ) {
568
+ *r = *ea;
569
+ }
570
+ }
571
+ #define DEFINE_MM(mm, op, op_id, opb) \
572
+ static VALUE \
573
+ km_mat_##mm##_all(SMAT *sr, SMAT *sa, VALUE va) \
574
+ { \
575
+ if ( sr->vtype == VT_DOUBLE ) { \
576
+ sr->dbody[0] = sa->dbody[0]; \
577
+ km_smat_each_d(sa, km_##mm##_func_d, sr->body); \
578
+ return rb_float_new(sr->dbody[0]); \
579
+ } else if ( sr->vtype == VT_INT ) { \
580
+ sr->ibody[0] = sa->ibody[0]; \
581
+ km_smat_each_i(sa, km_##mm##_func_i, sr->body); \
582
+ return INT2NUM(sr->ibody[0]); \
583
+ } else if ( sr->vtype == VT_BOOL ) { \
584
+ sr->bbody[0] = sa->bbody[0]; \
585
+ km_smat_each_b(sa, km_##mm##_func_b, sr->body); \
586
+ return TF2V(sr->bbody[0]); \
587
+ } else if ( sr->vtype == VT_VALUE ) { \
588
+ sr->vbody[0] = sa->vbody[0]; \
589
+ km_smat_each_v(sa, km_##mm##_func_v, sr->body); \
590
+ return sr->vbody[0]; \
591
+ } else { \
592
+ sa = km_mat2smat(kmm_mat_to_omat(va)); \
593
+ VALUE ret=sa->vbody[0]; \
594
+ km_smat_each_v(sa, km_##mm##_func_v, &ret); \
595
+ if ( sr->vtype == VT_COMPLEX ) { \
596
+ sr->zbody[0] = km_v2c(ret); \
597
+ } else { \
598
+ rb_raise(km_eInternal, "unexpected reach"); \
599
+ } \
600
+ return ret; \
601
+ } \
602
+ } \
603
+ static VALUE \
604
+ km_mat_##mm##_col(VALUE self, SMAT *sr, SMAT *sa, VALUE va) \
605
+ { \
606
+ if ( sr->vtype == VT_DOUBLE ) { \
607
+ for ( int j=0; j<sr->n; j++ ) { \
608
+ sr->dbody[j] = ENTITY(sa, d, 0, j); \
609
+ for ( int i=1; i<sa->m; i++ ) { \
610
+ double tmp = ENTITY(sa, d, i, j); \
611
+ if ( sr->dbody[j] op tmp ) { \
612
+ sr->dbody[j] = tmp; \
613
+ } \
614
+ } \
615
+ } \
616
+ } else if ( sr->vtype == VT_INT ) { \
617
+ for ( int j=0; j<sr->n; j++ ) { \
618
+ sr->ibody[j] = ENTITY(sa, i, 0, j); \
619
+ for ( int i=1; i<sa->m; i++ ) { \
620
+ int tmp = ENTITY(sa, i, i, j); \
621
+ if ( sr->ibody[j] op tmp ) { \
622
+ sr->ibody[j] = tmp; \
623
+ } \
624
+ } \
625
+ } \
626
+ } else if ( sr->vtype == VT_BOOL ) { \
627
+ for ( int j=0; j<sr->n; j++ ) { \
628
+ sr->bbody[j] = ENTITY(sa, b, 0, j); \
629
+ if ( !(opb sr->bbody[j]) ) { \
630
+ for ( int i=1; i<sa->m; i++ ) { \
631
+ bool tmp = ENTITY(sa, b, i, j); \
632
+ if ( opb tmp ) { \
633
+ sr->bbody[j] = tmp; \
634
+ } \
635
+ } \
636
+ } \
637
+ } \
638
+ } else if ( sr->vtype == VT_VALUE ) { \
639
+ for ( int j=0; j<sr->n; j++ ) { \
640
+ sr->vbody[j] = ENTITY(sa, v, 0, j); \
641
+ for ( int i=1; i<sa->m; i++ ) { \
642
+ VALUE tmp = ENTITY(sa, v, i, j); \
643
+ if ( RTEST(rb_funcall(sr->vbody[j], op_id, 1, tmp)) ) { \
644
+ sr->vbody[j] = tmp; \
645
+ } \
646
+ } \
647
+ } \
648
+ } else { \
649
+ VALUE tmp = kmm_mat_##mm##_destl(km_Mat(1, sr->n, VT_VALUE), kmm_mat_to_omat(va)); \
650
+ if ( sr->vtype == VT_COMPLEX ) { \
651
+ return kmm_mat_copy_from(self, kmm_mat_to_cmat(tmp)); \
652
+ } else { \
653
+ rb_raise(km_eInternal, "unexpected reach"); \
654
+ } \
655
+ } \
656
+ return self; \
657
+ } \
658
+ static VALUE \
659
+ km_mat_##mm##_row(VALUE self, SMAT *sr, SMAT *sa, VALUE va) \
660
+ { \
661
+ if ( sr->vtype == VT_DOUBLE ) { \
662
+ for ( int i=0; i<sr->m; i++ ) { \
663
+ sr->dbody[i] = ENTITY(sa, d, i, 0); \
664
+ for ( int j=1; j<sa->n; j++ ) { \
665
+ double tmp = ENTITY(sa, d, i, j); \
666
+ if ( sr->dbody[i] op tmp ) { \
667
+ sr->dbody[i] = tmp; \
668
+ } \
669
+ } \
670
+ } \
671
+ } else if ( sr->vtype == VT_INT ) { \
672
+ for ( int i=0; i<sr->m; i++ ) { \
673
+ sr->ibody[i] = ENTITY(sa, i, i, 0); \
674
+ for ( int j=1; j<sa->n; j++ ) { \
675
+ int tmp = ENTITY(sa, i, i, j); \
676
+ if ( sr->ibody[i] op tmp ) { \
677
+ sr->ibody[i] = tmp; \
678
+ } \
679
+ } \
680
+ } \
681
+ } else if ( sr->vtype == VT_BOOL ) { \
682
+ for ( int i=0; i<sr->m; i++ ) { \
683
+ sr->bbody[i] = ENTITY(sa, b, i, 0); \
684
+ if ( !(opb sr->bbody[i]) ) { \
685
+ for ( int j=0; j<sa->n; j++ ) { \
686
+ bool tmp = ENTITY(sa, b, i, j); \
687
+ if ( opb tmp ) { \
688
+ sr->bbody[i] = tmp; \
689
+ } \
690
+ } \
691
+ } \
692
+ } \
693
+ } else if ( sr->vtype == VT_VALUE ) { \
694
+ for ( int i=0; i<sr->m; i++ ) { \
695
+ sr->vbody[i] = ENTITY(sa, v, i, 0); \
696
+ for ( int j=1; j<sa->n; j++ ) { \
697
+ VALUE tmp = ENTITY(sa, v, i, j); \
698
+ if ( RTEST(rb_funcall(sr->vbody[i], op_id, 1, tmp)) ) { \
699
+ sr->vbody[i] = tmp; \
700
+ } \
701
+ } \
702
+ } \
703
+ } else { \
704
+ VALUE tmp = kmm_mat_##mm##_destl(km_Mat(sr->m, 1, VT_VALUE), kmm_mat_to_omat(va)); \
705
+ if ( sr->vtype == VT_COMPLEX ) { \
706
+ return kmm_mat_copy_from(self, kmm_mat_to_cmat(tmp)); \
707
+ } else { \
708
+ rb_raise(km_eInternal, "unexpected reach"); \
709
+ } \
710
+ } \
711
+ return self; \
712
+ }
713
+ DEFINE_MM(max, <, id_op_lt, )
714
+ DEFINE_MM(min, <, id_op_gt, !)
715
+ VALUE
716
+ kmm_mat_max_destl(VALUE self, VALUE vr)
717
+ {
718
+ km_check_frozen(self);
719
+ SMAT *sr = km_mat2smat(vr), *sa = km_mat2smat(self);
720
+ if ( sr->vtype != sa->vtype ) { rb_raise(km_eVT, "value types must be the same"); }
721
+ if ( sr->stype != ST_FULL ) { rb_raise(km_eShare, "self must be full matrix"); }
722
+ if ( sr->trans ) {
723
+ if ( kmm_mat_have_submatrix_p(vr) ) {
724
+ VALUE mm = kmm_mat_max_destl(self, rb_obj_dup(vr));
725
+ if ( sr->m == 1 && sr->n == 1 ) {
726
+ kmm_mat_set_value(vr, INT2NUM(0), INT2NUM(0), mm);
727
+ return mm;
728
+ } else {
729
+ kmm_mat_copy_from(vr, mm);
730
+ return vr;
731
+ }
732
+ } else {
733
+ sr->trans = false; sr->ld = sr->m; // this is available because the contents of sr are ignored
734
+ }
735
+ }
736
+ if ( sr->m == 1 && sr->n == 1 ) {
737
+ return km_mat_max_all(sr, sa, self);
738
+ } else if ( sr->m==1 && sr->n==sa->n ) {
739
+ return km_mat_max_col(vr, sr, sa, self);
740
+ } else if ( sr->m==sa->m && sr->n==1 ) {
741
+ return km_mat_max_row(vr, sr, sa, self);
742
+ } else if ( SAME_SIZE(sr, sa) ) {
743
+ km_smat_copy(sr, sa);
744
+ return self;
745
+ } else {
746
+ rb_raise(km_eDim, "max/min from size (%d, %d) to size (%d, %d) is not defined", sa->m, sa->n, sr->m, sr->n);
747
+ }
748
+ }
749
+ // the argument is a Symbol which specify the axis
750
+ // if the argument is :col take a max in column axis and return row vector
751
+ // if the argument is :row take a max in row axis and return column vector
752
+ // if the argument is :all or omitted, take a max of all the elements
753
+ VALUE
754
+ kmm_mat_max(int argc, VALUE *argv, VALUE self)
755
+ {
756
+ rb_check_arity(argc, 0, 1);
757
+ if ( argc == 0 ) {
758
+ return kmm_mat_max_destl(self, km_Mat(1, 1, km_mat2smat(self)->vtype));
759
+ } else {
760
+ VALUE asym = argv[0];
761
+ if ( rb_respond_to(asym, id_to_sym) ) {
762
+ asym = rb_funcall(asym, id_to_sym, 0);
763
+ }
764
+ SMAT *sa = km_mat2smat(self);
765
+ if ( asym == sym_col || asym == sym_c ) {
766
+ return kmm_mat_max_destl(self, km_Mat(1, sa->n, sa->vtype));
767
+ } else if ( asym == sym_row || asym == sym_r ) {
768
+ return kmm_mat_max_destl(self, km_Mat(sa->m, 1, sa->vtype));
769
+ } else if ( asym == sym_all || asym == sym_a ) {
770
+ return kmm_mat_max_destl(self, km_Mat(1, 1, sa->vtype));
771
+ } else if ( asym == sym_none || asym == sym_n ) {
772
+ return kmm_mat_max_destl(self, km_Mat(sa->m, sa->n, sa->vtype));
773
+ } else {
774
+ rb_raise(rb_eArgError, "unknown axis name");
775
+ }
776
+ }
777
+ }
778
+
779
+ VALUE
780
+ kmm_mat_min_destl(VALUE self, VALUE vr)
781
+ {
782
+ km_check_frozen(self);
783
+ SMAT *sr = km_mat2smat(vr), *sa = km_mat2smat(self);
784
+ if ( sr->vtype != sa->vtype ) { rb_raise(km_eVT, "value types must be the same"); }
785
+ if ( sr->stype != ST_FULL ) { rb_raise(km_eShare, "self must be full matrix"); }
786
+ if ( sr->trans ) {
787
+ if ( kmm_mat_have_submatrix_p(vr) ) {
788
+ VALUE mm = kmm_mat_min_destl(self, rb_obj_dup(vr));
789
+ if ( sr->m == 1 && sr->n == 1 ) {
790
+ kmm_mat_set_value(vr, INT2NUM(0), INT2NUM(0), mm);
791
+ return mm;
792
+ } else {
793
+ kmm_mat_copy_from(vr, mm);
794
+ return vr;
795
+ }
796
+ } else {
797
+ sr->trans = false; sr->ld = sr->m; // this is available because the contents of sr are ignored
798
+ }
799
+ }
800
+ if ( sr->m == 1 && sr->n == 1 ) {
801
+ return km_mat_min_all(sr, sa, self);
802
+ } else if ( sr->m==1 && sr->n==sa->n ) {
803
+ return km_mat_min_col(vr, sr, sa, self);
804
+ } else if ( sr->m==sa->m && sr->n==1 ) {
805
+ return km_mat_min_row(vr, sr, sa, self);
806
+ } else if ( SAME_SIZE(sr, sa) ) {
807
+ km_smat_copy(sr, sa);
808
+ return self;
809
+ } else {
810
+ rb_raise(km_eDim, "max/min from size (%d, %d) to size (%d, %d) is not defined", sa->m, sa->n, sr->m, sr->n);
811
+ }
812
+ }
813
+ VALUE
814
+ kmm_mat_min(int argc, VALUE *argv, VALUE self)
815
+ {
816
+ rb_check_arity(argc, 0, 1);
817
+ if ( argc == 0 ) {
818
+ return kmm_mat_min_destl(self, km_Mat(1, 1, km_mat2smat(self)->vtype));
819
+ } else {
820
+ VALUE asym = argv[0];
821
+ if ( rb_respond_to(asym, id_to_sym) ) {
822
+ asym = rb_funcall(asym, id_to_sym, 0);
823
+ }
824
+ SMAT *sa = km_mat2smat(self);
825
+ if ( asym == sym_col || asym == sym_c ) {
826
+ return kmm_mat_min_destl(self, km_Mat(1, sa->n, sa->vtype));
827
+ } else if ( asym == sym_row || asym == sym_r ) {
828
+ return kmm_mat_min_destl(self, km_Mat(sa->m, 1, sa->vtype));
829
+ } else if ( asym == sym_all || asym == sym_a ) {
830
+ return kmm_mat_min_destl(self, km_Mat(1, 1, sa->vtype));
831
+ } else if ( asym == sym_none || asym == sym_n ) {
832
+ return kmm_mat_min_destl(self, km_Mat(sa->m, sa->n, sa->vtype));
833
+ } else {
834
+ rb_raise(rb_eArgError, "unknown axis name");
835
+ }
836
+ }
837
+ }
838
+
839
+ struct km_amm_arg {
840
+ int i;
841
+ int j;
842
+ union {
843
+ double dmm;
844
+ int imm;
845
+ bool bmm;
846
+ VALUE vmm;
847
+ };
848
+ };
849
+ static void
850
+ km_argmax_func_d(double *ea, int i, int j, void *data)
851
+ {
852
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
853
+ if ( arg->dmm < *ea ) {
854
+ arg->i = i; arg->j = j; arg->dmm = *ea;
855
+ }
856
+ }
857
+ static void
858
+ km_argmax_func_i(int *ea, int i, int j, void *data)
859
+ {
860
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
861
+ if ( arg->imm < *ea ) {
862
+ arg->i = i; arg->j = j; arg->imm = *ea;
863
+ }
864
+ }
865
+ static void
866
+ km_argmax_func_b(bool *ea, int i, int j, void *data)
867
+ {
868
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
869
+ if ( (!(arg->bmm)) && *ea ) {
870
+ arg->i = i; arg->j = j; arg->bmm = true;
871
+ }
872
+ }
873
+ static void
874
+ km_argmax_func_v(VALUE *ea, int i, int j, void *data)
875
+ {
876
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
877
+ if ( RTEST(rb_funcall(arg->vmm, id_op_lt, 1, *ea)) ) {
878
+ arg->i = i; arg->j = j; arg->vmm = *ea;
879
+ }
880
+ }
881
+ #define DEFINE_AMM(mm, op, op_id, opb) \
882
+ static VALUE \
883
+ km_mat_arg##mm##_all(SMAT *sr, SMAT *sa, VALUE va) \
884
+ { \
885
+ if ( sa->vtype == VT_DOUBLE ) { \
886
+ struct km_amm_arg data = {0, 0, {.dmm = sa->dbody[0]}}; \
887
+ km_smat_each_with_index_d(sa, km_arg##mm##_func_d, &data); \
888
+ sr->ibody[0] = INDEX(sa, data.i, data.j); \
889
+ if ( VECTOR_P(sa) ) { \
890
+ return INT2NUM(MAX(data.i, data.j)); \
891
+ } else { \
892
+ return rb_ary_new3(2, INT2NUM(data.i), INT2NUM(data.j)); \
893
+ } \
894
+ } else if ( sa->vtype == VT_INT ) { \
895
+ struct km_amm_arg data = {0, 0, {.imm = sa->ibody[0]}}; \
896
+ km_smat_each_with_index_i(sa, km_arg##mm##_func_i, &data); \
897
+ sr->ibody[0] = INDEX(sa, data.i, data.j); \
898
+ if ( VECTOR_P(sa) ) { \
899
+ return INT2NUM(MAX(data.i, data.j)); \
900
+ } else { \
901
+ return rb_ary_new3(2, INT2NUM(data.i), INT2NUM(data.j)); \
902
+ } \
903
+ } else if ( sa->vtype == VT_BOOL ) { \
904
+ struct km_amm_arg data = {0, 0, {.bmm = sa->bbody[0]}}; \
905
+ km_smat_each_with_index_b(sa, km_arg##mm##_func_b, &data); \
906
+ sr->ibody[0] = INDEX(sa, data.i, data.j); \
907
+ if ( VECTOR_P(sa) ) { \
908
+ return INT2NUM(MAX(data.i, data.j)); \
909
+ } else { \
910
+ return rb_ary_new3(2, INT2NUM(data.i), INT2NUM(data.j)); \
911
+ } \
912
+ } else if ( sa->vtype == VT_VALUE ) { \
913
+ struct km_amm_arg data = {0, 0, {.vmm = sa->vbody[0]}}; \
914
+ km_smat_each_with_index_v(sa, km_arg##mm##_func_v, &data); \
915
+ sr->ibody[0] = INDEX(sa, data.i, data.j); \
916
+ if ( VECTOR_P(sa) ) { \
917
+ return INT2NUM(MAX(data.i, data.j)); \
918
+ } else { \
919
+ return rb_ary_new3(2, INT2NUM(data.i), INT2NUM(data.j)); \
920
+ } \
921
+ } else { \
922
+ VALUE omat = kmm_mat_to_omat(va); \
923
+ return km_mat_arg##mm##_all(sr, km_mat2smat(omat), omat); \
924
+ } \
925
+ } \
926
+ static VALUE \
927
+ km_mat_arg##mm##_col(VALUE self, SMAT *sr, SMAT *sa, VALUE va) \
928
+ { \
929
+ if ( sa->vtype == VT_DOUBLE ) { \
930
+ for ( int j=0; j<sr->n; j++ ) { \
931
+ sr->ibody[j] = 0; double mm = ENTITY(sa, d, 0, j); \
932
+ for ( int i=0; i<sa->m; i++ ) { \
933
+ double tmp = ENTITY(sa, d, i, j); \
934
+ if ( mm op tmp ) { \
935
+ sr->ibody[j] = i; mm = tmp; \
936
+ } \
937
+ } \
938
+ } \
939
+ } else if ( sa->vtype == VT_INT ) { \
940
+ for ( int j=0; j<sr->n; j++ ) { \
941
+ sr->ibody[j] = 0; int mm = ENTITY(sa, i, 0, j); \
942
+ for ( int i=0; i<sa->m; i++ ) { \
943
+ int tmp = ENTITY(sa, i, i, j); \
944
+ if ( mm op tmp ) { \
945
+ sr->ibody[j] = i; mm = tmp; \
946
+ } \
947
+ } \
948
+ } \
949
+ } else if ( sa->vtype == VT_BOOL ) { \
950
+ for ( int j=0; j<sr->n; j++ ) { \
951
+ sr->ibody[j] = 0; bool mm = ENTITY(sa, b, 0, j); \
952
+ if ( !( opb mm ) ) { \
953
+ for ( int i=0; i<sa->m; i++ ) { \
954
+ int tmp = ENTITY(sa, b, i, j); \
955
+ if ( opb tmp ) { \
956
+ sr->bbody[j] = i; break; \
957
+ } \
958
+ } \
959
+ } \
960
+ } \
961
+ } else if ( sa->vtype == VT_VALUE ) { \
962
+ for ( int j=0; j<sr->n; j++ ) { \
963
+ sr->ibody[j] = 0; VALUE mm = ENTITY(sa, v, 0, j); \
964
+ for ( int i=0; i<sa->m; i++ ) { \
965
+ VALUE tmp = ENTITY(sa, v, i, j); \
966
+ if ( rb_funcall(mm, op_id, 1, tmp) ) { \
967
+ sr->ibody[j] = i; mm = tmp; \
968
+ } \
969
+ } \
970
+ } \
971
+ } else { \
972
+ VALUE omat = kmm_mat_to_omat(va); \
973
+ return km_mat_arg##mm##_col(self, sr, km_mat2smat(omat), omat); \
974
+ } \
975
+ return self; \
976
+ } \
977
+ static VALUE \
978
+ km_mat_arg##mm##_row(VALUE self, SMAT *sr, SMAT *sa, VALUE va) \
979
+ { \
980
+ if ( sa->vtype == VT_DOUBLE ) { \
981
+ for ( int i=0; i<sr->m; i++ ) { \
982
+ sr->ibody[i] = 0; double mm = ENTITY(sa, d, i, 0); \
983
+ for ( int j=1; j<sa->n; j++ ) { \
984
+ double tmp = ENTITY(sa, d, i, j); \
985
+ if ( mm op tmp ) { \
986
+ sr->ibody[i] = j; mm = tmp; \
987
+ } \
988
+ } \
989
+ } \
990
+ } else if ( sa->vtype == VT_INT ) { \
991
+ for ( int i=0; i<sr->m; i++ ) { \
992
+ sr->ibody[i] = 0; int mm = ENTITY(sa, i, i, 0); \
993
+ for ( int j=1; j<sa->n; j++ ) { \
994
+ int tmp = ENTITY(sa, i, i, j); \
995
+ if ( mm op tmp ) { \
996
+ sr->ibody[i] = j; mm = tmp; \
997
+ } \
998
+ } \
999
+ } \
1000
+ } else if ( sa->vtype == VT_BOOL ) { \
1001
+ for ( int i=0; i<sr->m; i++ ) { \
1002
+ sr->ibody[i] = 0; int mm = ENTITY(sa, b, i, 0); \
1003
+ if ( ! (opb mm) ) { \
1004
+ for ( int j=1; j<sa->n; j++ ) { \
1005
+ int tmp = ENTITY(sa, i, i, j); \
1006
+ if ( opb tmp ) { \
1007
+ sr->ibody[i] = j; break; \
1008
+ } \
1009
+ } \
1010
+ } \
1011
+ } \
1012
+ } else if ( sa->vtype == VT_VALUE ) { \
1013
+ for ( int i=0; i<sr->m; i++ ) { \
1014
+ sr->ibody[i] = 0; VALUE mm = ENTITY(sa, v, i, 0); \
1015
+ for ( int j=1; j<sa->n; j++ ) { \
1016
+ VALUE tmp = ENTITY(sa, v, i, j); \
1017
+ if ( rb_funcall(mm, op_id, 1, tmp) ) { \
1018
+ sr->ibody[i] = j; mm = tmp; \
1019
+ } \
1020
+ } \
1021
+ } \
1022
+ } else { \
1023
+ VALUE omat = kmm_mat_to_omat(va); \
1024
+ return km_mat_arg##mm##_row(self, sr, km_mat2smat(omat), omat); \
1025
+ } \
1026
+ return self; \
1027
+ }
1028
+ DEFINE_AMM(max, <, id_op_lt, )
1029
+ VALUE
1030
+ kmm_mat_argmax_destl(VALUE self, VALUE va)
1031
+ {
1032
+ km_check_frozen(self); SMAT *sr = km_mat2smat(self), *sa = km_mat2smat(va);
1033
+ if ( sr->vtype != VT_INT || sr->stype != ST_FULL ) {
1034
+ rb_raise(rb_eRuntimeError, "self must be an int full matrix");
1035
+ }
1036
+ if ( sr->trans ) {
1037
+ if ( kmm_mat_have_submatrix_p(self) ) {
1038
+ return kmm_mat_copy_from(self, kmm_mat_argmax_destl(rb_obj_dup(self), va));
1039
+ } else {
1040
+ sr->trans = false; sr->ld = sr->m;
1041
+ }
1042
+ }
1043
+ if ( sr->m == 1 && sr->n == 1 ) {
1044
+ return km_mat_argmax_all(sr, sa, va);
1045
+ } else if ( sr->m == 1 && sr->n == sa->n ) {
1046
+ return km_mat_argmax_col(self, sr, sa, va);
1047
+ } else if ( sr->m == sa->m && sr->n == 1 ) {
1048
+ return km_mat_argmax_row(self, sr, sa, va);
1049
+ } else {
1050
+ rb_raise(km_eDim, "argmax/min from size (%d, %d) to size (%d, %d) is not defined", sa->m, sa->n, sr->m, sr->n);
1051
+ }
1052
+ }
1053
+ VALUE
1054
+ kmm_mat_argmax(int argc, VALUE *argv, VALUE va)
1055
+ {
1056
+ rb_check_arity(argc, 0, 1);
1057
+ if ( argc == 0 ) {
1058
+ return kmm_mat_argmax_destl(km_Mat(1, 1, VT_INT), va);
1059
+ } else {
1060
+ VALUE asym = argv[0];
1061
+ if ( rb_respond_to(asym, id_to_sym) ) {
1062
+ asym = rb_funcall(asym, id_to_sym, 0);
1063
+ }
1064
+ SMAT *sa = km_mat2smat(va);
1065
+ if ( asym == sym_col || asym == sym_c ) {
1066
+ return kmm_mat_argmax_destl(km_Mat(1, sa->n, VT_INT), va);
1067
+ } else if ( asym == sym_row || asym == sym_r ) {
1068
+ return kmm_mat_argmax_destl(km_Mat(sa->m, 1, VT_INT), va);
1069
+ } else if ( asym == sym_all || asym == sym_a ) {
1070
+ return kmm_mat_argmax_destl(km_Mat(1, 1, VT_INT), va);
1071
+ } else {
1072
+ rb_raise(rb_eArgError, "unknown axis name");
1073
+ }
1074
+ }
1075
+ }
1076
+
1077
+ static void
1078
+ km_argmin_func_d(double *ea, int i, int j, void *data)
1079
+ {
1080
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
1081
+ if ( arg->dmm > *ea ) {
1082
+ arg->i = i; arg->j = j; arg->dmm = *ea;
1083
+ }
1084
+ }
1085
+ static void
1086
+ km_argmin_func_i(int *ea, int i, int j, void *data)
1087
+ {
1088
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
1089
+ if ( arg->imm > *ea ) {
1090
+ arg->i = i; arg->j = j; arg->imm = *ea;
1091
+ }
1092
+ }
1093
+ static void
1094
+ km_argmin_func_b(bool *ea, int i, int j, void *data)
1095
+ {
1096
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
1097
+ if ( (arg->bmm) && (!(*ea)) ) {
1098
+ arg->i = i; arg->j = j; arg->bmm = false;
1099
+ }
1100
+ }
1101
+ static void
1102
+ km_argmin_func_v(VALUE *ea, int i, int j, void *data)
1103
+ {
1104
+ struct km_amm_arg *arg = (struct km_amm_arg *)data;
1105
+ if ( RTEST(rb_funcall(arg->vmm, id_op_gt, 1, *ea)) ) {
1106
+ arg->i = i; arg->j = j; arg->vmm = *ea;
1107
+ }
1108
+ }
1109
+ DEFINE_AMM(min, >, id_op_gt, !)
1110
+ VALUE
1111
+ kmm_mat_argmin_destl(VALUE self, VALUE va)
1112
+ {
1113
+ km_check_frozen(self); SMAT *sr = km_mat2smat(self), *sa = km_mat2smat(va);
1114
+ if ( sr->vtype != VT_INT || sr->stype != ST_FULL ) {
1115
+ rb_raise(rb_eRuntimeError, "self must be an int full matrix");
1116
+ }
1117
+ if ( sr->trans ) {
1118
+ if ( kmm_mat_have_submatrix_p(self) ) {
1119
+ return kmm_mat_copy_from(self, kmm_mat_argmin_destl(rb_obj_dup(self), va));
1120
+ } else {
1121
+ sr->trans = false; sr->ld = sr->m;
1122
+ }
1123
+ }
1124
+ if ( sr->m == 1 && sr->n == 1 ) {
1125
+ return km_mat_argmin_all(sr, sa, va);
1126
+ } else if ( sr->m == 1 && sr->n == sa->n ) {
1127
+ return km_mat_argmin_col(self, sr, sa, va);
1128
+ } else if ( sr->m == sa->m && sr->n == 1 ) {
1129
+ return km_mat_argmin_row(self, sr, sa, va);
1130
+ } else {
1131
+ rb_raise(km_eDim, "argmax/min from size (%d, %d) to size (%d, %d) is not defined", sa->m, sa->n, sr->m, sr->n);
1132
+ }
1133
+ }
1134
+ VALUE
1135
+ kmm_mat_argmin(int argc, VALUE *argv, VALUE va)
1136
+ {
1137
+ rb_check_arity(argc, 0, 1);
1138
+ if ( argc == 0 ) {
1139
+ return kmm_mat_argmin_destl(km_Mat(1, 1, VT_INT), va);
1140
+ } else {
1141
+ VALUE asym = argv[0];
1142
+ if ( rb_respond_to(asym, id_to_sym) ) {
1143
+ asym = rb_funcall(asym, id_to_sym, 0);
1144
+ }
1145
+ SMAT *sa = km_mat2smat(va);
1146
+ if ( asym == sym_col || asym == sym_c ) {
1147
+ return kmm_mat_argmin_destl(km_Mat(1, sa->n, VT_INT), va);
1148
+ } else if ( asym == sym_row || asym == sym_r ) {
1149
+ return kmm_mat_argmin_destl(km_Mat(sa->m, 1, VT_INT), va);
1150
+ } else if ( asym == sym_all || asym == sym_a ) {
1151
+ return kmm_mat_argmin_destl(km_Mat(1, 1, VT_INT), va);
1152
+ } else {
1153
+ rb_raise(rb_eArgError, "unknown axis name");
1154
+ }
1155
+ }
1156
+ }