matrix 0.1.0 → 0.4.2
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/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)
|