fast_matrix 0.1.4 → 0.1.5
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 +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
|