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.
- checksums.yaml +7 -0
- data/.gitattributes +3 -0
- data/.gitignore +15 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE.md +675 -0
- data/README.md +224 -0
- data/Rakefile +26 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/kmat/arith/binary.c +1121 -0
- data/ext/kmat/arith/logical.c +332 -0
- data/ext/kmat/arith/math.c +34 -0
- data/ext/kmat/arith/statistics.c +173 -0
- data/ext/kmat/arith/unary.c +165 -0
- data/ext/kmat/auto_collect.rb +118 -0
- data/ext/kmat/elementwise_function.rb +149 -0
- data/ext/kmat/extconf.rb +75 -0
- data/ext/kmat/id.txt +80 -0
- data/ext/kmat/id_sym.rb +40 -0
- data/ext/kmat/km_util.h +97 -0
- data/ext/kmat/kmat.h +96 -0
- data/ext/kmat/lapack_headers/blas.h +354 -0
- data/ext/kmat/lapack_headers/lapacke.h +19455 -0
- data/ext/kmat/lapack_headers/lapacke_config.h +119 -0
- data/ext/kmat/lapack_headers/lapacke_mangling.h +17 -0
- data/ext/kmat/lapack_headers/lapacke_utils.h +579 -0
- data/ext/kmat/linalg/dla.c +1629 -0
- data/ext/kmat/linalg/linalg.c +267 -0
- data/ext/kmat/linalg/norm.c +727 -0
- data/ext/kmat/linalg/vla.c +102 -0
- data/ext/kmat/linalg/working.c +240 -0
- data/ext/kmat/main.c +95 -0
- data/ext/kmat/smat/accessor.c +719 -0
- data/ext/kmat/smat/array.c +108 -0
- data/ext/kmat/smat/boxmuller.c +72 -0
- data/ext/kmat/smat/constructer.c +302 -0
- data/ext/kmat/smat/convert.c +375 -0
- data/ext/kmat/smat/elem.c +171 -0
- data/ext/kmat/smat/fund.c +702 -0
- data/ext/kmat/smat/share.c +427 -0
- data/ext/kmat/smat/smat.c +530 -0
- data/ext/kmat/smat/sort.c +1156 -0
- data/ext/kmat/sym.txt +34 -0
- data/kmat.gemspec +46 -0
- data/lib/kmat.rb +20 -0
- data/lib/kmat/accessor.rb +164 -0
- data/lib/kmat/arith.rb +189 -0
- data/lib/kmat/linalg.rb +279 -0
- data/lib/kmat/logical.rb +150 -0
- data/lib/kmat/misc.rb +122 -0
- data/lib/kmat/random.rb +106 -0
- data/lib/kmat/statistics.rb +98 -0
- data/lib/kmat/version.rb +3 -0
- 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
|
+
}
|