matrix_gem 0.1.0 → 0.2.0
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/Rakefile +12 -0
- data/lib/matrix_gem/diagonal_matrix.rb +109 -0
- data/lib/matrix_gem/matrix.rb +371 -0
- data/lib/matrix_gem/matrix_err.rb +6 -1
- data/lib/matrix_gem/orthogonal_matrix.rb +26 -0
- data/lib/matrix_gem/properties_module.rb +92 -8
- data/lib/matrix_gem.rb +5 -304
- metadata +49 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc7ba70b852af0c334f8206cd216b1ff2dbf4d33
|
4
|
+
data.tar.gz: 8ce5d4a3281b74f3920886c427c6d9a22791fea4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc66b52f0908a2c87e4e15492cddd2ddc3648bbd2bee0907785a2c2730d0bca7b429e7eefef20ee901dcdd90d109a5e2d7df7244cb805237f6e6ec1b35a2921e
|
7
|
+
data.tar.gz: 0071e0d34d392db460c59645dd49f7b23b6ed6e556f78258ee3d1403d126ad8562b9a53e50f1e869b9d51f761badc1698a74badf9d0b852b462761947f6adb32
|
data/Rakefile
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Diagonal_Matrix < Matrix
|
4
|
+
|
5
|
+
# Creates a matrix by given rows, columns, and nums where the diagonal elements are composed of nums.
|
6
|
+
# With given only rows create identity matrix.
|
7
|
+
def initialize(rows, cols = nil, *nums)
|
8
|
+
if cols == nil
|
9
|
+
@matrix = identity rows
|
10
|
+
elsif nums.length != [rows, cols].min
|
11
|
+
raise MatrixArgumentError,
|
12
|
+
"Wrong number of arguments (#{2 + nums.length} for #{2 + [rows, cols].min})"
|
13
|
+
else
|
14
|
+
@matrix = []
|
15
|
+
rows.times do |row|
|
16
|
+
@matrix[row] = []
|
17
|
+
cols.times do |col|
|
18
|
+
if row == col
|
19
|
+
@matrix[row][col] = nums[row]
|
20
|
+
else
|
21
|
+
@matrix[row][col] = 0
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
# Creates a matrix where the diagonal elements are composed of nums.
|
30
|
+
def diagonal(*nums)
|
31
|
+
size = nums.length
|
32
|
+
Diagonal_Matrix.new size, size, *(nums)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a zero matrix with dimension equal to n.
|
36
|
+
def zero(n)
|
37
|
+
Diagonal_Matrix.diagonal(*(Array.new(n, 0)))
|
38
|
+
end
|
39
|
+
|
40
|
+
def identity(n)
|
41
|
+
Diagonal_Matrix.new n
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set element on main diagonal
|
46
|
+
def []=(i, j = nil, value)
|
47
|
+
if j != nil && i != j
|
48
|
+
raise MatrixIndexOutOfRange,
|
49
|
+
"You can set only elements on main diagonal in a diagonal matrix."
|
50
|
+
elsif @matrix.size <= i
|
51
|
+
raise MatrixIndexOutOfRange
|
52
|
+
end
|
53
|
+
@matrix[i][i] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sum values on main diagonal of two matrices.
|
57
|
+
# Raises error if 'matrix' is not a Matrix or if matrices dimensions mismatch.
|
58
|
+
def +(matrix)
|
59
|
+
sum_validation(self, matrix)
|
60
|
+
values = self.diagonal_values.zip(matrix.diagonal_values).map{ |i| i.inject(:+) }
|
61
|
+
Diagonal_Matrix.new self.m, self.n, *(values)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the difference of values on main diagonal of two matrices in new matrix.
|
65
|
+
# Raises error if 'matrix' is not a Matrix or if matrices dimensions mismatch.
|
66
|
+
def -(matrix)
|
67
|
+
sum_validation(self, matrix)
|
68
|
+
values = self.diagonal_values.zip(matrix.diagonal_values).map{ |i| i.inject(:-) }
|
69
|
+
|
70
|
+
Diagonal_Matrix.new self.m, self.n, *(values)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Matrix multiplication. Returns new instance of Diagonal_Matrix.
|
74
|
+
# Raises error if product can't be instance of Diagonal_Matrix.
|
75
|
+
def *(matrix)
|
76
|
+
product = super(matrix)
|
77
|
+
raise MatrixInvalidValue, "Product of multiplication is not diagonal matrix." if product.diagonal?
|
78
|
+
|
79
|
+
Diagonal_Matrix.new(product.m, product.n, *(product.diagonal_values))
|
80
|
+
end
|
81
|
+
|
82
|
+
# Matrix division (multiplication by the inverse).
|
83
|
+
# Raises error if difference can't be instance of Diagonal_Matrix.
|
84
|
+
# Raises error if matrix is not invertible.
|
85
|
+
def /(matrix)
|
86
|
+
diff = super(matrix)
|
87
|
+
raise MatrixInvalidValue, "Difference of matrices in not a diagonal matrix." if diff.diagonal?
|
88
|
+
|
89
|
+
Diagonal_Matrix.new(diff.m, diff.n, *(diff.diagonal_values))
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the determinant of the matrix.
|
93
|
+
def det
|
94
|
+
is_square_validation self
|
95
|
+
self.diagonal_values.reduce(:*)
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def non_main_diagonal_elements?(matrix)
|
101
|
+
matrix.m.times do |i|
|
102
|
+
matrix.n.times do |j|
|
103
|
+
return true if ((i != j) && (matrix[i,j] != 0))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,371 @@
|
|
1
|
+
class Matrix
|
2
|
+
include MatrixErr
|
3
|
+
include Properties
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
#---------Initialize the matrix--------
|
7
|
+
# 1. Matrix with values
|
8
|
+
# Matrix.new(rows, cols, numbers) // numbers = rows*cols
|
9
|
+
# 2. Matrix only with dimension(rows and cols) make Identity matrix with dimension
|
10
|
+
# equal to rows
|
11
|
+
# Matrix.new(rows, cols)
|
12
|
+
def initialize(rows, cols, *nums)
|
13
|
+
if rows < 1 || cols < 1
|
14
|
+
raise MatrixArgumentError, "Rows and Columns should be positive numbers!"
|
15
|
+
elsif ((cols.is_a? Float) || (rows.is_a? Float))
|
16
|
+
raise MatrixArgumentError, "Dimension of matrix can't be floating point number"
|
17
|
+
elsif nums.length == 0
|
18
|
+
@matrix = identity rows
|
19
|
+
elsif rows * cols == nums.length
|
20
|
+
@matrix = matrix_with_values nums, cols
|
21
|
+
else
|
22
|
+
raise MatrixArgumentError,
|
23
|
+
"Wrong number of arguments (#{2 + nums.length} for #{2 + rows * cols})"
|
24
|
+
end
|
25
|
+
@matrix
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
# Creates an n by n zero matrix.
|
31
|
+
def zero(n)
|
32
|
+
values = Array.new(n*n, 0)
|
33
|
+
Matrix.new n, n, *(values)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Creates a matrix where the diagonal elements are composed of values.
|
37
|
+
def diagonal(*nums)
|
38
|
+
raise ArgumentError, "Matrix values can't be nil" if nums.include? nil
|
39
|
+
size = nums.length
|
40
|
+
matrix_values = []
|
41
|
+
Array.new(size) { |i| Array.new(size) do |j|
|
42
|
+
if i == j
|
43
|
+
matrix_values << nums[i]
|
44
|
+
else
|
45
|
+
matrix_values << 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
}
|
49
|
+
Matrix.new(size, size, *(matrix_values))
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates an n by n identity matrix.
|
53
|
+
def identity(n)
|
54
|
+
Matrix.new n, n
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the sum of two matrices in new matrix
|
59
|
+
# Raises an error if matrices dimension mismatch.
|
60
|
+
def +(matrix)
|
61
|
+
sum_validation(self, matrix)
|
62
|
+
values = self.zip(matrix).map{ |i| i.inject(:+) }
|
63
|
+
|
64
|
+
Matrix.new self.m, self.n, *(values)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return the difference of two matrices in new matrix.
|
68
|
+
# Raises an error if matrices dimension mismatch.
|
69
|
+
def -(matrix)
|
70
|
+
sum_validation(self, matrix)
|
71
|
+
values = self.zip(matrix).map{|i| i.inject(:-)}
|
72
|
+
|
73
|
+
Matrix.new self.m, self.n, *(values)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Matrix multiplication.
|
77
|
+
def *(matrix)
|
78
|
+
case(matrix)
|
79
|
+
when Numeric
|
80
|
+
new_matrix_values = []
|
81
|
+
self.each { |x| new_matrix_values << x * matrix }
|
82
|
+
Matrix.new self.m, self.n, *(new_matrix_values)
|
83
|
+
when Matrix
|
84
|
+
multiply_validation self, matrix
|
85
|
+
rows = Array.new(self.m) { |i|
|
86
|
+
Array.new(matrix.n) { |j|
|
87
|
+
(0 ... self.n).inject(0) do |vij, k|
|
88
|
+
vij + self[i, k] * matrix[k, j]
|
89
|
+
end
|
90
|
+
}
|
91
|
+
}
|
92
|
+
values = []
|
93
|
+
rows.each{ |x| x.each { |y| values << y} }
|
94
|
+
Matrix.new self.m, matrix.n, *(values)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Matrix division (multiplication by the inverse).
|
99
|
+
def /(matrix)
|
100
|
+
case matrix
|
101
|
+
when Numeric
|
102
|
+
new_matrix_values = []
|
103
|
+
self.each { |x| new_matrix_values << x / matrix.to_f }
|
104
|
+
Matrix.new self.m, self.n, *(new_matrix_values)
|
105
|
+
when Matrix
|
106
|
+
self * matrix.inversed
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns element (i,j) of the matrix. That is: row i, column j.
|
111
|
+
# If only i is given return row[i]. That is: row with index i.
|
112
|
+
def [](i, j = nil)
|
113
|
+
if j == nil
|
114
|
+
@matrix[i]
|
115
|
+
else
|
116
|
+
@matrix[i][j]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Set element (i,j) of the matrix. That is: row i, column j.
|
121
|
+
# Set row i of the matrix if j is not given. That is: column j.
|
122
|
+
# Also aliased as set_element
|
123
|
+
def []=(i, j = nil, val)
|
124
|
+
if j == nil
|
125
|
+
raise ErrDimensionMismatch if val.length != self.m
|
126
|
+
@matrix[i] = val
|
127
|
+
elsif (i < self.m && j < self.n)
|
128
|
+
@matrix[i][j] = val
|
129
|
+
end
|
130
|
+
end
|
131
|
+
alias set_element []=
|
132
|
+
|
133
|
+
# Return a new matrix which is the transposition of the given one.
|
134
|
+
def transposed
|
135
|
+
elements = []
|
136
|
+
@matrix.to_a.transpose.map{ |x| x.map{ |y| elements << y } }
|
137
|
+
Matrix.new self.m, self.n, *(elements)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Transpose the matrix.
|
141
|
+
# Also aliased as t().
|
142
|
+
def transpose
|
143
|
+
elements = []
|
144
|
+
@matrix.to_a.transpose.map{ |x| x.map{ |y| elements << y } }
|
145
|
+
@matrix = elements.each_slice(@matrix[0].length).to_a
|
146
|
+
self
|
147
|
+
end
|
148
|
+
alias t transpose
|
149
|
+
|
150
|
+
#Each method.
|
151
|
+
def each
|
152
|
+
@matrix.each do |sub_arr|
|
153
|
+
sub_arr.each do |value|
|
154
|
+
yield value
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns true if and only if the two matrices contain equal elements.
|
160
|
+
def ==(matrix)
|
161
|
+
(0..self.m-1).each do |i|
|
162
|
+
(0..self.n-1).each do |j|
|
163
|
+
return false if self[i][j] != matrix[i][j]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns the determinant of the matrix.
|
170
|
+
# Also alised as determinant()
|
171
|
+
def det
|
172
|
+
is_square_validation self
|
173
|
+
|
174
|
+
_this = copy(self)
|
175
|
+
c = 1
|
176
|
+
new_matrix = nil
|
177
|
+
size = _this.n
|
178
|
+
|
179
|
+
(0..size - 2).each do |i|
|
180
|
+
(i + 1..size -1).each do |j|
|
181
|
+
if _this[i][i] == 0
|
182
|
+
(i+1..size-1).each do |k|
|
183
|
+
if _this[k,i] != 0
|
184
|
+
swap_rows(_this, k, i)
|
185
|
+
c *= -1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
if _this[i,i] == 0
|
190
|
+
return 0
|
191
|
+
end
|
192
|
+
|
193
|
+
new_matrix = cauchy_method(_this, i, j, -_this[j,i]/_this[i,i].to_f)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
det = 1
|
198
|
+
|
199
|
+
(0..size-1).each do |i|
|
200
|
+
det *= new_matrix[i][i]
|
201
|
+
end
|
202
|
+
|
203
|
+
det *= c
|
204
|
+
det.round
|
205
|
+
end
|
206
|
+
alias determinant det
|
207
|
+
|
208
|
+
# Returns new matrix witch is the inverse of the matrix.
|
209
|
+
def inversed
|
210
|
+
is_square_validation self
|
211
|
+
raise ErrZeroDeterminant if self.det == 0
|
212
|
+
|
213
|
+
_this = copy(self)
|
214
|
+
c = 1
|
215
|
+
e = Matrix.new _this.m, _this.n
|
216
|
+
size = _this.m
|
217
|
+
|
218
|
+
(0..size-2).each do |i|
|
219
|
+
(i+1..size-1).each do |j|
|
220
|
+
if _this[i, i] == 0
|
221
|
+
(i..size-2).each do |k|
|
222
|
+
if _this[k, i] != 0
|
223
|
+
swap_rows(_this, k, i)
|
224
|
+
swap_rows(e, k, i)
|
225
|
+
c *= -1
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
return 0 if _this[i, i] == 0
|
231
|
+
|
232
|
+
cauchy_method(e, i, j, -_this[j, i]/_this[i, i].to_f)
|
233
|
+
cauchy_method(_this, i, j, -_this[j, i]/_this[i, i].to_f)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
(0..size-2).each do |i|
|
238
|
+
(i+1..size-1).each do |j|
|
239
|
+
|
240
|
+
cauchy_method(e, size-i-1, size-j-1, -_this[size-j-1, size-i-1]/_this[size-i-1, size-i-1])
|
241
|
+
|
242
|
+
cauchy_method(_this, size-i-1, size-j-1, -_this[size-j-1, size-i-1]/_this[size-i-1, size-i-1])
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
(0..size-1).each do |i|
|
247
|
+
e.set_row i, multiply_row(e, i, 1/_this[i,i])
|
248
|
+
_this.set_row i, multiply_row(_this, i, 1/_this[i,i])
|
249
|
+
end
|
250
|
+
Matrix.new self.m, self.m, *(e)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Chanege matrix to its inversed.
|
254
|
+
def inverse
|
255
|
+
elements = []
|
256
|
+
self.inversed.each{ |x| elements << x}
|
257
|
+
@matrix = elements.each_slice(@matrix[0].length).to_a
|
258
|
+
self
|
259
|
+
end
|
260
|
+
|
261
|
+
# To stirng method.
|
262
|
+
def to_str
|
263
|
+
a = "Matrix\n" + @matrix.map do |row|
|
264
|
+
"[" + row.map do |e|
|
265
|
+
e.to_s
|
266
|
+
end.join(" ") + "]"
|
267
|
+
end.join(",\n")
|
268
|
+
puts a
|
269
|
+
end
|
270
|
+
|
271
|
+
# Matrix exponentiation. Equivalent to multiplying the matrix by itself N times.
|
272
|
+
def **(n)
|
273
|
+
raise MatrixArgumentError if !(n.is_a? Integer)
|
274
|
+
matrix = Matrix.identity(self.m)
|
275
|
+
n.times { |_| matrix *= self } if self.square?
|
276
|
+
matrix
|
277
|
+
end
|
278
|
+
|
279
|
+
def minor(*param)
|
280
|
+
row_range, col_range = param
|
281
|
+
|
282
|
+
from_row = row_range.first
|
283
|
+
form_row += self.m if from_row < 0
|
284
|
+
to_row = row_range.end
|
285
|
+
to_row += self.m if to_row < 0
|
286
|
+
to_row += 1 unless row_range.exclude_end?
|
287
|
+
size_row = to_row - from_row
|
288
|
+
|
289
|
+
from_col = col_range.first
|
290
|
+
from_col += self.n if from_col < 0
|
291
|
+
to_col = col_range.end
|
292
|
+
to_col += self.n if from_col < 0
|
293
|
+
to_col += 1 unless col_range.exclude_end?
|
294
|
+
size_col = to_col - from_col
|
295
|
+
return nil if from_row > row_count || from_col > column_count ||
|
296
|
+
from_row < 0 || from_col < 0
|
297
|
+
rows = @matrix[from_row, size_row].collect{ |row| row[from_col, size_col] }
|
298
|
+
values = []
|
299
|
+
rows.each{ |row| row.each {|val| values << val } }
|
300
|
+
Matrix.new [self.m - from_row, size_row].min, [self.n - from_col, size_col].min, *(values)
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
# Swap to matrix rows.
|
306
|
+
def swap_rows(_this, row1_index, row2_index)
|
307
|
+
_this[row1_index], _this[row2_index] = _this[row2_index], _this[row1_index]
|
308
|
+
end
|
309
|
+
|
310
|
+
# Return new instance of Matrix with same values.
|
311
|
+
def copy(_this)
|
312
|
+
values = []
|
313
|
+
_this.each{ |row| values << row }
|
314
|
+
copy = Matrix.new _this.m, _this.n, *(values)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Multiply the first row elements with multiplier and sum it with second row
|
318
|
+
# elements.
|
319
|
+
# Used to make matrix in triangular form.
|
320
|
+
def cauchy_method(_this, row1_index, row2_index, multiplier)
|
321
|
+
_this.row(row2_index).each_with_index do |row_element, i|
|
322
|
+
_this.row(row2_index)[i] += _this[row1_index][i] * multiplier
|
323
|
+
end
|
324
|
+
_this
|
325
|
+
end
|
326
|
+
|
327
|
+
# Check if caller matrix columns are equal to other matrix rows.
|
328
|
+
def multiply_validation(_this, matrix)
|
329
|
+
raise ErrDimensionMismatch if _this.col_size != matrix.row_size
|
330
|
+
end
|
331
|
+
|
332
|
+
# Check if matrix rows are equals to its columns.
|
333
|
+
def is_square_validation(_this)
|
334
|
+
raise NoSquareMatrix if _this.m != _this.n
|
335
|
+
end
|
336
|
+
|
337
|
+
# Check if matrices have same dimensions.
|
338
|
+
def sum_validation(_this, matrix)
|
339
|
+
raise ErrOperationNotDefine if !matrix.is_a? Matrix
|
340
|
+
raise ErrDimensionMismatch if matrix.m != _this.m || matrix.n != _this.n
|
341
|
+
end
|
342
|
+
|
343
|
+
# Make Identity matrix.
|
344
|
+
def identity(dimension)
|
345
|
+
id_matrix = []
|
346
|
+
dimension.times do |x|
|
347
|
+
id_matrix[x] = []
|
348
|
+
dimension.times do |y|
|
349
|
+
if x == y
|
350
|
+
id_matrix[x][y] = 1
|
351
|
+
else
|
352
|
+
id_matrix[x][y] = 0
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
return id_matrix
|
357
|
+
end
|
358
|
+
|
359
|
+
# Multiplication of matrix row with number.
|
360
|
+
def multiply_row(matrix, index, number)
|
361
|
+
matrix = matrix.row(index).map{ |n| n * number }
|
362
|
+
end
|
363
|
+
|
364
|
+
# Format values.
|
365
|
+
def matrix_with_values(values, col_length)
|
366
|
+
matrixNums = values.each_slice(col_length).to_a
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
|
@@ -3,9 +3,15 @@ module MatrixErr
|
|
3
3
|
class Matrix_Error < StandardError
|
4
4
|
end
|
5
5
|
|
6
|
+
class MatrixInvalidValue < StandardError
|
7
|
+
end
|
8
|
+
|
6
9
|
class MatrixArgumentError < Matrix_Error
|
7
10
|
end
|
8
11
|
|
12
|
+
class MatrixIndexOutOfRange < Matrix_Error
|
13
|
+
end
|
14
|
+
|
9
15
|
class ErrOperationNotDefine < Matrix_Error
|
10
16
|
def message
|
11
17
|
"Operation is not define!"
|
@@ -29,5 +35,4 @@ module MatrixErr
|
|
29
35
|
"Matrix determinant should be not equal to zero!"
|
30
36
|
end
|
31
37
|
end
|
32
|
-
|
33
38
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Orthogonal_Matrix < Matrix
|
2
|
+
|
3
|
+
# Initialize orthogonal matrix (square matrix and its transpose is equal to its inverse).
|
4
|
+
def initialize(rows, cols, *nums)
|
5
|
+
if !(Matrix.new rows, cols, *(nums)).orthogonal?
|
6
|
+
raise MatrixArgumentError,
|
7
|
+
"Can't initialize orthogonal matrix with this values."
|
8
|
+
elsif nums.length == 0
|
9
|
+
@matrix = identity rows
|
10
|
+
else
|
11
|
+
@matrix = matrix_with_values nums, cols
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Set element.
|
16
|
+
# Raise error if the matrix with new value is not orthogonal.
|
17
|
+
def []=(i, j, value)
|
18
|
+
b = copy(self)
|
19
|
+
b[i,j] = value
|
20
|
+
if b.orthogonal?
|
21
|
+
@matrix[i][j] = value
|
22
|
+
else
|
23
|
+
raise MatrixIndexOutOfRange, 'The matrix must be orthogonal.'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,9 +1,44 @@
|
|
1
1
|
module Properties
|
2
|
+
|
3
|
+
include MatrixErr
|
4
|
+
|
2
5
|
# Returns an array of arrays that describe the rows of the matrix.
|
3
6
|
def to_a
|
4
7
|
self
|
5
8
|
end
|
6
9
|
|
10
|
+
# Make all values floating point.
|
11
|
+
def to_f
|
12
|
+
(0..self.n - 1).each{ |i| (0..self.m - 1).each do
|
13
|
+
|j| self[i,j] = self[i,j].to_f
|
14
|
+
end }
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return array with values on main diagonal.
|
19
|
+
def diagonal_values
|
20
|
+
size = ([self.m, self.n].min) -1
|
21
|
+
values = []
|
22
|
+
|
23
|
+
(0..size).each do |i|
|
24
|
+
values << self[i][i]
|
25
|
+
end
|
26
|
+
values
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set values on main diagonal.
|
30
|
+
# Raise error if nums are less than matrix main diagonal length
|
31
|
+
# Also aliased as set_diagonal_values
|
32
|
+
def set_diagonal(*nums)
|
33
|
+
size = ([self.m, self.n].min) -1
|
34
|
+
raise MatrixArgumentError, 'Wrong number of arguments.' if nums.length < size + 1
|
35
|
+
(0..size).each do |i|
|
36
|
+
self[i,i] = nums[i]
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
alias set_diagonal_values set_diagonal
|
41
|
+
|
7
42
|
# Returns the number of columns.
|
8
43
|
# Also aliased as n(), col_size(), column_count()
|
9
44
|
def col_length
|
@@ -27,21 +62,70 @@ module Properties
|
|
27
62
|
alias col_size col_length
|
28
63
|
alias column_count n
|
29
64
|
|
30
|
-
#
|
65
|
+
# Retuns array with row on index as values.
|
31
66
|
def row(index)
|
32
67
|
self[index]
|
33
68
|
end
|
34
69
|
|
35
|
-
#
|
36
|
-
|
70
|
+
# Returns array with column on index as values.
|
71
|
+
# Also aliased as column()
|
72
|
+
def col(index)
|
73
|
+
column = []
|
74
|
+
(0..self.m-1).each{ |x| column << self[x, index] }
|
75
|
+
column
|
76
|
+
end
|
77
|
+
alias column col
|
78
|
+
|
79
|
+
# Set values of matrix row. Elements shoud be an array of values
|
80
|
+
# Raise error if length of elements is not equal to matrix row length.
|
81
|
+
def set_row(index, elements)
|
82
|
+
raise MatrixArgumentError, 'Different length of elements and row length' if
|
83
|
+
elements.length != self.row_length
|
37
84
|
self[index] = elements
|
85
|
+
self
|
38
86
|
end
|
39
87
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
def
|
43
|
-
|
88
|
+
# Set values of matrix column. Elements shoud be an array of values.
|
89
|
+
# Raise error if length of elements is not equal to matrix column length.
|
90
|
+
def set_col(index, elements)
|
91
|
+
raise MatrixArgumentError, 'Different length of elements and column length' if elements.length != self.col_length
|
92
|
+
(0..self.m-1).each{ |x| self[x, index] = elements[x] }
|
93
|
+
self
|
44
94
|
end
|
45
95
|
|
46
|
-
|
96
|
+
# Returns true if there is values not equal to 0 only on main diagonal.
|
97
|
+
# Also aliased as diagonal?
|
98
|
+
def is_diagonal
|
99
|
+
(0..self.m-1).each do |i|
|
100
|
+
(0..self.m-1).each do |j|
|
101
|
+
return false if ((self[i,j] != 0 && i != j))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
true
|
105
|
+
end
|
106
|
+
alias diagonal? is_diagonal
|
107
|
+
|
108
|
+
# Returns true if this is a matrix with only zero elements.
|
109
|
+
# Also aliased as is_zero
|
110
|
+
def zero?
|
111
|
+
self.map{ |x| return false if x != 0 }
|
112
|
+
true
|
113
|
+
end
|
114
|
+
alias is_zero zero?
|
115
|
+
|
116
|
+
# Returns true if this is a matrix with equal rows and columns.
|
117
|
+
# Also aliased as square?
|
118
|
+
def is_square
|
119
|
+
return false if self.m != self.n
|
120
|
+
true
|
121
|
+
end
|
122
|
+
alias square? is_square
|
123
|
+
|
124
|
+
# Returns true if this is square matrix and its transpose is equal to its inverse.
|
125
|
+
# Also aliased as is_zero
|
126
|
+
def orthogonal?
|
127
|
+
return true if ((self.is_square) && (self.transposed == self.inversed))
|
128
|
+
false
|
129
|
+
end
|
130
|
+
alias is_orthogonal orthogonal?
|
47
131
|
end
|
data/lib/matrix_gem.rb
CHANGED
@@ -1,305 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
include MatrixErr
|
7
|
-
include Properties
|
8
|
-
include Enumerable
|
9
|
-
|
10
|
-
#---------Initialize the matrix------
|
11
|
-
# 1. Matrix with values
|
12
|
-
# Matrix.new(rows, cols, numbers) // numbers = rows*cols
|
13
|
-
# 2. Matrix only with dimention(rows and cols) make Identity matrix
|
14
|
-
# Matrix.new(rows, cols)
|
15
|
-
def initialize(rows, cols, *nums)
|
16
|
-
if rows < 1 || cols < 1
|
17
|
-
raise MatrixArgumentError, "Rows and Columns should be positive numbers!"
|
18
|
-
elsif nums.length == 0
|
19
|
-
@matrix = identity cols
|
20
|
-
elsif rows * cols == nums.length
|
21
|
-
@matrix = matrix_with_values nums, cols
|
22
|
-
else
|
23
|
-
raise MatrixArgumentError,
|
24
|
-
"Wrong number of arguments (#{2 + nums.length} for #{2 + rows * cols})"
|
25
|
-
end
|
26
|
-
@matrix
|
27
|
-
end
|
28
|
-
|
29
|
-
#Return the sum of two matrices in new matrix
|
30
|
-
def +(matrix)
|
31
|
-
sum_validation(matrix, self)
|
32
|
-
values = self.zip(matrix).map{|i| i.inject(:+)}
|
33
|
-
|
34
|
-
Matrix.new self.m, self.n, *(values)
|
35
|
-
end
|
36
|
-
|
37
|
-
#Return the difference of two matrices in new matrix
|
38
|
-
def -(matrix)
|
39
|
-
sum_validation(matrix, self)
|
40
|
-
values = self.zip(matrix).map{|i| i.inject(:-)}
|
41
|
-
|
42
|
-
Matrix.new self.m, self.n, *(values)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Returns element (i,j) of the matrix. That is: row i, column j.
|
46
|
-
# If only i is given return row[i]. That is: row with index i.
|
47
|
-
def [](i, j = nil)
|
48
|
-
if j == nil
|
49
|
-
@matrix[i]
|
50
|
-
else
|
51
|
-
@matrix[i][j]
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Set element (i,j) of the matrix. That is: row i, column j.
|
56
|
-
# Set row i of the matrix if j is not given. That is: column j.
|
57
|
-
# Also aliased as set_element
|
58
|
-
def []=(i, j = nil, val)
|
59
|
-
if j == nil
|
60
|
-
raise ErrDimensionMismatch if val.length != self.m
|
61
|
-
@matrix[i] = val
|
62
|
-
else
|
63
|
-
@matrix[i][j] = val
|
64
|
-
end
|
65
|
-
end
|
66
|
-
alias set_element []=
|
67
|
-
|
68
|
-
# Return a new matrix which is the transposition of the given one.
|
69
|
-
def transposed
|
70
|
-
elements = []
|
71
|
-
@matrix.to_a.transpose.map{ |x| x.map{ |y| elements << y } }
|
72
|
-
Matrix.new self.m, self.n, *(elements)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Transpose the matrix.
|
76
|
-
# Also aliased as t().
|
77
|
-
def transpose
|
78
|
-
elements = []
|
79
|
-
@matrix.to_a.transpose.map{ |x| x.map{ |y| elements << y } }
|
80
|
-
@matrix = elements.each_slice(@matrix[0].length).to_a
|
81
|
-
end
|
82
|
-
alias t transpose
|
83
|
-
|
84
|
-
#Each method.
|
85
|
-
def each
|
86
|
-
@matrix.each do |sub_arr|
|
87
|
-
sub_arr.each do |value|
|
88
|
-
yield value
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Returns true if and only if the two matrices contain equal elements.
|
94
|
-
def ==(matrix)
|
95
|
-
matrix.to_a == self.to_a
|
96
|
-
end
|
97
|
-
|
98
|
-
# Matrix multiplication.
|
99
|
-
def *(m)
|
100
|
-
case(m)
|
101
|
-
when Numeric
|
102
|
-
new_matrix_values = []
|
103
|
-
self.each { |x| new_matrix_values << x * m }
|
104
|
-
Matrix.new self.m, self.n, *(new_matrix_values)
|
105
|
-
when Matrix
|
106
|
-
multiply_validation self, m
|
107
|
-
rows = Array.new(self.m) { |i|
|
108
|
-
Array.new(m.n) { |j|
|
109
|
-
(0 ... m.n ).inject(0) do |vij, k|
|
110
|
-
vij + self[i, k] * m[k, j]
|
111
|
-
end
|
112
|
-
}
|
113
|
-
}
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Returns the determinant of the matrix.
|
118
|
-
# Also alised as determinant()
|
119
|
-
def det
|
120
|
-
is_square_validation self
|
121
|
-
|
122
|
-
_this = copy(self)
|
123
|
-
c = 1
|
124
|
-
new_matrix = nil
|
125
|
-
size = _this.n
|
126
|
-
|
127
|
-
(0..size - 2).each do |i|
|
128
|
-
(i + 1..size -1).each do |j|
|
129
|
-
if _this[i][i] == 0
|
130
|
-
(i+1..size-1).each do |k|
|
131
|
-
if _this[k,i] != 0
|
132
|
-
swap_rows(_this, k, i)
|
133
|
-
c *= -1
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
if _this[i,i] == 0
|
138
|
-
p _this
|
139
|
-
return 0
|
140
|
-
end
|
141
|
-
|
142
|
-
new_matrix = cauchy_method(_this, i, j, -_this[j,i]/_this[i,i].to_f)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
det = 1
|
147
|
-
|
148
|
-
(0..size-1).each do |i|
|
149
|
-
det *= new_matrix[i][i]
|
150
|
-
end
|
151
|
-
|
152
|
-
det *= c
|
153
|
-
det.round
|
154
|
-
end
|
155
|
-
alias determinant det
|
156
|
-
|
157
|
-
# Multiplication of matrix row with number.
|
158
|
-
def multiply_row(matrix, index, number)
|
159
|
-
matrix = matrix.row(index).map{ |n| n*number }
|
160
|
-
end
|
161
|
-
|
162
|
-
# Returns the inverse of the matrix.
|
163
|
-
def inverse
|
164
|
-
is_square_validation self
|
165
|
-
raise ErrZeroDeterminant if self.det == 0
|
166
|
-
|
167
|
-
_this = copy(self)
|
168
|
-
c = 1
|
169
|
-
e = Matrix.new _this.m, _this.n
|
170
|
-
size = _this.m
|
171
|
-
|
172
|
-
(0..size-2).each do |i|
|
173
|
-
(i+1..size-1).each do |j|
|
174
|
-
if _this[i, i] == 0
|
175
|
-
(i..size-2).each do |k|
|
176
|
-
if _this[k, i] != 0
|
177
|
-
swap_rows(_this, k, i)
|
178
|
-
swap_rows(e, k, i)
|
179
|
-
c *= -1
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
return 0 if _this[i, i] == 0
|
185
|
-
|
186
|
-
cauchy_method(e, i, j, -_this[j, i]/_this[i, i].to_f)
|
187
|
-
cauchy_method(_this, i, j, -_this[j, i]/_this[i, i].to_f)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
(0..size-2).each do |i|
|
192
|
-
(i+1..size-1).each do |j|
|
193
|
-
|
194
|
-
cauchy_method(e, size-i-1, size-j-1, -_this[size-j-1, size-i-1]/_this[size-i-1, size-i-1])
|
195
|
-
|
196
|
-
cauchy_method(_this, size-i-1, size-j-1, -_this[size-j-1, size-i-1]/_this[size-i-1, size-i-1])
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
(0..size-1).each do |i|
|
201
|
-
e.row_change i, multiply_row(e, i, 1/_this[i,i])
|
202
|
-
_this.row_change i, multiply_row(_this, i, 1/_this[i,i])
|
203
|
-
end
|
204
|
-
e
|
205
|
-
end
|
206
|
-
|
207
|
-
# Chanege matrix to its inversed.
|
208
|
-
def inversed
|
209
|
-
elements = []
|
210
|
-
self.inverse.each{ |x| elements << x}
|
211
|
-
@matrix = elements.each_slice(@matrix[0].length).to_a
|
212
|
-
end
|
213
|
-
|
214
|
-
# def to_s
|
215
|
-
# "Matrix[" + @matrix.map{|row|
|
216
|
-
# "[" + row.map{|e| e.to_s}.join("\t") + "]"
|
217
|
-
# }.join(", ") + "]"
|
218
|
-
# end
|
219
|
-
|
220
|
-
private
|
221
|
-
|
222
|
-
# Swap to matrix rows.
|
223
|
-
def swap_rows(_this, row1_index, row2_index)
|
224
|
-
_this[row1_index], _this[row2_index] = _this[row2_index], _this[row1_index]
|
225
|
-
end
|
226
|
-
|
227
|
-
# Return new instance of Matrix with same values.
|
228
|
-
def copy(_this)
|
229
|
-
values = []
|
230
|
-
_this.each{ |row| values << row }
|
231
|
-
copy = Matrix.new _this.m, _this.n, *(values)
|
232
|
-
end
|
233
|
-
|
234
|
-
# Multiply the first row elements with multiplier and sum it with second row
|
235
|
-
# elements.
|
236
|
-
# Used to make matrix in triangular form.
|
237
|
-
def cauchy_method(_this, row1_index, row2_index, multiplier)
|
238
|
-
_this.row(row2_index).each_with_index do |row_element, i|
|
239
|
-
_this.row(row2_index)[i] += _this[row1_index][i] * multiplier
|
240
|
-
end
|
241
|
-
_this
|
242
|
-
end
|
243
|
-
|
244
|
-
# Check if caller matrix columns are equal to other matrix rows.
|
245
|
-
def multiply_validation(_this, matrix)
|
246
|
-
raise ErrDimensionMismatch if _this.n != matrix.m
|
247
|
-
end
|
248
|
-
|
249
|
-
# Check if matrix rows are equals to its columns.
|
250
|
-
def is_square_validation(_this)
|
251
|
-
raise NoSquareMatrix if _this.m != _this.n
|
252
|
-
end
|
253
|
-
|
254
|
-
# Check if matrices have same dimentions.
|
255
|
-
def sum_validation(_this, matrix)
|
256
|
-
raise ErrOperationNotDefine if matrix.is_a? Numeric
|
257
|
-
raise ErrDimensionMismatch if matrix.m != _this.m || matrix.n != _this.n
|
258
|
-
end
|
259
|
-
|
260
|
-
# Make Identity matrix.
|
261
|
-
def identity(dimension)
|
262
|
-
id_matrix = []
|
263
|
-
dimension.times do |x|
|
264
|
-
id_matrix[x] = []
|
265
|
-
dimension.times do |y|
|
266
|
-
if x == y
|
267
|
-
id_matrix[x][y] = 1
|
268
|
-
else
|
269
|
-
id_matrix[x][y] = 0
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
return id_matrix
|
274
|
-
end
|
275
|
-
|
276
|
-
# Format values.
|
277
|
-
def matrix_with_values(values, col_length)
|
278
|
-
matrixNums = values.each_slice(col_length).to_a
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
|
283
|
-
a = Matrix.new 3,3,1,2,57,1,3,43,5,6,70
|
284
|
-
# p a
|
285
|
-
c = Matrix.new 2,2,4,3,3,2
|
286
|
-
d = Matrix.new 3,3,2,3,1,1,2,1,3,5,3
|
287
|
-
# d = Matrix.new 2,2,0,1,3,0
|
288
|
-
# d = Matrix.new 2,2,0,9,5,2
|
289
|
-
|
290
|
-
|
291
|
-
d = Matrix.new 3,3
|
292
|
-
|
293
|
-
#
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
1
|
+
require_relative './matrix_gem/matrix_err'
|
2
|
+
require_relative './matrix_gem/properties_module'
|
3
|
+
require_relative './matrix_gem/matrix'
|
4
|
+
require_relative './matrix_gem/diagonal_matrix'
|
5
|
+
require_relative './matrix_gem/orthogonal_matrix'
|
305
6
|
|
metadata
CHANGED
@@ -1,23 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matrix_gem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Grigorov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
-
dependencies:
|
11
|
+
date: 2015-02-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.4'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.4'
|
13
55
|
description: Gem for work with matrices
|
14
56
|
email: bojko002@gmail.com
|
15
57
|
executables: []
|
16
58
|
extensions: []
|
17
59
|
extra_rdoc_files: []
|
18
60
|
files:
|
61
|
+
- Rakefile
|
19
62
|
- lib/matrix_gem.rb
|
63
|
+
- lib/matrix_gem/diagonal_matrix.rb
|
64
|
+
- lib/matrix_gem/matrix.rb
|
20
65
|
- lib/matrix_gem/matrix_err.rb
|
66
|
+
- lib/matrix_gem/orthogonal_matrix.rb
|
21
67
|
- lib/matrix_gem/properties_module.rb
|
22
68
|
homepage: http://rubygems.org/gems/matrix_gem
|
23
69
|
licenses:
|