matrix 0.1.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/matrix.rb +299 -180
- data/lib/matrix/eigenvalue_decomposition.rb +882 -0
- data/lib/matrix/lup_decomposition.rb +219 -0
- data/lib/matrix/version.rb +5 -0
- data/matrix.gemspec +12 -7
- metadata +12 -44
- data/.gitignore +0 -9
- data/.travis.yml +0 -4
- data/Gemfile +0 -6
- data/README.md +0 -41
- data/Rakefile +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb141efd74292651e0289eb99780e5fdc476e5bf124a1038f6240939c629a2bf
|
4
|
+
data.tar.gz: 0e2f47d4f48c2986e4a4cc71973040b9b4a44f1e4c17a0f2319d46316ec742c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86c8960e1d3878711dc34b4af96ae95a4e0a2c765ab3fd1b63cf1e868ccd6b89cbdbbf4821744202c8ad834f7b65bd7b15642383156cac78d767351085ea4997
|
7
|
+
data.tar.gz: e1f5cf5fbdfb027d80afb774c3c89ef8ea837f2c1711ee91ac4689154a24588bfa21f74f2e47a71e5be698512c0023e4649ff1dc64d9feb0fbfcefe250874694
|
data/lib/matrix.rb
CHANGED
@@ -12,17 +12,44 @@
|
|
12
12
|
# Original Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly))
|
13
13
|
##
|
14
14
|
|
15
|
-
|
15
|
+
require_relative "matrix/version"
|
16
16
|
|
17
17
|
module ExceptionForMatrix # :nodoc:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
class ErrDimensionMismatch < StandardError
|
19
|
+
def initialize(val = nil)
|
20
|
+
if val
|
21
|
+
super(val)
|
22
|
+
else
|
23
|
+
super("Dimension mismatch")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ErrNotRegular < StandardError
|
29
|
+
def initialize(val = nil)
|
30
|
+
if val
|
31
|
+
super(val)
|
32
|
+
else
|
33
|
+
super("Not Regular Matrix")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ErrOperationNotDefined < StandardError
|
39
|
+
def initialize(vals)
|
40
|
+
if vals.is_a?(Array)
|
41
|
+
super("Operation(#{vals[0]}) can't be defined: #{vals[1]} op #{vals[2]}")
|
42
|
+
else
|
43
|
+
super(vals)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ErrOperationNotImplemented < StandardError
|
49
|
+
def initialize(vals)
|
50
|
+
super("Sorry, Operation(#{vals[0]}) not implemented: #{vals[1]} op #{vals[2]}")
|
51
|
+
end
|
52
|
+
end
|
26
53
|
end
|
27
54
|
|
28
55
|
#
|
@@ -45,8 +72,8 @@ class Matrix
|
|
45
72
|
#
|
46
73
|
# Creates a matrix where each argument is a row.
|
47
74
|
# Matrix[ [25, 93], [-1, 66] ]
|
48
|
-
#
|
49
|
-
#
|
75
|
+
# # => 25 93
|
76
|
+
# # -1 66
|
50
77
|
#
|
51
78
|
def Matrix.[](*rows)
|
52
79
|
rows(rows, false)
|
@@ -57,8 +84,8 @@ class Matrix
|
|
57
84
|
# of the matrix. If the optional argument +copy+ is false, use the given
|
58
85
|
# arrays as the internal structure of the matrix without copying.
|
59
86
|
# Matrix.rows([[25, 93], [-1, 66]])
|
60
|
-
#
|
61
|
-
#
|
87
|
+
# # => 25 93
|
88
|
+
# # -1 66
|
62
89
|
#
|
63
90
|
def Matrix.rows(rows, copy = true)
|
64
91
|
rows = convert_to_array(rows, copy)
|
@@ -75,8 +102,8 @@ class Matrix
|
|
75
102
|
#
|
76
103
|
# Creates a matrix using +columns+ as an array of column vectors.
|
77
104
|
# Matrix.columns([[25, 93], [-1, 66]])
|
78
|
-
#
|
79
|
-
#
|
105
|
+
# # => 25 -1
|
106
|
+
# # 93 66
|
80
107
|
#
|
81
108
|
def Matrix.columns(columns)
|
82
109
|
rows(columns, false).transpose
|
@@ -89,9 +116,9 @@ class Matrix
|
|
89
116
|
# Returns an enumerator if no block is given.
|
90
117
|
#
|
91
118
|
# m = Matrix.build(2, 4) {|row, col| col - row }
|
92
|
-
#
|
119
|
+
# # => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
|
93
120
|
# m = Matrix.build(3) { rand }
|
94
|
-
#
|
121
|
+
# # => a 3x3 matrix with random elements
|
95
122
|
#
|
96
123
|
def Matrix.build(row_count, column_count = row_count)
|
97
124
|
row_count = CoercionHelper.coerce_to_int(row_count)
|
@@ -109,9 +136,9 @@ class Matrix
|
|
109
136
|
#
|
110
137
|
# Creates a matrix where the diagonal elements are composed of +values+.
|
111
138
|
# Matrix.diagonal(9, 5, -3)
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
139
|
+
# # => 9 0 0
|
140
|
+
# # 0 5 0
|
141
|
+
# # 0 0 -3
|
115
142
|
#
|
116
143
|
def Matrix.diagonal(*values)
|
117
144
|
size = values.size
|
@@ -128,8 +155,8 @@ class Matrix
|
|
128
155
|
# Creates an +n+ by +n+ diagonal matrix where each diagonal element is
|
129
156
|
# +value+.
|
130
157
|
# Matrix.scalar(2, 5)
|
131
|
-
#
|
132
|
-
#
|
158
|
+
# # => 5 0
|
159
|
+
# # 0 5
|
133
160
|
#
|
134
161
|
def Matrix.scalar(n, value)
|
135
162
|
diagonal(*Array.new(n, value))
|
@@ -138,8 +165,8 @@ class Matrix
|
|
138
165
|
#
|
139
166
|
# Creates an +n+ by +n+ identity matrix.
|
140
167
|
# Matrix.identity(2)
|
141
|
-
#
|
142
|
-
#
|
168
|
+
# # => 1 0
|
169
|
+
# # 0 1
|
143
170
|
#
|
144
171
|
def Matrix.identity(n)
|
145
172
|
scalar(n, 1)
|
@@ -152,8 +179,8 @@ class Matrix
|
|
152
179
|
#
|
153
180
|
# Creates a zero matrix.
|
154
181
|
# Matrix.zero(2)
|
155
|
-
#
|
156
|
-
#
|
182
|
+
# # => 0 0
|
183
|
+
# # 0 0
|
157
184
|
#
|
158
185
|
def Matrix.zero(row_count, column_count = row_count)
|
159
186
|
rows = Array.new(row_count){Array.new(column_count, 0)}
|
@@ -164,7 +191,7 @@ class Matrix
|
|
164
191
|
# Creates a single-row matrix where the values of that row are as given in
|
165
192
|
# +row+.
|
166
193
|
# Matrix.row_vector([4,5,6])
|
167
|
-
#
|
194
|
+
# # => 4 5 6
|
168
195
|
#
|
169
196
|
def Matrix.row_vector(row)
|
170
197
|
row = convert_to_array(row)
|
@@ -175,9 +202,9 @@ class Matrix
|
|
175
202
|
# Creates a single-column matrix where the values of that column are as given
|
176
203
|
# in +column+.
|
177
204
|
# Matrix.column_vector([4,5,6])
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
205
|
+
# # => 4
|
206
|
+
# # 5
|
207
|
+
# # 6
|
181
208
|
#
|
182
209
|
def Matrix.column_vector(column)
|
183
210
|
column = convert_to_array(column)
|
@@ -190,12 +217,12 @@ class Matrix
|
|
190
217
|
#
|
191
218
|
# m = Matrix.empty(2, 0)
|
192
219
|
# m == Matrix[ [], [] ]
|
193
|
-
#
|
220
|
+
# # => true
|
194
221
|
# n = Matrix.empty(0, 3)
|
195
222
|
# n == Matrix.columns([ [], [], [] ])
|
196
|
-
#
|
223
|
+
# # => true
|
197
224
|
# m * n
|
198
|
-
#
|
225
|
+
# # => Matrix[[0, 0, 0], [0, 0, 0]]
|
199
226
|
#
|
200
227
|
def Matrix.empty(row_count = 0, column_count = 0)
|
201
228
|
raise ArgumentError, "One size must be 0" if column_count != 0 && row_count != 0
|
@@ -249,6 +276,8 @@ class Matrix
|
|
249
276
|
new result, total_column_count
|
250
277
|
end
|
251
278
|
|
279
|
+
# :call-seq:
|
280
|
+
# Matrix.combine(*matrices) { |*elements| ... }
|
252
281
|
#
|
253
282
|
# Create a matrix by combining matrices entrywise, using the given block
|
254
283
|
#
|
@@ -263,7 +292,7 @@ class Matrix
|
|
263
292
|
matrices.map!(&CoercionHelper.method(:coerce_to_matrix))
|
264
293
|
x = matrices.first
|
265
294
|
matrices.each do |m|
|
266
|
-
|
295
|
+
raise ErrDimensionMismatch unless x.row_count == m.row_count && x.column_count == m.column_count
|
267
296
|
end
|
268
297
|
|
269
298
|
rows = Array.new(x.row_count) do |i|
|
@@ -274,12 +303,21 @@ class Matrix
|
|
274
303
|
new rows, x.column_count
|
275
304
|
end
|
276
305
|
|
306
|
+
# :call-seq:
|
307
|
+
# combine(*other_matrices) { |*elements| ... }
|
308
|
+
#
|
309
|
+
# Creates new matrix by combining with <i>other_matrices</i> entrywise,
|
310
|
+
# using the given block.
|
311
|
+
#
|
312
|
+
# x = Matrix[[6, 6], [4, 4]]
|
313
|
+
# y = Matrix[[1, 2], [3, 4]]
|
314
|
+
# x.combine(y) {|a, b| a - b} # => Matrix[[5, 4], [1, 0]]
|
277
315
|
def combine(*matrices, &block)
|
278
316
|
Matrix.combine(self, *matrices, &block)
|
279
317
|
end
|
280
318
|
|
281
319
|
#
|
282
|
-
# Matrix.new is private; use
|
320
|
+
# Matrix.new is private; use ::rows, ::columns, ::[], etc... to create.
|
283
321
|
#
|
284
322
|
def initialize(rows, column_count = rows[0].size)
|
285
323
|
# No checking is done at this point. rows must be an Array of Arrays.
|
@@ -341,7 +379,7 @@ class Matrix
|
|
341
379
|
end
|
342
380
|
|
343
381
|
private def set_value(row, col, value)
|
344
|
-
raise ErrDimensionMismatch, "Expected a
|
382
|
+
raise ErrDimensionMismatch, "Expected a value, got a #{value.class}" if value.respond_to?(:to_matrix)
|
345
383
|
|
346
384
|
@rows[row][col] = value
|
347
385
|
end
|
@@ -372,12 +410,12 @@ class Matrix
|
|
372
410
|
|
373
411
|
private def set_row_range(row_range, col, value)
|
374
412
|
if value.is_a?(Vector)
|
375
|
-
|
413
|
+
raise ErrDimensionMismatch unless row_range.size == value.size
|
376
414
|
set_column_vector(row_range, col, value)
|
377
415
|
elsif value.is_a?(Matrix)
|
378
|
-
|
416
|
+
raise ErrDimensionMismatch unless value.column_count == 1
|
379
417
|
value = value.column(0)
|
380
|
-
|
418
|
+
raise ErrDimensionMismatch unless row_range.size == value.size
|
381
419
|
set_column_vector(row_range, col, value)
|
382
420
|
else
|
383
421
|
@rows[row_range].each{|e| e[col] = value }
|
@@ -395,12 +433,12 @@ class Matrix
|
|
395
433
|
value = if value.is_a?(Vector)
|
396
434
|
value.to_a
|
397
435
|
elsif value.is_a?(Matrix)
|
398
|
-
|
436
|
+
raise ErrDimensionMismatch unless value.row_count == 1
|
399
437
|
value.row(0).to_a
|
400
438
|
else
|
401
439
|
Array.new(col_range.size, value)
|
402
440
|
end
|
403
|
-
|
441
|
+
raise ErrDimensionMismatch unless col_range.size == value.size
|
404
442
|
@rows[row][col_range] = value
|
405
443
|
end
|
406
444
|
|
@@ -464,8 +502,8 @@ class Matrix
|
|
464
502
|
# * :strict_upper: yields only elements above the diagonal
|
465
503
|
# * :upper: yields only elements on or above the diagonal
|
466
504
|
# Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
|
467
|
-
#
|
468
|
-
#
|
505
|
+
# # => 1 4
|
506
|
+
# # 9 16
|
469
507
|
#
|
470
508
|
def collect(which = :all, &block) # :yield: e
|
471
509
|
return to_enum(:collect, which) unless block_given?
|
@@ -494,7 +532,8 @@ class Matrix
|
|
494
532
|
alias map! collect!
|
495
533
|
|
496
534
|
def freeze
|
497
|
-
@rows.freeze
|
535
|
+
@rows.each(&:freeze).freeze
|
536
|
+
|
498
537
|
super
|
499
538
|
end
|
500
539
|
|
@@ -510,16 +549,15 @@ class Matrix
|
|
510
549
|
# * :strict_upper: yields only elements above the diagonal
|
511
550
|
# * :upper: yields only elements on or above the diagonal
|
512
551
|
#
|
513
|
-
#
|
514
|
-
#
|
515
|
-
#
|
552
|
+
# Matrix[ [1,2], [3,4] ].each { |e| puts e }
|
553
|
+
# # => prints the numbers 1 to 4
|
554
|
+
# Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3]
|
516
555
|
#
|
517
|
-
def each(which = :all) # :yield: e
|
556
|
+
def each(which = :all, &block) # :yield: e
|
518
557
|
return to_enum :each, which unless block_given?
|
519
558
|
last = column_count - 1
|
520
559
|
case which
|
521
560
|
when :all
|
522
|
-
block = Proc.new
|
523
561
|
@rows.each do |row|
|
524
562
|
row.each(&block)
|
525
563
|
end
|
@@ -662,8 +700,8 @@ class Matrix
|
|
662
700
|
# * row_range, col_range
|
663
701
|
#
|
664
702
|
# Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
|
665
|
-
#
|
666
|
-
#
|
703
|
+
# # => 9 0 0
|
704
|
+
# # 0 5 0
|
667
705
|
#
|
668
706
|
# Like Array#[], negative indices count backward from the end of the
|
669
707
|
# row or column (-1 is the last element). Returns nil if the starting
|
@@ -706,9 +744,9 @@ class Matrix
|
|
706
744
|
# Returns the submatrix obtained by deleting the specified row and column.
|
707
745
|
#
|
708
746
|
# Matrix.diagonal(9, 5, -3, 4).first_minor(1, 2)
|
709
|
-
#
|
710
|
-
#
|
711
|
-
#
|
747
|
+
# # => 9 0 0
|
748
|
+
# # 0 0 0
|
749
|
+
# # 0 0 4
|
712
750
|
#
|
713
751
|
def first_minor(row, column)
|
714
752
|
raise RuntimeError, "first_minor of empty matrix is not defined" if empty?
|
@@ -735,11 +773,11 @@ class Matrix
|
|
735
773
|
# the first minor by (-1)**(row + column).
|
736
774
|
#
|
737
775
|
# Matrix.diagonal(9, 5, -3, 4).cofactor(1, 1)
|
738
|
-
#
|
776
|
+
# # => -108
|
739
777
|
#
|
740
778
|
def cofactor(row, column)
|
741
779
|
raise RuntimeError, "cofactor of empty matrix is not defined" if empty?
|
742
|
-
|
780
|
+
raise ErrDimensionMismatch unless square?
|
743
781
|
|
744
782
|
det_of_minor = first_minor(row, column).determinant
|
745
783
|
det_of_minor * (-1) ** (row + column)
|
@@ -749,11 +787,11 @@ class Matrix
|
|
749
787
|
# Returns the adjugate of the matrix.
|
750
788
|
#
|
751
789
|
# Matrix[ [7,6],[3,9] ].adjugate
|
752
|
-
#
|
753
|
-
#
|
790
|
+
# # => 9 -6
|
791
|
+
# # -3 7
|
754
792
|
#
|
755
793
|
def adjugate
|
756
|
-
|
794
|
+
raise ErrDimensionMismatch unless square?
|
757
795
|
Matrix.build(row_count, column_count) do |row, column|
|
758
796
|
cofactor(column, row)
|
759
797
|
end
|
@@ -763,10 +801,10 @@ class Matrix
|
|
763
801
|
# Returns the Laplace expansion along given row or column.
|
764
802
|
#
|
765
803
|
# Matrix[[7,6], [3,9]].laplace_expansion(column: 1)
|
766
|
-
#
|
804
|
+
# # => 45
|
767
805
|
#
|
768
806
|
# Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0)
|
769
|
-
#
|
807
|
+
# # => Vector[3, -2]
|
770
808
|
#
|
771
809
|
#
|
772
810
|
def laplace_expansion(row: nil, column: nil)
|
@@ -776,7 +814,7 @@ class Matrix
|
|
776
814
|
raise ArgumentError, "exactly one the row or column arguments must be specified"
|
777
815
|
end
|
778
816
|
|
779
|
-
|
817
|
+
raise ErrDimensionMismatch unless square?
|
780
818
|
raise RuntimeError, "laplace_expansion of empty matrix is not defined" if empty?
|
781
819
|
|
782
820
|
unless 0 <= num && num < row_count
|
@@ -799,7 +837,7 @@ class Matrix
|
|
799
837
|
# Raises an error if matrix is not square.
|
800
838
|
#
|
801
839
|
def diagonal?
|
802
|
-
|
840
|
+
raise ErrDimensionMismatch unless square?
|
803
841
|
each(:off_diagonal).all?(&:zero?)
|
804
842
|
end
|
805
843
|
|
@@ -816,7 +854,7 @@ class Matrix
|
|
816
854
|
# Raises an error if matrix is not square.
|
817
855
|
#
|
818
856
|
def hermitian?
|
819
|
-
|
857
|
+
raise ErrDimensionMismatch unless square?
|
820
858
|
each_with_index(:upper).all? do |e, row, col|
|
821
859
|
e == rows[col][row].conj
|
822
860
|
end
|
@@ -834,7 +872,7 @@ class Matrix
|
|
834
872
|
# Raises an error if matrix is not square.
|
835
873
|
#
|
836
874
|
def normal?
|
837
|
-
|
875
|
+
raise ErrDimensionMismatch unless square?
|
838
876
|
rows.each_with_index do |row_i, i|
|
839
877
|
rows.each_with_index do |row_j, j|
|
840
878
|
s = 0
|
@@ -852,12 +890,13 @@ class Matrix
|
|
852
890
|
# Raises an error if matrix is not square.
|
853
891
|
#
|
854
892
|
def orthogonal?
|
855
|
-
|
856
|
-
|
857
|
-
|
893
|
+
raise ErrDimensionMismatch unless square?
|
894
|
+
|
895
|
+
rows.each_with_index do |row_i, i|
|
896
|
+
rows.each_with_index do |row_j, j|
|
858
897
|
s = 0
|
859
898
|
row_count.times do |k|
|
860
|
-
s +=
|
899
|
+
s += row_i[k] * row_j[k]
|
861
900
|
end
|
862
901
|
return false unless s == (i == j ? 1 : 0)
|
863
902
|
end
|
@@ -870,7 +909,7 @@ class Matrix
|
|
870
909
|
# Raises an error if matrix is not square.
|
871
910
|
#
|
872
911
|
def permutation?
|
873
|
-
|
912
|
+
raise ErrDimensionMismatch unless square?
|
874
913
|
cols = Array.new(column_count)
|
875
914
|
rows.each_with_index do |row, i|
|
876
915
|
found = false
|
@@ -920,7 +959,7 @@ class Matrix
|
|
920
959
|
# Raises an error if matrix is not square.
|
921
960
|
#
|
922
961
|
def symmetric?
|
923
|
-
|
962
|
+
raise ErrDimensionMismatch unless square?
|
924
963
|
each_with_index(:strict_upper) do |e, row, col|
|
925
964
|
return false if e != rows[col][row]
|
926
965
|
end
|
@@ -932,7 +971,7 @@ class Matrix
|
|
932
971
|
# Raises an error if matrix is not square.
|
933
972
|
#
|
934
973
|
def antisymmetric?
|
935
|
-
|
974
|
+
raise ErrDimensionMismatch unless square?
|
936
975
|
each_with_index(:upper) do |e, row, col|
|
937
976
|
return false unless e == -rows[col][row]
|
938
977
|
end
|
@@ -945,12 +984,12 @@ class Matrix
|
|
945
984
|
# Raises an error if matrix is not square.
|
946
985
|
#
|
947
986
|
def unitary?
|
948
|
-
|
949
|
-
rows.each_with_index do |
|
950
|
-
|
987
|
+
raise ErrDimensionMismatch unless square?
|
988
|
+
rows.each_with_index do |row_i, i|
|
989
|
+
rows.each_with_index do |row_j, j|
|
951
990
|
s = 0
|
952
991
|
row_count.times do |k|
|
953
|
-
s +=
|
992
|
+
s += row_i[k].conj * row_j[k]
|
954
993
|
end
|
955
994
|
return false unless s == (i == j ? 1 : 0)
|
956
995
|
end
|
@@ -977,7 +1016,7 @@ class Matrix
|
|
977
1016
|
#++
|
978
1017
|
|
979
1018
|
#
|
980
|
-
# Returns
|
1019
|
+
# Returns whether the two matrices contain equal elements.
|
981
1020
|
#
|
982
1021
|
def ==(other)
|
983
1022
|
return false unless Matrix === other &&
|
@@ -1013,31 +1052,33 @@ class Matrix
|
|
1013
1052
|
#
|
1014
1053
|
# Matrix multiplication.
|
1015
1054
|
# Matrix[[2,4], [6,8]] * Matrix.identity(2)
|
1016
|
-
#
|
1017
|
-
#
|
1055
|
+
# # => 2 4
|
1056
|
+
# # 6 8
|
1018
1057
|
#
|
1019
1058
|
def *(m) # m is matrix or vector or number
|
1020
1059
|
case(m)
|
1021
1060
|
when Numeric
|
1022
|
-
|
1061
|
+
new_rows = @rows.collect {|row|
|
1023
1062
|
row.collect {|e| e * m }
|
1024
1063
|
}
|
1025
|
-
return new_matrix
|
1064
|
+
return new_matrix new_rows, column_count
|
1026
1065
|
when Vector
|
1027
1066
|
m = self.class.column_vector(m)
|
1028
1067
|
r = self * m
|
1029
1068
|
return r.column(0)
|
1030
1069
|
when Matrix
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
Array.new(m.column_count)
|
1035
|
-
|
1036
|
-
|
1070
|
+
raise ErrDimensionMismatch if column_count != m.row_count
|
1071
|
+
m_rows = m.rows
|
1072
|
+
new_rows = rows.map do |row_i|
|
1073
|
+
Array.new(m.column_count) do |j|
|
1074
|
+
vij = 0
|
1075
|
+
column_count.times do |k|
|
1076
|
+
vij += row_i[k] * m_rows[k][j]
|
1037
1077
|
end
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1078
|
+
vij
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
return new_matrix new_rows, m.column_count
|
1041
1082
|
else
|
1042
1083
|
return apply_through_coercion(m, __method__)
|
1043
1084
|
end
|
@@ -1046,13 +1087,13 @@ class Matrix
|
|
1046
1087
|
#
|
1047
1088
|
# Matrix addition.
|
1048
1089
|
# Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
|
1049
|
-
#
|
1050
|
-
#
|
1090
|
+
# # => 6 0
|
1091
|
+
# # -4 12
|
1051
1092
|
#
|
1052
1093
|
def +(m)
|
1053
1094
|
case m
|
1054
1095
|
when Numeric
|
1055
|
-
|
1096
|
+
raise ErrOperationNotDefined, ["+", self.class, m.class]
|
1056
1097
|
when Vector
|
1057
1098
|
m = self.class.column_vector(m)
|
1058
1099
|
when Matrix
|
@@ -1060,7 +1101,7 @@ class Matrix
|
|
1060
1101
|
return apply_through_coercion(m, __method__)
|
1061
1102
|
end
|
1062
1103
|
|
1063
|
-
|
1104
|
+
raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
|
1064
1105
|
|
1065
1106
|
rows = Array.new(row_count) {|i|
|
1066
1107
|
Array.new(column_count) {|j|
|
@@ -1073,13 +1114,13 @@ class Matrix
|
|
1073
1114
|
#
|
1074
1115
|
# Matrix subtraction.
|
1075
1116
|
# Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
|
1076
|
-
#
|
1077
|
-
#
|
1117
|
+
# # => -8 2
|
1118
|
+
# # 8 1
|
1078
1119
|
#
|
1079
1120
|
def -(m)
|
1080
1121
|
case m
|
1081
1122
|
when Numeric
|
1082
|
-
|
1123
|
+
raise ErrOperationNotDefined, ["-", self.class, m.class]
|
1083
1124
|
when Vector
|
1084
1125
|
m = self.class.column_vector(m)
|
1085
1126
|
when Matrix
|
@@ -1087,7 +1128,7 @@ class Matrix
|
|
1087
1128
|
return apply_through_coercion(m, __method__)
|
1088
1129
|
end
|
1089
1130
|
|
1090
|
-
|
1131
|
+
raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
|
1091
1132
|
|
1092
1133
|
rows = Array.new(row_count) {|i|
|
1093
1134
|
Array.new(column_count) {|j|
|
@@ -1100,8 +1141,8 @@ class Matrix
|
|
1100
1141
|
#
|
1101
1142
|
# Matrix division (multiplication by the inverse).
|
1102
1143
|
# Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
|
1103
|
-
#
|
1104
|
-
#
|
1144
|
+
# # => -7 1
|
1145
|
+
# # -3 -6
|
1105
1146
|
#
|
1106
1147
|
def /(other)
|
1107
1148
|
case other
|
@@ -1120,8 +1161,8 @@ class Matrix
|
|
1120
1161
|
#
|
1121
1162
|
# Hadamard product
|
1122
1163
|
# Matrix[[1,2], [3,4]].hadamard_product(Matrix[[1,2], [3,2]])
|
1123
|
-
#
|
1124
|
-
#
|
1164
|
+
# # => 1 4
|
1165
|
+
# # 9 8
|
1125
1166
|
#
|
1126
1167
|
def hadamard_product(m)
|
1127
1168
|
combine(m){|a, b| a * b}
|
@@ -1131,11 +1172,11 @@ class Matrix
|
|
1131
1172
|
#
|
1132
1173
|
# Returns the inverse of the matrix.
|
1133
1174
|
# Matrix[[-1, -1], [0, -1]].inverse
|
1134
|
-
#
|
1135
|
-
#
|
1175
|
+
# # => -1 1
|
1176
|
+
# # 0 -1
|
1136
1177
|
#
|
1137
1178
|
def inverse
|
1138
|
-
|
1179
|
+
raise ErrDimensionMismatch unless square?
|
1139
1180
|
self.class.I(row_count).send(:inverse_from, self)
|
1140
1181
|
end
|
1141
1182
|
alias_method :inv, :inverse
|
@@ -1154,7 +1195,7 @@ class Matrix
|
|
1154
1195
|
akk = v
|
1155
1196
|
end
|
1156
1197
|
end
|
1157
|
-
|
1198
|
+
raise ErrNotRegular if akk == 0
|
1158
1199
|
if i != k
|
1159
1200
|
a[i], a[k] = a[k], a[i]
|
1160
1201
|
@rows[i], @rows[k] = @rows[k], @rows[i]
|
@@ -1190,29 +1231,52 @@ class Matrix
|
|
1190
1231
|
# Non integer exponents will be handled by diagonalizing the matrix.
|
1191
1232
|
#
|
1192
1233
|
# Matrix[[7,6], [3,9]] ** 2
|
1193
|
-
#
|
1194
|
-
#
|
1234
|
+
# # => 67 96
|
1235
|
+
# # 48 99
|
1195
1236
|
#
|
1196
|
-
def **(
|
1197
|
-
case
|
1237
|
+
def **(exp)
|
1238
|
+
case exp
|
1198
1239
|
when Integer
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
z = z ? z * x : x if other[0] == 1
|
1208
|
-
return z if (other >>= 1).zero?
|
1209
|
-
x *= x
|
1240
|
+
case
|
1241
|
+
when exp == 0
|
1242
|
+
raise ErrDimensionMismatch unless square?
|
1243
|
+
self.class.identity(column_count)
|
1244
|
+
when exp < 0
|
1245
|
+
inverse.power_int(-exp)
|
1246
|
+
else
|
1247
|
+
power_int(exp)
|
1210
1248
|
end
|
1211
1249
|
when Numeric
|
1212
1250
|
v, d, v_inv = eigensystem
|
1213
|
-
v * self.class.diagonal(*d.each(:diagonal).map{|e| e **
|
1251
|
+
v * self.class.diagonal(*d.each(:diagonal).map{|e| e ** exp}) * v_inv
|
1252
|
+
else
|
1253
|
+
raise ErrOperationNotDefined, ["**", self.class, exp.class]
|
1254
|
+
end
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
protected def power_int(exp)
|
1258
|
+
# assumes `exp` is an Integer > 0
|
1259
|
+
#
|
1260
|
+
# Previous algorithm:
|
1261
|
+
# build M**2, M**4 = (M**2)**2, M**8, ... and multiplying those you need
|
1262
|
+
# e.g. M**0b1011 = M**11 = M * M**2 * M**8
|
1263
|
+
# ^ ^
|
1264
|
+
# (highlighted the 2 out of 5 multiplications involving `M * x`)
|
1265
|
+
#
|
1266
|
+
# Current algorithm has same number of multiplications but with lower exponents:
|
1267
|
+
# M**11 = M * (M * M**4)**2
|
1268
|
+
# ^ ^ ^
|
1269
|
+
# (highlighted the 3 out of 5 multiplications involving `M * x`)
|
1270
|
+
#
|
1271
|
+
# This should be faster for all (non nil-potent) matrices.
|
1272
|
+
case
|
1273
|
+
when exp == 1
|
1274
|
+
self
|
1275
|
+
when exp.odd?
|
1276
|
+
self * power_int(exp - 1)
|
1214
1277
|
else
|
1215
|
-
|
1278
|
+
sqrt = power_int(exp / 2)
|
1279
|
+
sqrt * sqrt
|
1216
1280
|
end
|
1217
1281
|
end
|
1218
1282
|
|
@@ -1220,10 +1284,22 @@ class Matrix
|
|
1220
1284
|
self
|
1221
1285
|
end
|
1222
1286
|
|
1287
|
+
# Unary matrix negation.
|
1288
|
+
#
|
1289
|
+
# -Matrix[[1,5], [4,2]]
|
1290
|
+
# # => -1 -5
|
1291
|
+
# # -4 -2
|
1223
1292
|
def -@
|
1224
1293
|
collect {|e| -e }
|
1225
1294
|
end
|
1226
1295
|
|
1296
|
+
#
|
1297
|
+
# Returns the absolute value elementwise
|
1298
|
+
#
|
1299
|
+
def abs
|
1300
|
+
collect(&:abs)
|
1301
|
+
end
|
1302
|
+
|
1227
1303
|
#--
|
1228
1304
|
# MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
1229
1305
|
#++
|
@@ -1236,10 +1312,10 @@ class Matrix
|
|
1236
1312
|
# Consider using exact types like Rational or BigDecimal instead.
|
1237
1313
|
#
|
1238
1314
|
# Matrix[[7,6], [3,9]].determinant
|
1239
|
-
#
|
1315
|
+
# # => 45
|
1240
1316
|
#
|
1241
1317
|
def determinant
|
1242
|
-
|
1318
|
+
raise ErrDimensionMismatch unless square?
|
1243
1319
|
m = @rows
|
1244
1320
|
case row_count
|
1245
1321
|
# Up to 4x4, give result using Laplacian expansion by minors.
|
@@ -1344,7 +1420,7 @@ class Matrix
|
|
1344
1420
|
# Consider using exact types like Rational or BigDecimal instead.
|
1345
1421
|
#
|
1346
1422
|
# Matrix[[7,6], [3,9]].rank
|
1347
|
-
#
|
1423
|
+
# # => 2
|
1348
1424
|
#
|
1349
1425
|
def rank
|
1350
1426
|
# We currently use Bareiss' multistep integer-preserving gaussian elimination
|
@@ -1382,6 +1458,35 @@ class Matrix
|
|
1382
1458
|
rank
|
1383
1459
|
end
|
1384
1460
|
|
1461
|
+
#
|
1462
|
+
# Returns a new matrix with rotated elements.
|
1463
|
+
# The argument specifies the rotation (defaults to `:clockwise`):
|
1464
|
+
# * :clockwise, 1, -3, etc.: "turn right" - first row becomes last column
|
1465
|
+
# * :half_turn, 2, -2, etc.: first row becomes last row, elements in reverse order
|
1466
|
+
# * :counter_clockwise, -1, 3: "turn left" - first row becomes first column
|
1467
|
+
# (but with elements in reverse order)
|
1468
|
+
#
|
1469
|
+
# m = Matrix[ [1, 2], [3, 4] ]
|
1470
|
+
# r = m.rotate_entries(:clockwise)
|
1471
|
+
# # => Matrix[[3, 1], [4, 2]]
|
1472
|
+
#
|
1473
|
+
def rotate_entries(rotation = :clockwise)
|
1474
|
+
rotation %= 4 if rotation.respond_to? :to_int
|
1475
|
+
|
1476
|
+
case rotation
|
1477
|
+
when 0
|
1478
|
+
dup
|
1479
|
+
when 1, :clockwise
|
1480
|
+
new_matrix @rows.transpose.each(&:reverse!), row_count
|
1481
|
+
when 2, :half_turn
|
1482
|
+
new_matrix @rows.map(&:reverse).reverse!, column_count
|
1483
|
+
when 3, :counter_clockwise
|
1484
|
+
new_matrix @rows.transpose.reverse!, row_count
|
1485
|
+
else
|
1486
|
+
raise ArgumentError, "expected #{rotation.inspect} to be one of :clockwise, :counter_clockwise, :half_turn or an integer"
|
1487
|
+
end
|
1488
|
+
end
|
1489
|
+
|
1385
1490
|
# Returns a matrix with entries rounded to the given precision
|
1386
1491
|
# (see Float#round)
|
1387
1492
|
#
|
@@ -1392,10 +1497,10 @@ class Matrix
|
|
1392
1497
|
#
|
1393
1498
|
# Returns the trace (sum of diagonal elements) of the matrix.
|
1394
1499
|
# Matrix[[7,6], [3,9]].trace
|
1395
|
-
#
|
1500
|
+
# # => 16
|
1396
1501
|
#
|
1397
1502
|
def trace
|
1398
|
-
|
1503
|
+
raise ErrDimensionMismatch unless square?
|
1399
1504
|
(0...column_count).inject(0) do |tr, i|
|
1400
1505
|
tr + @rows[i][i]
|
1401
1506
|
end
|
@@ -1405,12 +1510,12 @@ class Matrix
|
|
1405
1510
|
#
|
1406
1511
|
# Returns the transpose of the matrix.
|
1407
1512
|
# Matrix[[1,2], [3,4], [5,6]]
|
1408
|
-
#
|
1409
|
-
#
|
1410
|
-
#
|
1513
|
+
# # => 1 2
|
1514
|
+
# # 3 4
|
1515
|
+
# # 5 6
|
1411
1516
|
# Matrix[[1,2], [3,4], [5,6]].transpose
|
1412
|
-
#
|
1413
|
-
#
|
1517
|
+
# # => 1 3 5
|
1518
|
+
# # 2 4 6
|
1414
1519
|
#
|
1415
1520
|
def transpose
|
1416
1521
|
return self.class.empty(column_count, 0) if row_count.zero?
|
@@ -1469,25 +1574,36 @@ class Matrix
|
|
1469
1574
|
#
|
1470
1575
|
# Returns the conjugate of the matrix.
|
1471
1576
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1472
|
-
#
|
1473
|
-
#
|
1577
|
+
# # => 1+2i i 0
|
1578
|
+
# # 1 2 3
|
1474
1579
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
|
1475
|
-
#
|
1476
|
-
#
|
1580
|
+
# # => 1-2i -i 0
|
1581
|
+
# # 1 2 3
|
1477
1582
|
#
|
1478
1583
|
def conjugate
|
1479
1584
|
collect(&:conjugate)
|
1480
1585
|
end
|
1481
1586
|
alias_method :conj, :conjugate
|
1482
1587
|
|
1588
|
+
#
|
1589
|
+
# Returns the adjoint of the matrix.
|
1590
|
+
#
|
1591
|
+
# Matrix[ [i,1],[2,-i] ].adjoint
|
1592
|
+
# # => -i 2
|
1593
|
+
# # 1 i
|
1594
|
+
#
|
1595
|
+
def adjoint
|
1596
|
+
conjugate.transpose
|
1597
|
+
end
|
1598
|
+
|
1483
1599
|
#
|
1484
1600
|
# Returns the imaginary part of the matrix.
|
1485
1601
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1486
|
-
#
|
1487
|
-
#
|
1602
|
+
# # => 1+2i i 0
|
1603
|
+
# # 1 2 3
|
1488
1604
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
|
1489
|
-
#
|
1490
|
-
#
|
1605
|
+
# # => 2i i 0
|
1606
|
+
# # 0 0 0
|
1491
1607
|
#
|
1492
1608
|
def imaginary
|
1493
1609
|
collect(&:imaginary)
|
@@ -1497,11 +1613,11 @@ class Matrix
|
|
1497
1613
|
#
|
1498
1614
|
# Returns the real part of the matrix.
|
1499
1615
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1500
|
-
#
|
1501
|
-
#
|
1616
|
+
# # => 1+2i i 0
|
1617
|
+
# # 1 2 3
|
1502
1618
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
|
1503
|
-
#
|
1504
|
-
#
|
1619
|
+
# # => 1 0 0
|
1620
|
+
# # 1 2 3
|
1505
1621
|
#
|
1506
1622
|
def real
|
1507
1623
|
collect(&:real)
|
@@ -1511,7 +1627,7 @@ class Matrix
|
|
1511
1627
|
# Returns an array containing matrices corresponding to the real and imaginary
|
1512
1628
|
# parts of the matrix
|
1513
1629
|
#
|
1514
|
-
#
|
1630
|
+
# m.rect == [m.real, m.imag] # ==> true for all matrices m
|
1515
1631
|
#
|
1516
1632
|
def rect
|
1517
1633
|
[real, imag]
|
@@ -1572,7 +1688,7 @@ class Matrix
|
|
1572
1688
|
|
1573
1689
|
# Deprecated.
|
1574
1690
|
#
|
1575
|
-
# Use map(&:to_f)
|
1691
|
+
# Use <code>map(&:to_f)</code>
|
1576
1692
|
def elements_to_f
|
1577
1693
|
warn "Matrix#elements_to_f is deprecated, use map(&:to_f)", uplevel: 1
|
1578
1694
|
map(&:to_f)
|
@@ -1580,7 +1696,7 @@ class Matrix
|
|
1580
1696
|
|
1581
1697
|
# Deprecated.
|
1582
1698
|
#
|
1583
|
-
# Use map(&:to_i)
|
1699
|
+
# Use <code>map(&:to_i)</code>
|
1584
1700
|
def elements_to_i
|
1585
1701
|
warn "Matrix#elements_to_i is deprecated, use map(&:to_i)", uplevel: 1
|
1586
1702
|
map(&:to_i)
|
@@ -1588,7 +1704,7 @@ class Matrix
|
|
1588
1704
|
|
1589
1705
|
# Deprecated.
|
1590
1706
|
#
|
1591
|
-
# Use map(&:to_r)
|
1707
|
+
# Use <code>map(&:to_r)</code>
|
1592
1708
|
def elements_to_r
|
1593
1709
|
warn "Matrix#elements_to_r is deprecated, use map(&:to_r)", uplevel: 1
|
1594
1710
|
map(&:to_r)
|
@@ -1728,7 +1844,7 @@ class Matrix
|
|
1728
1844
|
when Numeric
|
1729
1845
|
Scalar.new(@value + other)
|
1730
1846
|
when Vector, Matrix
|
1731
|
-
|
1847
|
+
raise ErrOperationNotDefined, ["+", @value.class, other.class]
|
1732
1848
|
else
|
1733
1849
|
apply_through_coercion(other, __method__)
|
1734
1850
|
end
|
@@ -1739,7 +1855,7 @@ class Matrix
|
|
1739
1855
|
when Numeric
|
1740
1856
|
Scalar.new(@value - other)
|
1741
1857
|
when Vector, Matrix
|
1742
|
-
|
1858
|
+
raise ErrOperationNotDefined, ["-", @value.class, other.class]
|
1743
1859
|
else
|
1744
1860
|
apply_through_coercion(other, __method__)
|
1745
1861
|
end
|
@@ -1761,7 +1877,7 @@ class Matrix
|
|
1761
1877
|
when Numeric
|
1762
1878
|
Scalar.new(@value / other)
|
1763
1879
|
when Vector
|
1764
|
-
|
1880
|
+
raise ErrOperationNotDefined, ["/", @value.class, other.class]
|
1765
1881
|
when Matrix
|
1766
1882
|
self * other.inverse
|
1767
1883
|
else
|
@@ -1774,10 +1890,10 @@ class Matrix
|
|
1774
1890
|
when Numeric
|
1775
1891
|
Scalar.new(@value ** other)
|
1776
1892
|
when Vector
|
1777
|
-
|
1893
|
+
raise ErrOperationNotDefined, ["**", @value.class, other.class]
|
1778
1894
|
when Matrix
|
1779
1895
|
#other.powered_by(self)
|
1780
|
-
|
1896
|
+
raise ErrOperationNotImplemented, ["**", @value.class, other.class]
|
1781
1897
|
else
|
1782
1898
|
apply_through_coercion(other, __method__)
|
1783
1899
|
end
|
@@ -1824,8 +1940,8 @@ end
|
|
1824
1940
|
# * #-@
|
1825
1941
|
#
|
1826
1942
|
# Vector functions:
|
1827
|
-
# * #inner_product(v), dot(v)
|
1828
|
-
# * #cross_product(v), cross(v)
|
1943
|
+
# * #inner_product(v), #dot(v)
|
1944
|
+
# * #cross_product(v), #cross(v)
|
1829
1945
|
# * #collect
|
1830
1946
|
# * #collect!
|
1831
1947
|
# * #magnitude
|
@@ -1890,7 +2006,7 @@ class Vector
|
|
1890
2006
|
#
|
1891
2007
|
# Return a zero vector.
|
1892
2008
|
#
|
1893
|
-
# Vector.zero(3) => Vector[0, 0, 0]
|
2009
|
+
# Vector.zero(3) # => Vector[0, 0, 0]
|
1894
2010
|
#
|
1895
2011
|
def Vector.zero(size)
|
1896
2012
|
raise ArgumentError, "invalid size (#{size} for 0..)" if size < 0
|
@@ -1953,7 +2069,7 @@ class Vector
|
|
1953
2069
|
raise ArgumentError, "vector to be set has wrong size" unless range.size == value.size
|
1954
2070
|
@elements[range] = value.elements
|
1955
2071
|
elsif value.is_a?(Matrix)
|
1956
|
-
|
2072
|
+
raise ErrDimensionMismatch unless value.row_count == 1
|
1957
2073
|
@elements[range] = value.row(0).elements
|
1958
2074
|
else
|
1959
2075
|
@elements[range] = Array.new(range.size, value)
|
@@ -1992,7 +2108,7 @@ class Vector
|
|
1992
2108
|
#
|
1993
2109
|
def each2(v) # :yield: e1, e2
|
1994
2110
|
raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
|
1995
|
-
|
2111
|
+
raise ErrDimensionMismatch if size != v.size
|
1996
2112
|
return to_enum(:each2, v) unless block_given?
|
1997
2113
|
size.times do |i|
|
1998
2114
|
yield @elements[i], v[i]
|
@@ -2006,7 +2122,7 @@ class Vector
|
|
2006
2122
|
#
|
2007
2123
|
def collect2(v) # :yield: e1, e2
|
2008
2124
|
raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
|
2009
|
-
|
2125
|
+
raise ErrDimensionMismatch if size != v.size
|
2010
2126
|
return to_enum(:collect2, v) unless block_given?
|
2011
2127
|
Array.new(size) do |i|
|
2012
2128
|
yield @elements[i], v[i]
|
@@ -2018,43 +2134,46 @@ class Vector
|
|
2018
2134
|
#++
|
2019
2135
|
|
2020
2136
|
#
|
2021
|
-
# Returns
|
2137
|
+
# Returns whether all of vectors are linearly independent.
|
2022
2138
|
#
|
2023
2139
|
# Vector.independent?(Vector[1,0], Vector[0,1])
|
2024
|
-
#
|
2140
|
+
# # => true
|
2025
2141
|
#
|
2026
2142
|
# Vector.independent?(Vector[1,2], Vector[2,4])
|
2027
|
-
#
|
2143
|
+
# # => false
|
2028
2144
|
#
|
2029
2145
|
def Vector.independent?(*vs)
|
2030
2146
|
vs.each do |v|
|
2031
2147
|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a?(Vector)
|
2032
|
-
|
2148
|
+
raise ErrDimensionMismatch unless v.size == vs.first.size
|
2033
2149
|
end
|
2034
2150
|
return false if vs.count > vs.first.size
|
2035
2151
|
Matrix[*vs].rank.eql?(vs.count)
|
2036
2152
|
end
|
2037
2153
|
|
2038
2154
|
#
|
2039
|
-
# Returns
|
2155
|
+
# Returns whether all of vectors are linearly independent.
|
2040
2156
|
#
|
2041
2157
|
# Vector[1,0].independent?(Vector[0,1])
|
2042
|
-
#
|
2158
|
+
# # => true
|
2043
2159
|
#
|
2044
2160
|
# Vector[1,2].independent?(Vector[2,4])
|
2045
|
-
#
|
2161
|
+
# # => false
|
2046
2162
|
#
|
2047
2163
|
def independent?(*vs)
|
2048
2164
|
self.class.independent?(self, *vs)
|
2049
2165
|
end
|
2050
2166
|
|
2051
2167
|
#
|
2052
|
-
# Returns
|
2168
|
+
# Returns whether all elements are zero.
|
2053
2169
|
#
|
2054
2170
|
def zero?
|
2055
2171
|
all?(&:zero?)
|
2056
2172
|
end
|
2057
2173
|
|
2174
|
+
#
|
2175
|
+
# Makes the matrix frozen and Ractor-shareable
|
2176
|
+
#
|
2058
2177
|
def freeze
|
2059
2178
|
@elements.freeze
|
2060
2179
|
super
|
@@ -2074,7 +2193,7 @@ class Vector
|
|
2074
2193
|
#++
|
2075
2194
|
|
2076
2195
|
#
|
2077
|
-
# Returns
|
2196
|
+
# Returns whether the two vectors have the same elements in the same order.
|
2078
2197
|
#
|
2079
2198
|
def ==(other)
|
2080
2199
|
return false unless Vector === other
|
@@ -2108,7 +2227,7 @@ class Vector
|
|
2108
2227
|
when Matrix
|
2109
2228
|
Matrix.column_vector(self) * x
|
2110
2229
|
when Vector
|
2111
|
-
|
2230
|
+
raise ErrOperationNotDefined, ["*", self.class, x.class]
|
2112
2231
|
else
|
2113
2232
|
apply_through_coercion(x, __method__)
|
2114
2233
|
end
|
@@ -2120,7 +2239,7 @@ class Vector
|
|
2120
2239
|
def +(v)
|
2121
2240
|
case v
|
2122
2241
|
when Vector
|
2123
|
-
|
2242
|
+
raise ErrDimensionMismatch if size != v.size
|
2124
2243
|
els = collect2(v) {|v1, v2|
|
2125
2244
|
v1 + v2
|
2126
2245
|
}
|
@@ -2138,7 +2257,7 @@ class Vector
|
|
2138
2257
|
def -(v)
|
2139
2258
|
case v
|
2140
2259
|
when Vector
|
2141
|
-
|
2260
|
+
raise ErrDimensionMismatch if size != v.size
|
2142
2261
|
els = collect2(v) {|v1, v2|
|
2143
2262
|
v1 - v2
|
2144
2263
|
}
|
@@ -2159,7 +2278,7 @@ class Vector
|
|
2159
2278
|
els = @elements.collect{|e| e / x}
|
2160
2279
|
self.class.elements(els, false)
|
2161
2280
|
when Matrix, Vector
|
2162
|
-
|
2281
|
+
raise ErrOperationNotDefined, ["/", self.class, x.class]
|
2163
2282
|
else
|
2164
2283
|
apply_through_coercion(x, __method__)
|
2165
2284
|
end
|
@@ -2179,10 +2298,10 @@ class Vector
|
|
2179
2298
|
|
2180
2299
|
#
|
2181
2300
|
# Returns the inner product of this vector with the other.
|
2182
|
-
# Vector[4,7].inner_product Vector[10,1]
|
2301
|
+
# Vector[4,7].inner_product Vector[10,1] # => 47
|
2183
2302
|
#
|
2184
2303
|
def inner_product(v)
|
2185
|
-
|
2304
|
+
raise ErrDimensionMismatch if size != v.size
|
2186
2305
|
|
2187
2306
|
p = 0
|
2188
2307
|
each2(v) {|v1, v2|
|
@@ -2194,7 +2313,7 @@ class Vector
|
|
2194
2313
|
|
2195
2314
|
#
|
2196
2315
|
# Returns the cross product of this vector with the others.
|
2197
|
-
# Vector[1, 0, 0].cross_product Vector[0, 1, 0]
|
2316
|
+
# Vector[1, 0, 0].cross_product Vector[0, 1, 0] # => Vector[0, 0, 1]
|
2198
2317
|
#
|
2199
2318
|
# It is generalized to other dimensions to return a vector perpendicular
|
2200
2319
|
# to the arguments.
|
@@ -2209,7 +2328,7 @@ class Vector
|
|
2209
2328
|
raise ArgumentError, "wrong number of arguments (#{vs.size} for #{size - 2})" unless vs.size == size - 2
|
2210
2329
|
vs.each do |v|
|
2211
2330
|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a? Vector
|
2212
|
-
|
2331
|
+
raise ErrDimensionMismatch unless v.size == size
|
2213
2332
|
end
|
2214
2333
|
case size
|
2215
2334
|
when 2
|
@@ -2249,7 +2368,7 @@ class Vector
|
|
2249
2368
|
|
2250
2369
|
#
|
2251
2370
|
# Returns the modulus (Pythagorean distance) of the vector.
|
2252
|
-
# Vector[5,8,2].r => 9.643650761
|
2371
|
+
# Vector[5,8,2].r # => 9.643650761
|
2253
2372
|
#
|
2254
2373
|
def magnitude
|
2255
2374
|
Math.sqrt(@elements.inject(0) {|v, e| v + e.abs2})
|
@@ -2272,7 +2391,7 @@ class Vector
|
|
2272
2391
|
# Returns a new vector with the same direction but with norm 1.
|
2273
2392
|
# v = Vector[5,8,2].normalize
|
2274
2393
|
# # => Vector[0.5184758473652127, 0.8295613557843402, 0.20739033894608505]
|
2275
|
-
# v.norm => 1.0
|
2394
|
+
# v.norm # => 1.0
|
2276
2395
|
#
|
2277
2396
|
def normalize
|
2278
2397
|
n = magnitude
|
@@ -2287,7 +2406,7 @@ class Vector
|
|
2287
2406
|
#
|
2288
2407
|
def angle_with(v)
|
2289
2408
|
raise TypeError, "Expected a Vector, got a #{v.class}" unless v.is_a?(Vector)
|
2290
|
-
|
2409
|
+
raise ErrDimensionMismatch if size != v.size
|
2291
2410
|
prod = magnitude * v.magnitude
|
2292
2411
|
raise ZeroVectorError, "Can't get angle of zero vector" if prod == 0
|
2293
2412
|
dot = inner_product(v)
|