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