fast_matrix 0.1.66 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +0 -1
- data/.travis.yml +2 -1
- data/README.md +3 -8
- data/ext/fast_matrix/{c_array_opeartions.c → Helper/c_array_opeartions.c} +39 -1
- data/ext/fast_matrix/{c_array_operations.h → Helper/c_array_operations.h} +6 -1
- data/ext/fast_matrix/{errors.c → Helper/errors.c} +8 -2
- data/ext/fast_matrix/{errors.h → Helper/errors.h} +3 -1
- data/ext/fast_matrix/Matrix/c_matrix.c +606 -0
- data/ext/fast_matrix/Matrix/c_matrix.h +49 -0
- data/ext/fast_matrix/Matrix/errors.h +28 -0
- data/ext/fast_matrix/Matrix/helper.h +27 -0
- data/ext/fast_matrix/Matrix/matrix.c +633 -0
- data/ext/fast_matrix/Matrix/matrix.h +11 -0
- data/ext/fast_matrix/Vector/c_vector.c +97 -0
- data/ext/fast_matrix/Vector/c_vector.h +24 -0
- data/ext/fast_matrix/Vector/errors.h +14 -0
- data/ext/fast_matrix/Vector/helper.h +26 -0
- data/ext/fast_matrix/Vector/vector.c +476 -0
- data/ext/fast_matrix/{vector.h → Vector/vector.h} +0 -10
- data/ext/fast_matrix/c_include.c +8 -0
- data/ext/fast_matrix/fast_matrix.h +3 -3
- data/fast_matrix.gemspec +1 -1
- data/lib/fast_matrix/version.rb +1 -1
- data/lib/matrix/constructors.rb +0 -63
- data/lib/matrix/matrix.rb +105 -4
- data/lib/vector/constructors.rb +5 -4
- data/lib/vector/vector.rb +29 -0
- metadata +21 -12
- data/ext/fast_matrix/matrix.c +0 -678
- data/ext/fast_matrix/matrix.h +0 -28
- data/ext/fast_matrix/vector.c +0 -277
@@ -0,0 +1,49 @@
|
|
1
|
+
#ifndef FAST_MATRIX_MATRIX_C_MATRIX_H
|
2
|
+
#define FAST_MATRIX_MATRIX_C_MATRIX_H 1
|
3
|
+
|
4
|
+
#include <stdbool.h>
|
5
|
+
|
6
|
+
// matrix
|
7
|
+
// m --->
|
8
|
+
// [ 0, 1, .., m-1]
|
9
|
+
// n [ m, m+1, .., 2m-1]
|
10
|
+
// | [2m, 2m+1, .., 3m-1]
|
11
|
+
// V [ . . . . .
|
12
|
+
// . . . . nm-1]
|
13
|
+
struct matrix
|
14
|
+
{
|
15
|
+
int m;
|
16
|
+
int n;
|
17
|
+
|
18
|
+
double* data;
|
19
|
+
};
|
20
|
+
|
21
|
+
double c_matrix_trace(int n, const double* A);
|
22
|
+
double c_matrix_determinant(int n, const double* A);
|
23
|
+
|
24
|
+
void c_matrix_transpose(int m, int n, const double* in, double* out);
|
25
|
+
void c_matrix_multiply(int n, int k, int m, const double* A, const double* B, double* C);
|
26
|
+
void c_matrix_vector_multiply(int n, int m, const double* M, const double* V, double* R);
|
27
|
+
void c_matrix_strassen(int n, int k, int m, const double* A, const double* B, double* C);
|
28
|
+
void c_matrix_hstack(int argc, struct matrix** mtrs, double* C, int m);
|
29
|
+
void c_matrix_column_vector(int m, int n, const double* M, double* V, int idx);
|
30
|
+
void c_matrix_scalar(int n, double* C, double v);
|
31
|
+
void c_matrix_minor(int m, int n, const double* A, double* B, int m_idx, int n_idx);
|
32
|
+
void c_matrix_vstack(int argc, struct matrix** mtrs, double* C);
|
33
|
+
|
34
|
+
bool c_matrix_symmetric(int n, const double* C);
|
35
|
+
bool c_matrix_antisymmetric(int n, const double* C);
|
36
|
+
bool c_matrix_diagonal(int n, const double* C);
|
37
|
+
bool c_matrix_lower_triangular(int n, const double* A);
|
38
|
+
bool c_matrix_upper_triangular(int n, const double* A);
|
39
|
+
bool c_matrix_permutation(int n, const double* A);
|
40
|
+
bool c_matrix_identity(int n, const double* A);
|
41
|
+
bool c_matrix_equal_by_m(int argc, struct matrix** mtrs);
|
42
|
+
bool c_matrix_equal_by_n(int argc, struct matrix** mtrs);
|
43
|
+
bool c_matrix_inverse(int n, const double* A, double* B);
|
44
|
+
|
45
|
+
int c_matrix_sum_by_m(int argc, struct matrix** mtrs);
|
46
|
+
int c_matrix_sum_by_n(int argc, struct matrix** mtrs);
|
47
|
+
int c_matrix_rank(int m, int n, const double* C);
|
48
|
+
|
49
|
+
#endif /* FAST_MATRIX_MATRIX_C_MATRIX_H */
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#ifndef FAST_MATRIX_MATRIX_ERRORS_H
|
2
|
+
#define FAST_MATRIX_MATRIX_ERRORS_H 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "Matrix/matrix.h"
|
6
|
+
|
7
|
+
// check if the matrix is of equal size and raise an error if not
|
8
|
+
inline void raise_check_equal_size_matrix(struct matrix* A, struct matrix* B)
|
9
|
+
{
|
10
|
+
if(A->m != B->m || A->n != B->n)
|
11
|
+
rb_raise(fm_eIndexError, "Different sizes matrices");
|
12
|
+
}
|
13
|
+
|
14
|
+
// check if the matrix is square and raise an error if not
|
15
|
+
inline void raise_check_square_matrix(struct matrix* A)
|
16
|
+
{
|
17
|
+
if(A->n != A->m)
|
18
|
+
rb_raise(fm_eIndexError, "Expected square matrix");
|
19
|
+
}
|
20
|
+
|
21
|
+
// check if the value is zero and raise an error if not
|
22
|
+
inline void raise_check_no_arguments(int argc)
|
23
|
+
{
|
24
|
+
if(argc == 0)
|
25
|
+
rb_raise(fm_eIndexError, "No arguments");
|
26
|
+
}
|
27
|
+
|
28
|
+
#endif /* FAST_MATRIX_MATRIX_ERRORS_H */
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#ifndef FAST_MATRIX_MATRIX_HELPER_H
|
2
|
+
#define FAST_MATRIX_MATRIX_HELPER_H 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "Matrix/c_matrix.h"
|
6
|
+
|
7
|
+
inline struct matrix* get_matrix_from_rb_value(VALUE m)
|
8
|
+
{
|
9
|
+
struct matrix* data;
|
10
|
+
TypedData_Get_Struct(m, struct matrix, &matrix_type, data);
|
11
|
+
return data;
|
12
|
+
}
|
13
|
+
|
14
|
+
inline void c_matrix_init(struct matrix* mtr, int m, int n)
|
15
|
+
{
|
16
|
+
mtr->m = m;
|
17
|
+
mtr->n = n;
|
18
|
+
mtr->data = malloc(m * n * sizeof(double));
|
19
|
+
}
|
20
|
+
|
21
|
+
#define MAKE_MATRIX_AND_RB_VALUE(matrix_name, rb_value_name, m, n)\
|
22
|
+
struct matrix* matrix_name; \
|
23
|
+
VALUE rb_value_name = TypedData_Make_Struct( \
|
24
|
+
cMatrix, struct matrix, &matrix_type, matrix_name); \
|
25
|
+
c_matrix_init(matrix_name, m, n)
|
26
|
+
|
27
|
+
#endif /* FAST_MATRIX_MATRIX_HELPER_H */
|
@@ -0,0 +1,633 @@
|
|
1
|
+
#include "Matrix/matrix.h"
|
2
|
+
#include "Helper/c_array_operations.h"
|
3
|
+
#include "Helper/errors.h"
|
4
|
+
#include "Vector/vector.h"
|
5
|
+
#include "Matrix/errors.h"
|
6
|
+
#include "Matrix/helper.h"
|
7
|
+
#include "Vector/helper.h"
|
8
|
+
|
9
|
+
VALUE cMatrix;
|
10
|
+
|
11
|
+
void matrix_free(void* data);
|
12
|
+
size_t matrix_size(const void* data);
|
13
|
+
|
14
|
+
const rb_data_type_t matrix_type =
|
15
|
+
{
|
16
|
+
.wrap_struct_name = "matrix",
|
17
|
+
.function =
|
18
|
+
{
|
19
|
+
.dmark = NULL,
|
20
|
+
.dfree = matrix_free,
|
21
|
+
.dsize = matrix_size,
|
22
|
+
},
|
23
|
+
.data = NULL,
|
24
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
25
|
+
};
|
26
|
+
|
27
|
+
void matrix_free(void* data)
|
28
|
+
{
|
29
|
+
free(((*(struct matrix*)data)).data);
|
30
|
+
free(data);
|
31
|
+
}
|
32
|
+
|
33
|
+
size_t matrix_size(const void* data)
|
34
|
+
{
|
35
|
+
return sizeof(struct matrix);
|
36
|
+
}
|
37
|
+
|
38
|
+
VALUE matrix_alloc(VALUE self)
|
39
|
+
{
|
40
|
+
struct matrix* mtx = malloc(sizeof(struct matrix));
|
41
|
+
mtx->data = NULL;
|
42
|
+
return TypedData_Wrap_Struct(self, &matrix_type, mtx);
|
43
|
+
}
|
44
|
+
|
45
|
+
VALUE matrix_initialize(VALUE self, VALUE rows_count, VALUE columns_count)
|
46
|
+
{
|
47
|
+
int m = raise_rb_value_to_int(columns_count);
|
48
|
+
int n = raise_rb_value_to_int(rows_count);
|
49
|
+
|
50
|
+
if(m <= 0 || n <= 0)
|
51
|
+
rb_raise(fm_eIndexError, "Size cannot be negative or zero");
|
52
|
+
|
53
|
+
struct matrix* data = get_matrix_from_rb_value(self);
|
54
|
+
c_matrix_init(data, m, n);
|
55
|
+
return self;
|
56
|
+
}
|
57
|
+
|
58
|
+
// []=
|
59
|
+
VALUE matrix_set(VALUE self, VALUE row, VALUE column, VALUE v)
|
60
|
+
{
|
61
|
+
int m = raise_rb_value_to_int(column);
|
62
|
+
int n = raise_rb_value_to_int(row);
|
63
|
+
double x = raise_rb_value_to_double(v);
|
64
|
+
struct matrix* data = get_matrix_from_rb_value(self);
|
65
|
+
|
66
|
+
m = (m < 0) ? data->m + m : m;
|
67
|
+
n = (n < 0) ? data->n + n : n;
|
68
|
+
|
69
|
+
raise_check_range(m, 0, data->m);
|
70
|
+
raise_check_range(n, 0, data->n);
|
71
|
+
|
72
|
+
data->data[m + data->m * n] = x;
|
73
|
+
return v;
|
74
|
+
}
|
75
|
+
|
76
|
+
// []
|
77
|
+
VALUE matrix_get(VALUE self, VALUE row, VALUE column)
|
78
|
+
{
|
79
|
+
int m = raise_rb_value_to_int(column);
|
80
|
+
int n = raise_rb_value_to_int(row);
|
81
|
+
struct matrix* data = get_matrix_from_rb_value(self);
|
82
|
+
|
83
|
+
m = (m < 0) ? data->m + m : m;
|
84
|
+
n = (n < 0) ? data->n + n : n;
|
85
|
+
|
86
|
+
if(m < 0 || n < 0 || n >= data->n || m >= data->m)
|
87
|
+
return Qnil;
|
88
|
+
|
89
|
+
return DBL2NUM(data->data[m + data->m * n]);
|
90
|
+
}
|
91
|
+
|
92
|
+
VALUE matrix_multiply_mv(VALUE self, VALUE other)
|
93
|
+
{
|
94
|
+
struct matrix* M = get_matrix_from_rb_value(self);
|
95
|
+
struct vector* V = get_vector_from_rb_value(other);
|
96
|
+
|
97
|
+
if(M->m != V->n)
|
98
|
+
rb_raise(fm_eIndexError, "Matrix columns differs from vector size");
|
99
|
+
|
100
|
+
MAKE_VECTOR_AND_RB_VALUE(R, result, M->n);
|
101
|
+
c_matrix_vector_multiply(M->n, M->m, M->data, V->data, R->data);
|
102
|
+
return result;
|
103
|
+
}
|
104
|
+
|
105
|
+
VALUE matrix_strassen(VALUE self, VALUE other)
|
106
|
+
{
|
107
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
108
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
109
|
+
|
110
|
+
if(A->m != B->n)
|
111
|
+
rb_raise(fm_eIndexError, "First columns differs from second rows");
|
112
|
+
|
113
|
+
int m = B->m;
|
114
|
+
int k = A->m;
|
115
|
+
int n = A->n;
|
116
|
+
|
117
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, m, n);
|
118
|
+
fill_d_array(m * n, C->data, 0);
|
119
|
+
|
120
|
+
c_matrix_strassen(n, k, m, A->data, B->data, C->data);
|
121
|
+
return result;
|
122
|
+
}
|
123
|
+
|
124
|
+
VALUE matrix_multiply_mm(VALUE self, VALUE other)
|
125
|
+
{
|
126
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
127
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
128
|
+
|
129
|
+
if(A->m != B->n)
|
130
|
+
rb_raise(fm_eIndexError, "First columns differs from second rows");
|
131
|
+
|
132
|
+
int m = B->m;
|
133
|
+
int k = A->m;
|
134
|
+
int n = A->n;
|
135
|
+
|
136
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, m, n);
|
137
|
+
c_matrix_multiply(n, k, m, A->data, B->data, C->data);
|
138
|
+
|
139
|
+
return result;
|
140
|
+
}
|
141
|
+
|
142
|
+
VALUE matrix_multiply_mn(VALUE self, VALUE value)
|
143
|
+
{
|
144
|
+
double d = NUM2DBL(value);
|
145
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
146
|
+
|
147
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, A->m, A->n);
|
148
|
+
copy_d_array(A->m * A->n, A->data, R->data);
|
149
|
+
multiply_d_array(R->m * R->n, R->data, d);
|
150
|
+
|
151
|
+
return result;
|
152
|
+
}
|
153
|
+
|
154
|
+
VALUE matrix_multiply(VALUE self, VALUE v)
|
155
|
+
{
|
156
|
+
if(RB_FLOAT_TYPE_P(v) || FIXNUM_P(v)
|
157
|
+
|| RB_TYPE_P(v, T_BIGNUM))
|
158
|
+
return matrix_multiply_mn(self, v);
|
159
|
+
if(RBASIC_CLASS(v) == cMatrix)
|
160
|
+
return matrix_strassen(self, v);
|
161
|
+
if(RBASIC_CLASS(v) == cVector);
|
162
|
+
return matrix_multiply_mv(self, v);
|
163
|
+
rb_raise(fm_eTypeError, "Invalid klass for multiply");
|
164
|
+
}
|
165
|
+
|
166
|
+
VALUE matrix_copy(VALUE self)
|
167
|
+
{
|
168
|
+
struct matrix* M = get_matrix_from_rb_value(self);
|
169
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, M->m, M->n);
|
170
|
+
copy_d_array(M->m * M->n, M->data, R->data);
|
171
|
+
return result;
|
172
|
+
}
|
173
|
+
|
174
|
+
VALUE matrix_row_size(VALUE self)
|
175
|
+
{
|
176
|
+
struct matrix* data = get_matrix_from_rb_value(self);
|
177
|
+
return INT2NUM(data->m);
|
178
|
+
}
|
179
|
+
|
180
|
+
VALUE matrix_column_size(VALUE self)
|
181
|
+
{
|
182
|
+
struct matrix* data = get_matrix_from_rb_value(self);
|
183
|
+
return INT2NUM(data->n);
|
184
|
+
}
|
185
|
+
|
186
|
+
VALUE matrix_transpose(VALUE self)
|
187
|
+
{
|
188
|
+
struct matrix* M = get_matrix_from_rb_value(self);
|
189
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, M->n, M->m);
|
190
|
+
c_matrix_transpose(M->m, M->n, M->data, R->data);
|
191
|
+
return result;
|
192
|
+
}
|
193
|
+
|
194
|
+
VALUE matrix_add_with(VALUE self, VALUE other)
|
195
|
+
{
|
196
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
197
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
198
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
199
|
+
|
200
|
+
raise_check_equal_size_matrix(A, B);
|
201
|
+
|
202
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, A->m, A->n);
|
203
|
+
add_d_arrays_to_result(A->n * A->m, A->data, B->data, C->data);
|
204
|
+
|
205
|
+
return result;
|
206
|
+
}
|
207
|
+
|
208
|
+
VALUE matrix_add_from(VALUE self, VALUE other)
|
209
|
+
{
|
210
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
211
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
212
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
213
|
+
|
214
|
+
raise_check_equal_size_matrix(A, B);
|
215
|
+
|
216
|
+
add_d_arrays_to_first(A->n * B->m, A->data, B->data);
|
217
|
+
return self;
|
218
|
+
}
|
219
|
+
|
220
|
+
VALUE matrix_sub_with(VALUE self, VALUE other)
|
221
|
+
{
|
222
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
223
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
224
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
225
|
+
|
226
|
+
raise_check_equal_size_matrix(A, B);
|
227
|
+
|
228
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, A->m, A->n);
|
229
|
+
sub_d_arrays_to_result(A->n * A->m, A->data, B->data, C->data);
|
230
|
+
return result;
|
231
|
+
}
|
232
|
+
|
233
|
+
VALUE matrix_sub_from(VALUE self, VALUE other)
|
234
|
+
{
|
235
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
236
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
237
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
238
|
+
|
239
|
+
raise_check_equal_size_matrix(A, B);
|
240
|
+
|
241
|
+
sub_d_arrays_to_first(A->n * B->m, A->data, B->data);
|
242
|
+
return self;
|
243
|
+
}
|
244
|
+
|
245
|
+
VALUE matrix_determinant(VALUE self)
|
246
|
+
{
|
247
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
248
|
+
raise_check_square_matrix(A);
|
249
|
+
return DBL2NUM(c_matrix_determinant(A->n, A->data));
|
250
|
+
}
|
251
|
+
|
252
|
+
VALUE matrix_fill(VALUE self, VALUE value)
|
253
|
+
{
|
254
|
+
double d = raise_rb_value_to_double(value);
|
255
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
256
|
+
fill_d_array(A->m * A->n, A->data, d);
|
257
|
+
return self;
|
258
|
+
}
|
259
|
+
|
260
|
+
VALUE matrix_equal(VALUE self, VALUE other)
|
261
|
+
{
|
262
|
+
if(RBASIC_CLASS(other) != cMatrix)
|
263
|
+
return Qfalse;
|
264
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
265
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
266
|
+
|
267
|
+
if(A->n != B->n || A->m != B->m)
|
268
|
+
return Qfalse;
|
269
|
+
|
270
|
+
if(equal_d_arrays(A->n * A->m, A->data, B->data))
|
271
|
+
return Qtrue;
|
272
|
+
return Qfalse;
|
273
|
+
}
|
274
|
+
|
275
|
+
VALUE matrix_abs(VALUE self)
|
276
|
+
{
|
277
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
278
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, A->m, A->n);
|
279
|
+
abs_d_array(A->n * A->m, A->data, R->data);
|
280
|
+
return result;
|
281
|
+
}
|
282
|
+
|
283
|
+
VALUE matrix_greater_or_equal(VALUE self, VALUE other)
|
284
|
+
{
|
285
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
286
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
287
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
288
|
+
|
289
|
+
raise_check_equal_size_matrix(A, B);
|
290
|
+
|
291
|
+
if(greater_or_equal_d_array(A->n * A->m, A->data, B->data))
|
292
|
+
return Qtrue;
|
293
|
+
return Qfalse;
|
294
|
+
}
|
295
|
+
|
296
|
+
struct matrix** convert_matrix_array(int argc, VALUE *argv, struct matrix*** mtrs)
|
297
|
+
{
|
298
|
+
for(int i = 0; i < argc; ++i)
|
299
|
+
raise_check_rbasic(argv[i], cMatrix, "matrix");
|
300
|
+
|
301
|
+
*mtrs = (struct matrix**)malloc(argc * sizeof(struct matrix*));
|
302
|
+
|
303
|
+
for(int i = 0; i < argc; ++i)
|
304
|
+
TypedData_Get_Struct(argv[i], struct matrix, &matrix_type, (*mtrs)[i]);
|
305
|
+
}
|
306
|
+
|
307
|
+
VALUE matrix_vstack(int argc, VALUE *argv, VALUE obj)
|
308
|
+
{
|
309
|
+
raise_check_no_arguments(argc);
|
310
|
+
|
311
|
+
struct matrix** mtrs;
|
312
|
+
convert_matrix_array(argc, argv, &mtrs);
|
313
|
+
|
314
|
+
if(!c_matrix_equal_by_m(argc, mtrs))
|
315
|
+
{
|
316
|
+
free(mtrs);
|
317
|
+
rb_raise(fm_eIndexError, "Rows of different size");
|
318
|
+
}
|
319
|
+
|
320
|
+
int m = mtrs[0]->m;
|
321
|
+
int n = c_matrix_sum_by_n(argc, mtrs);
|
322
|
+
|
323
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, m, n);
|
324
|
+
c_matrix_vstack(argc, mtrs, C->data);
|
325
|
+
free(mtrs);
|
326
|
+
return result;
|
327
|
+
}
|
328
|
+
|
329
|
+
VALUE matrix_hstack(int argc, VALUE *argv, VALUE obj)
|
330
|
+
{
|
331
|
+
raise_check_no_arguments(argc);
|
332
|
+
|
333
|
+
struct matrix** mtrs;
|
334
|
+
convert_matrix_array(argc, argv, &mtrs);
|
335
|
+
|
336
|
+
if(!c_matrix_equal_by_n(argc, mtrs))
|
337
|
+
{
|
338
|
+
free(mtrs);
|
339
|
+
rb_raise(fm_eIndexError, "Columns of different size");
|
340
|
+
}
|
341
|
+
|
342
|
+
int m = c_matrix_sum_by_m(argc, mtrs);
|
343
|
+
int n = mtrs[0]->n;
|
344
|
+
|
345
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, m, n);
|
346
|
+
c_matrix_hstack(argc, mtrs, C->data, m);
|
347
|
+
|
348
|
+
free(mtrs);
|
349
|
+
return result;
|
350
|
+
}
|
351
|
+
|
352
|
+
VALUE matrix_scalar(VALUE obj, VALUE size, VALUE value)
|
353
|
+
{
|
354
|
+
int n = raise_rb_value_to_int(size);
|
355
|
+
double v = raise_rb_value_to_double(value);
|
356
|
+
|
357
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, n, n);
|
358
|
+
c_matrix_scalar(n, C->data, v);
|
359
|
+
return result;
|
360
|
+
}
|
361
|
+
|
362
|
+
VALUE matrix_antisymmetric(VALUE self)
|
363
|
+
{
|
364
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
365
|
+
raise_check_square_matrix(A);
|
366
|
+
|
367
|
+
if(c_matrix_antisymmetric(A->n, A->data))
|
368
|
+
return Qtrue;
|
369
|
+
return Qfalse;
|
370
|
+
}
|
371
|
+
|
372
|
+
VALUE matrix_symmetric(VALUE self)
|
373
|
+
{
|
374
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
375
|
+
raise_check_square_matrix(A);
|
376
|
+
if(c_matrix_symmetric(A->n, A->data))
|
377
|
+
return Qtrue;
|
378
|
+
return Qfalse;
|
379
|
+
}
|
380
|
+
|
381
|
+
VALUE matrix_minus(VALUE self)
|
382
|
+
{
|
383
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
384
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, A->m, A->n);
|
385
|
+
multiply_d_array_to_result(A->n * A->m, A->data, -1, C->data);
|
386
|
+
return result;
|
387
|
+
}
|
388
|
+
|
389
|
+
VALUE matrix_plus(VALUE self)
|
390
|
+
{
|
391
|
+
return self;
|
392
|
+
}
|
393
|
+
|
394
|
+
VALUE matrix_row_vector(VALUE self, VALUE v)
|
395
|
+
{
|
396
|
+
int idx = raise_rb_value_to_int(v);
|
397
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
398
|
+
|
399
|
+
int m = A->m;
|
400
|
+
int n = A->n;
|
401
|
+
idx = (idx < 0) ? m + idx : idx;
|
402
|
+
|
403
|
+
if(idx < 0 || idx >= m)
|
404
|
+
return Qnil;
|
405
|
+
|
406
|
+
MAKE_VECTOR_AND_RB_VALUE(C, result, n);
|
407
|
+
copy_d_array(m, A->data + idx * m, C->data);
|
408
|
+
return result;
|
409
|
+
}
|
410
|
+
|
411
|
+
VALUE matrix_column_vector(VALUE self, VALUE v)
|
412
|
+
{
|
413
|
+
int idx = raise_rb_value_to_int(v);
|
414
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
415
|
+
|
416
|
+
int m = A->m;
|
417
|
+
int n = A->n;
|
418
|
+
idx = (idx < 0) ? n + idx : idx;
|
419
|
+
|
420
|
+
if(idx < 0 || idx >= n)
|
421
|
+
return Qnil;
|
422
|
+
|
423
|
+
MAKE_VECTOR_AND_RB_VALUE(C, result, n);
|
424
|
+
c_matrix_column_vector(m, n, A->data, C->data, idx);
|
425
|
+
return result;
|
426
|
+
}
|
427
|
+
|
428
|
+
VALUE matrix_diagonal(VALUE self)
|
429
|
+
{
|
430
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
431
|
+
raise_check_square_matrix(A);
|
432
|
+
|
433
|
+
if(c_matrix_diagonal(A->n, A->data))
|
434
|
+
return Qtrue;
|
435
|
+
return Qfalse;
|
436
|
+
}
|
437
|
+
|
438
|
+
VALUE matrix_hadamard_product(VALUE self, VALUE other)
|
439
|
+
{
|
440
|
+
raise_check_rbasic(other, cMatrix, "matrix");
|
441
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
442
|
+
struct matrix* B = get_matrix_from_rb_value(other);
|
443
|
+
|
444
|
+
raise_check_equal_size_matrix(A, B);
|
445
|
+
|
446
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, A->m, A->n);
|
447
|
+
multiply_elems_d_array_to_result(A->n * A->m, A->data, B->data, C->data);
|
448
|
+
return result;
|
449
|
+
}
|
450
|
+
|
451
|
+
VALUE matrix_trace(VALUE self)
|
452
|
+
{
|
453
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
454
|
+
raise_check_square_matrix(A);
|
455
|
+
return DBL2NUM(c_matrix_trace(A->n, A->data));
|
456
|
+
}
|
457
|
+
|
458
|
+
VALUE matrix_first_minor(VALUE self, VALUE row, VALUE column)
|
459
|
+
{
|
460
|
+
int i = raise_rb_value_to_int(column);
|
461
|
+
int j = raise_rb_value_to_int(row);
|
462
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
463
|
+
|
464
|
+
int m = A->m;
|
465
|
+
int n = A->n;
|
466
|
+
if(i < 0 || i >= m || j < 0 || j >= n)
|
467
|
+
rb_raise(fm_eIndexError, "Index out of range");
|
468
|
+
|
469
|
+
MAKE_MATRIX_AND_RB_VALUE(C, result, m - 1, n - 1);
|
470
|
+
c_matrix_minor(m, n, A->data, C->data, i, j);
|
471
|
+
return result;
|
472
|
+
}
|
473
|
+
|
474
|
+
VALUE matrix_cofactor(VALUE self, VALUE row, VALUE column)
|
475
|
+
{
|
476
|
+
int i = raise_rb_value_to_int(column);
|
477
|
+
int j = raise_rb_value_to_int(row);
|
478
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
479
|
+
|
480
|
+
int m = A->m;
|
481
|
+
int n = A->n;
|
482
|
+
if(i < 0 || i >= m || j < 0 || j >= n)
|
483
|
+
rb_raise(fm_eIndexError, "Index out of range");
|
484
|
+
raise_check_square_matrix(A);
|
485
|
+
|
486
|
+
double* D = malloc(sizeof(double) * (n - 1) * (n - 1));
|
487
|
+
c_matrix_minor(n, n, A->data, D, i, j);
|
488
|
+
|
489
|
+
int coefficient = ((i + j) % 2 == 1) ? -1 : 1;
|
490
|
+
double det = c_matrix_determinant(n - 1, D);
|
491
|
+
|
492
|
+
free(D);
|
493
|
+
return DBL2NUM(coefficient * det);
|
494
|
+
}
|
495
|
+
|
496
|
+
VALUE matrix_zero(VALUE self)
|
497
|
+
{
|
498
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
499
|
+
if(zero_d_array(A->m * A->n, A->data))
|
500
|
+
return Qtrue;
|
501
|
+
return Qfalse;
|
502
|
+
}
|
503
|
+
|
504
|
+
VALUE matrix_rank(VALUE self)
|
505
|
+
{
|
506
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
507
|
+
return INT2NUM(c_matrix_rank(A->m, A->n, A->data));
|
508
|
+
}
|
509
|
+
|
510
|
+
VALUE matrix_round(int argc, VALUE *argv, VALUE self)
|
511
|
+
{
|
512
|
+
if(argc > 1)
|
513
|
+
rb_raise(fm_eTypeError, "Wrong number of arguments");
|
514
|
+
int d;
|
515
|
+
if(argc == 1)
|
516
|
+
d = raise_rb_value_to_int(argv[0]);
|
517
|
+
else
|
518
|
+
d = 0;
|
519
|
+
|
520
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
521
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, A->m, A->n);
|
522
|
+
round_d_array(A->m * A->n, A->data, R->data, d);
|
523
|
+
return result;
|
524
|
+
}
|
525
|
+
|
526
|
+
VALUE matrix_lower_triangular(VALUE self)
|
527
|
+
{
|
528
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
529
|
+
raise_check_square_matrix(A);
|
530
|
+
|
531
|
+
if(c_matrix_lower_triangular(A->n, A->data))
|
532
|
+
return Qtrue;
|
533
|
+
return Qfalse;
|
534
|
+
}
|
535
|
+
|
536
|
+
VALUE matrix_upper_triangular(VALUE self)
|
537
|
+
{
|
538
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
539
|
+
raise_check_square_matrix(A);
|
540
|
+
|
541
|
+
if(c_matrix_upper_triangular(A->n, A->data))
|
542
|
+
return Qtrue;
|
543
|
+
return Qfalse;
|
544
|
+
}
|
545
|
+
|
546
|
+
VALUE matrix_permutation(VALUE self)
|
547
|
+
{
|
548
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
549
|
+
raise_check_square_matrix(A);
|
550
|
+
|
551
|
+
if(c_matrix_permutation(A->n, A->data))
|
552
|
+
return Qtrue;
|
553
|
+
return Qfalse;
|
554
|
+
}
|
555
|
+
|
556
|
+
VALUE matrix_orthogonal(VALUE self)
|
557
|
+
{
|
558
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
559
|
+
raise_check_square_matrix(A);
|
560
|
+
|
561
|
+
int n = A->n;
|
562
|
+
double* B = malloc(sizeof(double) * n * n);
|
563
|
+
double* C = malloc(sizeof(double) * n * n);
|
564
|
+
|
565
|
+
c_matrix_transpose(n, n, A->data, B);
|
566
|
+
fill_d_array(n * n, C, 0);
|
567
|
+
c_matrix_strassen(n, n, n, A->data, B, C);
|
568
|
+
bool result = c_matrix_identity(n, C);
|
569
|
+
|
570
|
+
free(B);
|
571
|
+
free(C);
|
572
|
+
if(result)
|
573
|
+
return Qtrue;
|
574
|
+
return Qfalse;
|
575
|
+
}
|
576
|
+
|
577
|
+
VALUE matrix_inverse(VALUE self)
|
578
|
+
{
|
579
|
+
struct matrix* A = get_matrix_from_rb_value(self);
|
580
|
+
raise_check_square_matrix(A);
|
581
|
+
MAKE_MATRIX_AND_RB_VALUE(R, result, A->n, A->n);
|
582
|
+
if(!c_matrix_inverse(R->n, A->data, R->data))
|
583
|
+
rb_raise(fm_eIndexError, "The discriminant is zero");
|
584
|
+
return result;
|
585
|
+
}
|
586
|
+
|
587
|
+
void init_fm_matrix()
|
588
|
+
{
|
589
|
+
VALUE mod = rb_define_module("FastMatrix");
|
590
|
+
cMatrix = rb_define_class_under(mod, "Matrix", rb_cData);
|
591
|
+
|
592
|
+
rb_define_alloc_func(cMatrix, matrix_alloc);
|
593
|
+
|
594
|
+
rb_define_method(cMatrix, "initialize", matrix_initialize, 2);
|
595
|
+
rb_define_method(cMatrix, "[]", matrix_get, 2);
|
596
|
+
rb_define_method(cMatrix, "[]=", matrix_set, 3);
|
597
|
+
rb_define_method(cMatrix, "*", matrix_multiply, 1);
|
598
|
+
rb_define_method(cMatrix, "column_count", matrix_row_size, 0);
|
599
|
+
rb_define_method(cMatrix, "row_count", matrix_column_size, 0);
|
600
|
+
rb_define_method(cMatrix, "clone", matrix_copy, 0);
|
601
|
+
rb_define_method(cMatrix, "transpose", matrix_transpose, 0);
|
602
|
+
rb_define_method(cMatrix, "+", matrix_add_with, 1);
|
603
|
+
rb_define_method(cMatrix, "+=", matrix_add_from, 1);
|
604
|
+
rb_define_method(cMatrix, "-", matrix_sub_with, 1);
|
605
|
+
rb_define_method(cMatrix, "-=", matrix_sub_from, 1);
|
606
|
+
rb_define_method(cMatrix, "fill!", matrix_fill, 1);
|
607
|
+
rb_define_method(cMatrix, "abs", matrix_abs, 0);
|
608
|
+
rb_define_method(cMatrix, ">=", matrix_greater_or_equal, 1);
|
609
|
+
rb_define_method(cMatrix, "determinant", matrix_determinant, 0);
|
610
|
+
rb_define_method(cMatrix, "eql?", matrix_equal, 1);
|
611
|
+
rb_define_method(cMatrix, "antisymmetric?", matrix_antisymmetric, 0);
|
612
|
+
rb_define_method(cMatrix, "symmetric?", matrix_symmetric, 0);
|
613
|
+
rb_define_method(cMatrix, "-@", matrix_minus, 0);
|
614
|
+
rb_define_method(cMatrix, "+@", matrix_plus, 0);
|
615
|
+
rb_define_method(cMatrix, "column", matrix_column_vector, 1);
|
616
|
+
rb_define_method(cMatrix, "row", matrix_row_vector, 1);
|
617
|
+
rb_define_method(cMatrix, "diagonal?", matrix_diagonal, 0);
|
618
|
+
rb_define_method(cMatrix, "hadamard_product", matrix_hadamard_product, 1);
|
619
|
+
rb_define_method(cMatrix, "trace", matrix_trace, 0);
|
620
|
+
rb_define_method(cMatrix, "first_minor", matrix_first_minor, 2);
|
621
|
+
rb_define_method(cMatrix, "cofactor", matrix_cofactor, 2);
|
622
|
+
rb_define_method(cMatrix, "zero?", matrix_zero, 0);
|
623
|
+
rb_define_method(cMatrix, "rank", matrix_rank, 0);
|
624
|
+
rb_define_method(cMatrix, "round", matrix_round, -1);
|
625
|
+
rb_define_method(cMatrix, "lower_triangular?", matrix_lower_triangular, 0);
|
626
|
+
rb_define_method(cMatrix, "upper_triangular?", matrix_upper_triangular, 0);
|
627
|
+
rb_define_method(cMatrix, "permutation?", matrix_permutation, 0);
|
628
|
+
rb_define_method(cMatrix, "orthogonal?", matrix_orthogonal, 0);
|
629
|
+
rb_define_method(cMatrix, "inverse", matrix_inverse, 0);
|
630
|
+
rb_define_module_function(cMatrix, "vstack", matrix_vstack, -1);
|
631
|
+
rb_define_module_function(cMatrix, "hstack", matrix_hstack, -1);
|
632
|
+
rb_define_module_function(cMatrix, "scalar", matrix_scalar, 2);
|
633
|
+
}
|