fast_matrix 0.1.4 → 0.1.5
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/Dockerfile +3 -3
- data/README.md +15 -1
- data/ext/fast_matrix/c_array_opeartions.c +36 -1
- data/ext/fast_matrix/c_array_operations.h +8 -1
- data/ext/fast_matrix/errors.c +37 -0
- data/ext/fast_matrix/errors.h +18 -0
- data/ext/fast_matrix/fast_matrix.c +2 -0
- data/ext/fast_matrix/fast_matrix.h +2 -0
- data/ext/fast_matrix/matrix.c +367 -49
- data/ext/fast_matrix/matrix.h +4 -19
- data/ext/fast_matrix/vector.c +273 -0
- data/ext/fast_matrix/vector.h +20 -0
- data/lib/errors.rb +9 -0
- data/lib/fast_matrix.rb +3 -72
- data/lib/fast_matrix/version.rb +1 -1
- data/lib/matrix/constructors.rb +253 -0
- data/lib/matrix/matrix.rb +80 -0
- data/lib/vector/constructors.rb +58 -0
- data/lib/vector/vector.rb +20 -0
- metadata +11 -5
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/constructors.rb +0 -109
data/ext/fast_matrix/matrix.h
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
static VALUE cMatrix;
|
6
|
+
extern VALUE cMatrix;
|
7
|
+
extern const rb_data_type_t matrix_type;
|
9
8
|
|
10
9
|
// matrix
|
11
10
|
// m --->
|
@@ -22,22 +21,8 @@ struct matrix
|
|
22
21
|
double* data;
|
23
22
|
};
|
24
23
|
|
25
|
-
void
|
26
|
-
size_t matrix_size(const void* data);
|
27
|
-
|
28
|
-
static const rb_data_type_t matrix_type =
|
29
|
-
{
|
30
|
-
.wrap_struct_name = "matrix",
|
31
|
-
.function =
|
32
|
-
{
|
33
|
-
.dmark = NULL,
|
34
|
-
.dfree = matrix_free,
|
35
|
-
.dsize = matrix_size,
|
36
|
-
},
|
37
|
-
.data = NULL,
|
38
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
39
|
-
};
|
24
|
+
void c_matrix_init(struct matrix* mtr, int m, int n);
|
40
25
|
|
41
26
|
void init_fm_matrix();
|
42
27
|
|
43
|
-
#endif /* FAST_MATRIX_MATRIX_H */
|
28
|
+
#endif /* FAST_MATRIX_MATRIX_H */
|
@@ -0,0 +1,273 @@
|
|
1
|
+
#include "vector.h"
|
2
|
+
#include "c_array_operations.h"
|
3
|
+
#include "errors.h"
|
4
|
+
#include "matrix.h"
|
5
|
+
|
6
|
+
VALUE cVector;
|
7
|
+
|
8
|
+
void vector_free(void* data);
|
9
|
+
size_t vector_size(const void* data);
|
10
|
+
|
11
|
+
const rb_data_type_t vector_type =
|
12
|
+
{
|
13
|
+
.wrap_struct_name = "vector",
|
14
|
+
.function =
|
15
|
+
{
|
16
|
+
.dmark = NULL,
|
17
|
+
.dfree = vector_free,
|
18
|
+
.dsize = vector_size,
|
19
|
+
},
|
20
|
+
.data = NULL,
|
21
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
22
|
+
};
|
23
|
+
|
24
|
+
void vector_free(void* data)
|
25
|
+
{
|
26
|
+
free(((*(struct vector*)data)).data);
|
27
|
+
free(data);
|
28
|
+
}
|
29
|
+
|
30
|
+
size_t vector_size(const void* data)
|
31
|
+
{
|
32
|
+
return sizeof(struct vector);
|
33
|
+
}
|
34
|
+
|
35
|
+
VALUE vector_alloc(VALUE self)
|
36
|
+
{
|
37
|
+
struct vector* vct = malloc(sizeof(struct vector));
|
38
|
+
vct->data = NULL;
|
39
|
+
return TypedData_Wrap_Struct(self, &vector_type, vct);
|
40
|
+
}
|
41
|
+
|
42
|
+
void c_vector_init(struct vector* vect, int n)
|
43
|
+
{
|
44
|
+
vect->n = n;
|
45
|
+
vect->data = malloc(n * sizeof(double));
|
46
|
+
}
|
47
|
+
|
48
|
+
VALUE vector_initialize(VALUE self, VALUE size)
|
49
|
+
{
|
50
|
+
struct vector* data;
|
51
|
+
int n = raise_rb_value_to_int(size);
|
52
|
+
|
53
|
+
if(n <= 0)
|
54
|
+
rb_raise(fm_eIndexError, "Size cannot be negative or zero");
|
55
|
+
|
56
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
57
|
+
|
58
|
+
c_vector_init(data, n);
|
59
|
+
|
60
|
+
return self;
|
61
|
+
}
|
62
|
+
|
63
|
+
// []=
|
64
|
+
VALUE vector_set(VALUE self, VALUE idx, VALUE v)
|
65
|
+
{
|
66
|
+
int i = raise_rb_value_to_int(idx);
|
67
|
+
double x = raise_rb_value_to_double(v);
|
68
|
+
|
69
|
+
struct vector* data;
|
70
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
71
|
+
|
72
|
+
raise_check_range(i, 0, data->n);
|
73
|
+
|
74
|
+
data->data[i] = x;
|
75
|
+
return v;
|
76
|
+
}
|
77
|
+
|
78
|
+
// []
|
79
|
+
VALUE vector_get(VALUE self, VALUE idx)
|
80
|
+
{
|
81
|
+
int i = raise_rb_value_to_int(idx);
|
82
|
+
|
83
|
+
struct vector* data;
|
84
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
85
|
+
|
86
|
+
raise_check_range(i, 0, data->n);
|
87
|
+
|
88
|
+
return DBL2NUM(data->data[i]);
|
89
|
+
}
|
90
|
+
|
91
|
+
VALUE c_vector_size(VALUE self)
|
92
|
+
{
|
93
|
+
struct vector* data;
|
94
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
95
|
+
return INT2NUM(data->n);
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
VALUE vector_add_with(VALUE self, VALUE value)
|
100
|
+
{
|
101
|
+
struct vector* A;
|
102
|
+
struct vector* B;
|
103
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, A);
|
104
|
+
TypedData_Get_Struct(value, struct vector, &vector_type, B);
|
105
|
+
|
106
|
+
if(A->n != B->n)
|
107
|
+
rb_raise(fm_eIndexError, "Different sizes matrices");
|
108
|
+
|
109
|
+
int n = A->n;
|
110
|
+
|
111
|
+
struct vector* C;
|
112
|
+
VALUE result = TypedData_Make_Struct(cVector, struct vector, &vector_type, C);
|
113
|
+
|
114
|
+
c_vector_init(C, n);
|
115
|
+
add_d_arrays_to_result(n, A->data, B->data, C->data);
|
116
|
+
|
117
|
+
return result;
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
VALUE vector_add_from(VALUE self, VALUE value)
|
122
|
+
{
|
123
|
+
struct vector* A;
|
124
|
+
struct vector* B;
|
125
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, A);
|
126
|
+
TypedData_Get_Struct(value, struct vector, &vector_type, B);
|
127
|
+
|
128
|
+
if(A->n != B->n)
|
129
|
+
rb_raise(fm_eIndexError, "Different sizes matrices");
|
130
|
+
|
131
|
+
int n = A->n;
|
132
|
+
|
133
|
+
add_d_arrays_to_first(n, A->data, B->data);
|
134
|
+
|
135
|
+
return self;
|
136
|
+
}
|
137
|
+
|
138
|
+
VALUE vector_equal(VALUE self, VALUE value)
|
139
|
+
{
|
140
|
+
struct vector* A;
|
141
|
+
struct vector* B;
|
142
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, A);
|
143
|
+
TypedData_Get_Struct(value, struct vector, &vector_type, B);
|
144
|
+
|
145
|
+
if(A->n != B->n)
|
146
|
+
return Qfalse;
|
147
|
+
|
148
|
+
int n = A->n;
|
149
|
+
|
150
|
+
if(equal_d_arrays(n, A->data, B->data))
|
151
|
+
return Qtrue;
|
152
|
+
return Qfalse;
|
153
|
+
}
|
154
|
+
|
155
|
+
VALUE vector_copy(VALUE v)
|
156
|
+
{
|
157
|
+
struct vector* V;
|
158
|
+
TypedData_Get_Struct(v, struct vector, &vector_type, V);
|
159
|
+
|
160
|
+
struct vector* R;
|
161
|
+
VALUE result = TypedData_Make_Struct(cVector, struct vector, &vector_type, R);
|
162
|
+
|
163
|
+
c_vector_init(R, V->n);
|
164
|
+
copy_d_array(R->n, V->data, R->data);
|
165
|
+
|
166
|
+
return result;
|
167
|
+
}
|
168
|
+
|
169
|
+
// V - vector n
|
170
|
+
// M - matrix m x 1
|
171
|
+
// R - matrix m x n
|
172
|
+
void c_vector_matrix_multiply(int n, int m, const double* V, const double* M, double* R)
|
173
|
+
{
|
174
|
+
fill_d_array(m * n, R, 0);
|
175
|
+
|
176
|
+
for(int j = 0; j < n; ++j)
|
177
|
+
{
|
178
|
+
double* p_r = R + m * j;
|
179
|
+
double d_v = V[j];
|
180
|
+
|
181
|
+
for(int i = 0; i < m; ++i)
|
182
|
+
p_r[i] += d_v * M[i];
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
VALUE vector_multiply_vm(VALUE self, VALUE other)
|
187
|
+
{
|
188
|
+
struct vector* V;
|
189
|
+
struct matrix* M;
|
190
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, V);
|
191
|
+
TypedData_Get_Struct(other, struct matrix, &matrix_type, M);
|
192
|
+
|
193
|
+
if(M->n != 1)
|
194
|
+
rb_raise(fm_eIndexError, "Number of rows must be 1");
|
195
|
+
|
196
|
+
int m = M->m;
|
197
|
+
int n = V->n;
|
198
|
+
|
199
|
+
struct matrix* R;
|
200
|
+
VALUE result = TypedData_Make_Struct(cMatrix, struct matrix, &matrix_type, R);
|
201
|
+
|
202
|
+
c_matrix_init(R, m, n);
|
203
|
+
c_vector_matrix_multiply(n, m, V->data, M->data, R->data);
|
204
|
+
|
205
|
+
return result;
|
206
|
+
}
|
207
|
+
|
208
|
+
VALUE vector_multiply_vn(VALUE self, VALUE value)
|
209
|
+
{
|
210
|
+
struct vector* A;
|
211
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, A);
|
212
|
+
|
213
|
+
double d = NUM2DBL(value);
|
214
|
+
|
215
|
+
struct vector* R;
|
216
|
+
VALUE result = TypedData_Make_Struct(cVector, struct vector, &vector_type, R);
|
217
|
+
|
218
|
+
c_vector_init(R, A->n);
|
219
|
+
copy_d_array(R->n, A->data, R->data);
|
220
|
+
multiply_d_array(R->n, R->data, d);
|
221
|
+
|
222
|
+
return result;
|
223
|
+
}
|
224
|
+
|
225
|
+
VALUE vector_multiply_vv(VALUE self, VALUE other)
|
226
|
+
{
|
227
|
+
struct vector* A;
|
228
|
+
struct vector* B;
|
229
|
+
TypedData_Get_Struct(self, struct vector, &vector_type, A);
|
230
|
+
TypedData_Get_Struct(other, struct vector, &vector_type, B);
|
231
|
+
|
232
|
+
if(B->n != 1)
|
233
|
+
rb_raise(fm_eIndexError, "Length of vector must be equal to 1");
|
234
|
+
|
235
|
+
struct vector* R;
|
236
|
+
VALUE result = TypedData_Make_Struct(cVector, struct vector, &vector_type, R);
|
237
|
+
|
238
|
+
c_vector_init(R, A->n);
|
239
|
+
copy_d_array(A->n, A->data, R->data);
|
240
|
+
multiply_d_array(R->n, R->data, B->data[0]);
|
241
|
+
|
242
|
+
return result;
|
243
|
+
}
|
244
|
+
|
245
|
+
VALUE vector_multiply(VALUE self, VALUE v)
|
246
|
+
{
|
247
|
+
if(RB_FLOAT_TYPE_P(v) || FIXNUM_P(v)
|
248
|
+
|| RB_TYPE_P(v, T_BIGNUM))
|
249
|
+
return vector_multiply_vn(self, v);
|
250
|
+
if(RBASIC_CLASS(v) == cMatrix)
|
251
|
+
return vector_multiply_vm(self, v);
|
252
|
+
if(RBASIC_CLASS(v) == cVector)
|
253
|
+
return vector_multiply_vv(self, v);
|
254
|
+
rb_raise(fm_eTypeError, "Invalid klass for multiply");
|
255
|
+
}
|
256
|
+
|
257
|
+
void init_fm_vector()
|
258
|
+
{
|
259
|
+
VALUE mod = rb_define_module("FastMatrix");
|
260
|
+
cVector = rb_define_class_under(mod, "Vector", rb_cData);
|
261
|
+
|
262
|
+
rb_define_alloc_func(cVector, vector_alloc);
|
263
|
+
|
264
|
+
rb_define_method(cVector, "initialize", vector_initialize, 1);
|
265
|
+
rb_define_method(cVector, "[]", vector_get, 1);
|
266
|
+
rb_define_method(cVector, "[]=", vector_set, 2);
|
267
|
+
rb_define_method(cVector, "size", c_vector_size, 0);
|
268
|
+
rb_define_method(cVector, "+", vector_add_with, 1);
|
269
|
+
rb_define_method(cVector, "+=", vector_add_from, 1);
|
270
|
+
rb_define_method(cVector, "==", vector_equal, 1);
|
271
|
+
rb_define_method(cVector, "clone", vector_copy, 0);
|
272
|
+
rb_define_method(cVector, "*", vector_multiply, 1);
|
273
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#ifndef FAST_MATRIX_VECTOR_H
|
2
|
+
#define FAST_MATRIX_VECTOR_H 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
extern VALUE cVector;
|
7
|
+
extern const rb_data_type_t vector_type;
|
8
|
+
|
9
|
+
// vector
|
10
|
+
struct vector
|
11
|
+
{
|
12
|
+
int n;
|
13
|
+
double* data;
|
14
|
+
};
|
15
|
+
|
16
|
+
void c_vector_init(struct vector* vect, int n);
|
17
|
+
|
18
|
+
void init_fm_vector();
|
19
|
+
|
20
|
+
#endif /* FAST_MATRIX_VECTOR_H */
|
data/lib/errors.rb
ADDED
data/lib/fast_matrix.rb
CHANGED
@@ -1,72 +1,3 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
5
|
-
module FastMatrix
|
6
|
-
class Error < StandardError; end
|
7
|
-
|
8
|
-
# Matrix with fast implementations of + - * determinate in C
|
9
|
-
class Matrix
|
10
|
-
|
11
|
-
# Aliases just for compatibility with standard matrix
|
12
|
-
#
|
13
|
-
# Returns the number of rows.
|
14
|
-
#
|
15
|
-
alias_method :row_size, :row_count
|
16
|
-
#
|
17
|
-
# Returns the number of columns.
|
18
|
-
#
|
19
|
-
alias_method :column_size, :column_count
|
20
|
-
|
21
|
-
#
|
22
|
-
# Create fast matrix from standard matrix
|
23
|
-
#
|
24
|
-
def self.convert(matrix)
|
25
|
-
fast_matrix = Matrix.new(matrix.row_count, matrix.column_count)
|
26
|
-
(0...matrix.row_count).each do |i|
|
27
|
-
(0...matrix.column_count).each do |j|
|
28
|
-
fast_matrix[i, j] = matrix[i, j]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
fast_matrix
|
32
|
-
end
|
33
|
-
|
34
|
-
def each_with_index
|
35
|
-
(0...row_count).each do |i|
|
36
|
-
(0...column_count).each do |j|
|
37
|
-
yield self[i, j], i, j
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def each_with_index!
|
43
|
-
(0...row_count).each do |i|
|
44
|
-
(0...column_count).each do |j|
|
45
|
-
self[i, j] = yield self[i, j], i, j
|
46
|
-
end
|
47
|
-
end
|
48
|
-
self
|
49
|
-
end
|
50
|
-
|
51
|
-
#
|
52
|
-
# Convert to standard ruby matrix.
|
53
|
-
#
|
54
|
-
def convert
|
55
|
-
::Matrix.build(row_size, column_size) { |i, j| self[i, j] }
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
# FIXME for compare with standard matrix
|
60
|
-
def ==(other)
|
61
|
-
# TODO check class and use fast compare from C if possibly
|
62
|
-
return false unless %i[row_size column_size \[\]].all? { |x| other.respond_to? x }
|
63
|
-
return false unless self.row_size == other.row_size && self.column_size == other.column_size
|
64
|
-
|
65
|
-
result = true
|
66
|
-
each_with_index do |elem, i, j|
|
67
|
-
result &&= elem == other[i, j].to_f
|
68
|
-
end
|
69
|
-
result
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
1
|
+
require 'fast_matrix/version'
|
2
|
+
require 'vector/vector'
|
3
|
+
require 'matrix/matrix'
|
data/lib/fast_matrix/version.rb
CHANGED
@@ -0,0 +1,253 @@
|
|
1
|
+
require 'fast_matrix/fast_matrix'
|
2
|
+
require 'errors'
|
3
|
+
|
4
|
+
module FastMatrix
|
5
|
+
#
|
6
|
+
# Constructors as in the standard matrix
|
7
|
+
#
|
8
|
+
class Matrix
|
9
|
+
|
10
|
+
#
|
11
|
+
# Creates a matrix of size +row_count+ x +column_count+.
|
12
|
+
# It fills the values by calling the given block,
|
13
|
+
# passing the current row and column.
|
14
|
+
# Returns random matrix if no block is given.
|
15
|
+
#
|
16
|
+
# m = Matrix.build(2, 4) {|row, col| col - row }
|
17
|
+
# => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
|
18
|
+
# m = Matrix.build(3) { rand }
|
19
|
+
# => a 3x3 matrix with random elements
|
20
|
+
#
|
21
|
+
def self.build(row_count, column_count = row_count, &block)
|
22
|
+
check_dimensions(row_count, column_count)
|
23
|
+
matrix = self.new(row_count, column_count)
|
24
|
+
matrix.each_with_index! { |_, i, j| block.call(i, j) } if block_given?
|
25
|
+
matrix
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Creates a matrix where +rows+ is an array of arrays, each of which is a row
|
30
|
+
# of the matrix.
|
31
|
+
# The optional argument +copy+ exists only for compatibility with standard.
|
32
|
+
# The optional argument +copy+ cannot be false, unlike standard.
|
33
|
+
# Matrix.rows([[25, 93], [-1, 66]])
|
34
|
+
# => 25 93
|
35
|
+
# -1 66
|
36
|
+
#
|
37
|
+
def self.rows(rows, copy = true)
|
38
|
+
check_flag_copy(copy)
|
39
|
+
lines(rows, true)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Creates a matrix using +columns+ as an array of column vectors.
|
44
|
+
# Matrix.columns([[25, 93], [-1, 66]])
|
45
|
+
# => 25 -1
|
46
|
+
# 93 66
|
47
|
+
#
|
48
|
+
def self.columns(columns)
|
49
|
+
lines(columns, false)
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Creates a matrix where each argument is a row.
|
54
|
+
# Matrix[ [25, 93], [-1, 66] ]
|
55
|
+
# => 25 93
|
56
|
+
# -1 66
|
57
|
+
#
|
58
|
+
def self.[](*rows)
|
59
|
+
self.rows(rows)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Creates a single-column matrix where the values of that column are as given
|
64
|
+
# in +column+.
|
65
|
+
# Matrix.column_vector([4,5,6])
|
66
|
+
# => 4
|
67
|
+
# 5
|
68
|
+
# 6
|
69
|
+
#
|
70
|
+
def self.column_vector(column)
|
71
|
+
matrix = Matrix.build(column.size, 1)
|
72
|
+
column.each_with_index { |elem, i| matrix[i, 0] = elem }
|
73
|
+
matrix
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Creates a single-row matrix where the values of that row are as given in
|
78
|
+
# +row+.
|
79
|
+
# Matrix.row_vector([4,5,6])
|
80
|
+
# => 4 5 6
|
81
|
+
#
|
82
|
+
def self.row_vector(row)
|
83
|
+
matrix = Matrix.build(1, row.size)
|
84
|
+
row.each_with_index { |elem, j| matrix[0, j] = elem }
|
85
|
+
matrix
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Creates a matrix where the diagonal elements are composed of +values+.
|
90
|
+
# Matrix.diagonal(9, 5, -3)
|
91
|
+
# => 9 0 0
|
92
|
+
# 0 5 0
|
93
|
+
# 0 0 -3
|
94
|
+
#
|
95
|
+
def self.diagonal(*values)
|
96
|
+
matrix = Matrix.build(values.size, values.size) { |i, j| i == j ? values[i] : 0 }
|
97
|
+
matrix
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Creates an +n+ by +n+ diagonal matrix where each diagonal element is
|
102
|
+
# +value+.
|
103
|
+
# Matrix.scalar(2, 5)
|
104
|
+
# => 5 0
|
105
|
+
# 0 5
|
106
|
+
#
|
107
|
+
def self.scalar(n, value)
|
108
|
+
Matrix.build(n, n) { |i, j| i == j ? value : 0 }
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Creates an +n+ by +n+ identity matrix.
|
113
|
+
# Matrix.identity(2)
|
114
|
+
# => 1 0
|
115
|
+
# 0 1
|
116
|
+
#
|
117
|
+
def self.identity(n)
|
118
|
+
scalar(n, 1)
|
119
|
+
end
|
120
|
+
class << Matrix
|
121
|
+
alias unit identity
|
122
|
+
alias I identity
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# Creates a zero matrix +n+ by +n+.
|
127
|
+
# Matrix.zero(2)
|
128
|
+
# => 0 0
|
129
|
+
# 0 0
|
130
|
+
#
|
131
|
+
def self.zero(n)
|
132
|
+
Matrix.build(n, n) { 0 }
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Empty matrices does not supported
|
137
|
+
#
|
138
|
+
def self.empty(_ = 0, _ = 0)
|
139
|
+
raise NotSupportedError, 'Empty matrices does not supported'
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Create a matrix by stacking matrices vertically
|
144
|
+
#
|
145
|
+
# x = Matrix[[1, 2], [3, 4]]
|
146
|
+
# y = Matrix[[5, 6], [7, 8]]
|
147
|
+
# Matrix.vstack(x, y) # => Matrix[[1, 2], [3, 4], [5, 6], [7, 8]]
|
148
|
+
# TODO: optimize (maybe in C)
|
149
|
+
def self.vstack(x, *matrices)
|
150
|
+
column_count = x.column_count
|
151
|
+
row_count = x.row_count
|
152
|
+
matrices.each do |matrix|
|
153
|
+
raise IndexError unless matrix.column_count == column_count
|
154
|
+
|
155
|
+
row_count += matrix.row_count
|
156
|
+
end
|
157
|
+
result = new(row_count, column_count)
|
158
|
+
m_i = 0
|
159
|
+
[x, *matrices].each do |matrix|
|
160
|
+
matrix.each_with_index do |elem, i, j|
|
161
|
+
result[m_i + i, j] = elem
|
162
|
+
end
|
163
|
+
m_i += matrix.row_count
|
164
|
+
end
|
165
|
+
result
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Create a matrix by stacking matrices horizontally
|
170
|
+
#
|
171
|
+
# x = Matrix[[1, 2], [3, 4]]
|
172
|
+
# y = Matrix[[5, 6], [7, 8]]
|
173
|
+
# Matrix.hstack(x, y) # => Matrix[[1, 2, 5, 6], [3, 4, 7, 8]]
|
174
|
+
#
|
175
|
+
def self.hstack(x, *matrices)
|
176
|
+
column_count = x.column_count
|
177
|
+
row_count = x.row_count
|
178
|
+
matrices.each do |matrix|
|
179
|
+
raise IndexError unless matrix.row_count == row_count
|
180
|
+
|
181
|
+
column_count += matrix.column_count
|
182
|
+
end
|
183
|
+
result = new(row_count, column_count)
|
184
|
+
m_j = 0
|
185
|
+
[x, *matrices].each do |matrix|
|
186
|
+
matrix.each_with_index do |elem, i, j|
|
187
|
+
result[i, m_j + j] = elem
|
188
|
+
end
|
189
|
+
m_j += matrix.column_count
|
190
|
+
end
|
191
|
+
result
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# Create a matrix by combining matrices entrywise, using the given block
|
196
|
+
#
|
197
|
+
# x = Matrix[[6, 6], [4, 4]]
|
198
|
+
# y = Matrix[[1, 2], [3, 4]]
|
199
|
+
# Matrix.combine(x, y) {|a, b| a - b} # => Matrix[[5, 4], [1, 0]]
|
200
|
+
# TODO: optimize in C
|
201
|
+
def self.combine(*matrices)
|
202
|
+
return Matrix.empty if matrices.empty?
|
203
|
+
|
204
|
+
result = convert(matrices.first)
|
205
|
+
matrices[1..matrices.size].each do |m|
|
206
|
+
raise IndexError unless result.row_count == m.row_count &&
|
207
|
+
result.column_count == m.column_count
|
208
|
+
|
209
|
+
result.each_with_index! { |elem, i, j| yield elem, m[i, j] }
|
210
|
+
end
|
211
|
+
result
|
212
|
+
end
|
213
|
+
|
214
|
+
class << Matrix
|
215
|
+
private
|
216
|
+
|
217
|
+
def check_empty_matrix(row_count, column_count)
|
218
|
+
empty if row_count.zero? || column_count.zero?
|
219
|
+
end
|
220
|
+
|
221
|
+
def check_negative_sizes(row_count, column_count)
|
222
|
+
raise IndexError if column_count.negative? || row_count.negative?
|
223
|
+
end
|
224
|
+
|
225
|
+
def check_dimensions(row_count, column_count)
|
226
|
+
check_empty_matrix(row_count, column_count)
|
227
|
+
check_negative_sizes(row_count, column_count)
|
228
|
+
end
|
229
|
+
|
230
|
+
def check_flag_copy(copy)
|
231
|
+
unless copy
|
232
|
+
raise NotSupportedError, "Can't create matrix without copy elements"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# generalization between ::rows and ::columns
|
237
|
+
def lines(lines, main_is_rows)
|
238
|
+
sizes = [lines.size, (lines[0] || []).size]
|
239
|
+
offset = main_is_rows ? 0 : -1
|
240
|
+
matrix = build(sizes[offset], sizes[1 + offset])
|
241
|
+
lines.each_with_index do |second_dim, main_index|
|
242
|
+
raise IndexError if second_dim.size != sizes[1]
|
243
|
+
|
244
|
+
second_dim.each_with_index do |elem, second_index|
|
245
|
+
indices = [main_index, second_index]
|
246
|
+
matrix[indices[offset], indices[1 + offset]] = elem
|
247
|
+
end
|
248
|
+
end
|
249
|
+
matrix
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|