matrix 0.1.0 → 0.3.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/README.md +11 -7
- data/lib/matrix.rb +222 -159
- 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 +10 -2
- metadata +7 -6
- data/.travis.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dafdb5e3baa2132e9e57ffa5058e7a868a3cf82a9ac3433af6e41744dee5af5c
|
4
|
+
data.tar.gz: 76ab3fcd078ceae78238eed7bc479f6038fe24106199406c3caa03b934cd7b3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52fd28e647cc8fec54e63eb1be9625a731c82c43508020d006d90e51d46863354bc60942878cbcf6aaa08a1cf00748cc07db139e75fe690c209dbfdbadb2f1ca
|
7
|
+
data.tar.gz: aaac184716f5efef477961ae5325d35829e004975f859007748f0e3352968244f02b3e15dbc4acdd21e211a233d707566293fcc28f1253d203c6073dc0734da4
|
data/README.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
# Matrix
|
1
|
+
# Matrix [](https://badge.fury.io/rb/matrix) [](https://stdgems.org/matrix/) [](https://travis-ci.com/ruby/matrix)
|
2
2
|
|
3
3
|
An implementation of `Matrix` and `Vector` classes.
|
4
4
|
|
5
|
-
The `Matrix` class represents a mathematical matrix. It provides methods for creating matrices, operating on them arithmetically and algebraically, and determining their mathematical properties (trace, rank, inverse, determinant).
|
5
|
+
The `Matrix` class represents a mathematical matrix. It provides methods for creating matrices, operating on them arithmetically and algebraically, and determining their mathematical properties (trace, rank, inverse, determinant, eigensystem, etc.).
|
6
6
|
|
7
7
|
The `Vector` class represents a mathematical vector, which is useful in its own right, and also constitutes a row or column of a `Matrix`.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
|
11
|
+
The `matrix` library comes pre-installed with Ruby. Unless you need recent features, you can simply `require 'matrix'` directly, no need to install it.
|
12
|
+
|
13
|
+
If you need features that are more recent than the version of Ruby you want to support (check the [CHANGELOG](CHANGELOG.md)), you must use the gem. To do this, add this line to your application's Gemfile or gem's gemspec:
|
12
14
|
|
13
15
|
```ruby
|
14
16
|
gem 'matrix'
|
@@ -18,13 +20,15 @@ And then execute:
|
|
18
20
|
|
19
21
|
$ bundle
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
$ gem install matrix
|
23
|
+
To make sure the gem takes over the builtin library, be to call `bundle exec ...` (or to call `gem 'matrix' explicitly).
|
24
24
|
|
25
25
|
## Usage
|
26
26
|
|
27
|
-
|
27
|
+
```ruby
|
28
|
+
require 'matrix'
|
29
|
+
m = Matrix[[1, 2], [3, 4]]
|
30
|
+
m.determinant # => -2
|
31
|
+
```
|
28
32
|
|
29
33
|
## Development
|
30
34
|
|
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.
|
@@ -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?
|
@@ -510,16 +548,15 @@ class Matrix
|
|
510
548
|
# * :strict_upper: yields only elements above the diagonal
|
511
549
|
# * :upper: yields only elements on or above the diagonal
|
512
550
|
#
|
513
|
-
#
|
514
|
-
#
|
515
|
-
#
|
551
|
+
# Matrix[ [1,2], [3,4] ].each { |e| puts e }
|
552
|
+
# # => prints the numbers 1 to 4
|
553
|
+
# Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3]
|
516
554
|
#
|
517
|
-
def each(which = :all) # :yield: e
|
555
|
+
def each(which = :all, &block) # :yield: e
|
518
556
|
return to_enum :each, which unless block_given?
|
519
557
|
last = column_count - 1
|
520
558
|
case which
|
521
559
|
when :all
|
522
|
-
block = Proc.new
|
523
560
|
@rows.each do |row|
|
524
561
|
row.each(&block)
|
525
562
|
end
|
@@ -662,8 +699,8 @@ class Matrix
|
|
662
699
|
# * row_range, col_range
|
663
700
|
#
|
664
701
|
# Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
|
665
|
-
#
|
666
|
-
#
|
702
|
+
# # => 9 0 0
|
703
|
+
# # 0 5 0
|
667
704
|
#
|
668
705
|
# Like Array#[], negative indices count backward from the end of the
|
669
706
|
# row or column (-1 is the last element). Returns nil if the starting
|
@@ -706,9 +743,9 @@ class Matrix
|
|
706
743
|
# Returns the submatrix obtained by deleting the specified row and column.
|
707
744
|
#
|
708
745
|
# Matrix.diagonal(9, 5, -3, 4).first_minor(1, 2)
|
709
|
-
#
|
710
|
-
#
|
711
|
-
#
|
746
|
+
# # => 9 0 0
|
747
|
+
# # 0 0 0
|
748
|
+
# # 0 0 4
|
712
749
|
#
|
713
750
|
def first_minor(row, column)
|
714
751
|
raise RuntimeError, "first_minor of empty matrix is not defined" if empty?
|
@@ -735,11 +772,11 @@ class Matrix
|
|
735
772
|
# the first minor by (-1)**(row + column).
|
736
773
|
#
|
737
774
|
# Matrix.diagonal(9, 5, -3, 4).cofactor(1, 1)
|
738
|
-
#
|
775
|
+
# # => -108
|
739
776
|
#
|
740
777
|
def cofactor(row, column)
|
741
778
|
raise RuntimeError, "cofactor of empty matrix is not defined" if empty?
|
742
|
-
|
779
|
+
raise ErrDimensionMismatch unless square?
|
743
780
|
|
744
781
|
det_of_minor = first_minor(row, column).determinant
|
745
782
|
det_of_minor * (-1) ** (row + column)
|
@@ -749,11 +786,11 @@ class Matrix
|
|
749
786
|
# Returns the adjugate of the matrix.
|
750
787
|
#
|
751
788
|
# Matrix[ [7,6],[3,9] ].adjugate
|
752
|
-
#
|
753
|
-
#
|
789
|
+
# # => 9 -6
|
790
|
+
# # -3 7
|
754
791
|
#
|
755
792
|
def adjugate
|
756
|
-
|
793
|
+
raise ErrDimensionMismatch unless square?
|
757
794
|
Matrix.build(row_count, column_count) do |row, column|
|
758
795
|
cofactor(column, row)
|
759
796
|
end
|
@@ -763,10 +800,10 @@ class Matrix
|
|
763
800
|
# Returns the Laplace expansion along given row or column.
|
764
801
|
#
|
765
802
|
# Matrix[[7,6], [3,9]].laplace_expansion(column: 1)
|
766
|
-
#
|
803
|
+
# # => 45
|
767
804
|
#
|
768
805
|
# Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0)
|
769
|
-
#
|
806
|
+
# # => Vector[3, -2]
|
770
807
|
#
|
771
808
|
#
|
772
809
|
def laplace_expansion(row: nil, column: nil)
|
@@ -776,7 +813,7 @@ class Matrix
|
|
776
813
|
raise ArgumentError, "exactly one the row or column arguments must be specified"
|
777
814
|
end
|
778
815
|
|
779
|
-
|
816
|
+
raise ErrDimensionMismatch unless square?
|
780
817
|
raise RuntimeError, "laplace_expansion of empty matrix is not defined" if empty?
|
781
818
|
|
782
819
|
unless 0 <= num && num < row_count
|
@@ -799,7 +836,7 @@ class Matrix
|
|
799
836
|
# Raises an error if matrix is not square.
|
800
837
|
#
|
801
838
|
def diagonal?
|
802
|
-
|
839
|
+
raise ErrDimensionMismatch unless square?
|
803
840
|
each(:off_diagonal).all?(&:zero?)
|
804
841
|
end
|
805
842
|
|
@@ -816,7 +853,7 @@ class Matrix
|
|
816
853
|
# Raises an error if matrix is not square.
|
817
854
|
#
|
818
855
|
def hermitian?
|
819
|
-
|
856
|
+
raise ErrDimensionMismatch unless square?
|
820
857
|
each_with_index(:upper).all? do |e, row, col|
|
821
858
|
e == rows[col][row].conj
|
822
859
|
end
|
@@ -834,7 +871,7 @@ class Matrix
|
|
834
871
|
# Raises an error if matrix is not square.
|
835
872
|
#
|
836
873
|
def normal?
|
837
|
-
|
874
|
+
raise ErrDimensionMismatch unless square?
|
838
875
|
rows.each_with_index do |row_i, i|
|
839
876
|
rows.each_with_index do |row_j, j|
|
840
877
|
s = 0
|
@@ -852,12 +889,13 @@ class Matrix
|
|
852
889
|
# Raises an error if matrix is not square.
|
853
890
|
#
|
854
891
|
def orthogonal?
|
855
|
-
|
856
|
-
|
857
|
-
|
892
|
+
raise ErrDimensionMismatch unless square?
|
893
|
+
|
894
|
+
rows.each_with_index do |row_i, i|
|
895
|
+
rows.each_with_index do |row_j, j|
|
858
896
|
s = 0
|
859
897
|
row_count.times do |k|
|
860
|
-
s +=
|
898
|
+
s += row_i[k] * row_j[k]
|
861
899
|
end
|
862
900
|
return false unless s == (i == j ? 1 : 0)
|
863
901
|
end
|
@@ -870,7 +908,7 @@ class Matrix
|
|
870
908
|
# Raises an error if matrix is not square.
|
871
909
|
#
|
872
910
|
def permutation?
|
873
|
-
|
911
|
+
raise ErrDimensionMismatch unless square?
|
874
912
|
cols = Array.new(column_count)
|
875
913
|
rows.each_with_index do |row, i|
|
876
914
|
found = false
|
@@ -920,7 +958,7 @@ class Matrix
|
|
920
958
|
# Raises an error if matrix is not square.
|
921
959
|
#
|
922
960
|
def symmetric?
|
923
|
-
|
961
|
+
raise ErrDimensionMismatch unless square?
|
924
962
|
each_with_index(:strict_upper) do |e, row, col|
|
925
963
|
return false if e != rows[col][row]
|
926
964
|
end
|
@@ -932,7 +970,7 @@ class Matrix
|
|
932
970
|
# Raises an error if matrix is not square.
|
933
971
|
#
|
934
972
|
def antisymmetric?
|
935
|
-
|
973
|
+
raise ErrDimensionMismatch unless square?
|
936
974
|
each_with_index(:upper) do |e, row, col|
|
937
975
|
return false unless e == -rows[col][row]
|
938
976
|
end
|
@@ -945,12 +983,12 @@ class Matrix
|
|
945
983
|
# Raises an error if matrix is not square.
|
946
984
|
#
|
947
985
|
def unitary?
|
948
|
-
|
949
|
-
rows.each_with_index do |
|
950
|
-
|
986
|
+
raise ErrDimensionMismatch unless square?
|
987
|
+
rows.each_with_index do |row_i, i|
|
988
|
+
rows.each_with_index do |row_j, j|
|
951
989
|
s = 0
|
952
990
|
row_count.times do |k|
|
953
|
-
s +=
|
991
|
+
s += row_i[k].conj * row_j[k]
|
954
992
|
end
|
955
993
|
return false unless s == (i == j ? 1 : 0)
|
956
994
|
end
|
@@ -1013,31 +1051,33 @@ class Matrix
|
|
1013
1051
|
#
|
1014
1052
|
# Matrix multiplication.
|
1015
1053
|
# Matrix[[2,4], [6,8]] * Matrix.identity(2)
|
1016
|
-
#
|
1017
|
-
#
|
1054
|
+
# # => 2 4
|
1055
|
+
# # 6 8
|
1018
1056
|
#
|
1019
1057
|
def *(m) # m is matrix or vector or number
|
1020
1058
|
case(m)
|
1021
1059
|
when Numeric
|
1022
|
-
|
1060
|
+
new_rows = @rows.collect {|row|
|
1023
1061
|
row.collect {|e| e * m }
|
1024
1062
|
}
|
1025
|
-
return new_matrix
|
1063
|
+
return new_matrix new_rows, column_count
|
1026
1064
|
when Vector
|
1027
1065
|
m = self.class.column_vector(m)
|
1028
1066
|
r = self * m
|
1029
1067
|
return r.column(0)
|
1030
1068
|
when Matrix
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
Array.new(m.column_count)
|
1035
|
-
|
1036
|
-
|
1069
|
+
raise ErrDimensionMismatch if column_count != m.row_count
|
1070
|
+
m_rows = m.rows
|
1071
|
+
new_rows = rows.map do |row_i|
|
1072
|
+
Array.new(m.column_count) do |j|
|
1073
|
+
vij = 0
|
1074
|
+
column_count.times do |k|
|
1075
|
+
vij += row_i[k] * m_rows[k][j]
|
1037
1076
|
end
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1077
|
+
vij
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
return new_matrix new_rows, m.column_count
|
1041
1081
|
else
|
1042
1082
|
return apply_through_coercion(m, __method__)
|
1043
1083
|
end
|
@@ -1046,13 +1086,13 @@ class Matrix
|
|
1046
1086
|
#
|
1047
1087
|
# Matrix addition.
|
1048
1088
|
# Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
|
1049
|
-
#
|
1050
|
-
#
|
1089
|
+
# # => 6 0
|
1090
|
+
# # -4 12
|
1051
1091
|
#
|
1052
1092
|
def +(m)
|
1053
1093
|
case m
|
1054
1094
|
when Numeric
|
1055
|
-
|
1095
|
+
raise ErrOperationNotDefined, ["+", self.class, m.class]
|
1056
1096
|
when Vector
|
1057
1097
|
m = self.class.column_vector(m)
|
1058
1098
|
when Matrix
|
@@ -1060,7 +1100,7 @@ class Matrix
|
|
1060
1100
|
return apply_through_coercion(m, __method__)
|
1061
1101
|
end
|
1062
1102
|
|
1063
|
-
|
1103
|
+
raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
|
1064
1104
|
|
1065
1105
|
rows = Array.new(row_count) {|i|
|
1066
1106
|
Array.new(column_count) {|j|
|
@@ -1073,13 +1113,13 @@ class Matrix
|
|
1073
1113
|
#
|
1074
1114
|
# Matrix subtraction.
|
1075
1115
|
# Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
|
1076
|
-
#
|
1077
|
-
#
|
1116
|
+
# # => -8 2
|
1117
|
+
# # 8 1
|
1078
1118
|
#
|
1079
1119
|
def -(m)
|
1080
1120
|
case m
|
1081
1121
|
when Numeric
|
1082
|
-
|
1122
|
+
raise ErrOperationNotDefined, ["-", self.class, m.class]
|
1083
1123
|
when Vector
|
1084
1124
|
m = self.class.column_vector(m)
|
1085
1125
|
when Matrix
|
@@ -1087,7 +1127,7 @@ class Matrix
|
|
1087
1127
|
return apply_through_coercion(m, __method__)
|
1088
1128
|
end
|
1089
1129
|
|
1090
|
-
|
1130
|
+
raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
|
1091
1131
|
|
1092
1132
|
rows = Array.new(row_count) {|i|
|
1093
1133
|
Array.new(column_count) {|j|
|
@@ -1100,8 +1140,8 @@ class Matrix
|
|
1100
1140
|
#
|
1101
1141
|
# Matrix division (multiplication by the inverse).
|
1102
1142
|
# Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
|
1103
|
-
#
|
1104
|
-
#
|
1143
|
+
# # => -7 1
|
1144
|
+
# # -3 -6
|
1105
1145
|
#
|
1106
1146
|
def /(other)
|
1107
1147
|
case other
|
@@ -1120,8 +1160,8 @@ class Matrix
|
|
1120
1160
|
#
|
1121
1161
|
# Hadamard product
|
1122
1162
|
# Matrix[[1,2], [3,4]].hadamard_product(Matrix[[1,2], [3,2]])
|
1123
|
-
#
|
1124
|
-
#
|
1163
|
+
# # => 1 4
|
1164
|
+
# # 9 8
|
1125
1165
|
#
|
1126
1166
|
def hadamard_product(m)
|
1127
1167
|
combine(m){|a, b| a * b}
|
@@ -1131,11 +1171,11 @@ class Matrix
|
|
1131
1171
|
#
|
1132
1172
|
# Returns the inverse of the matrix.
|
1133
1173
|
# Matrix[[-1, -1], [0, -1]].inverse
|
1134
|
-
#
|
1135
|
-
#
|
1174
|
+
# # => -1 1
|
1175
|
+
# # 0 -1
|
1136
1176
|
#
|
1137
1177
|
def inverse
|
1138
|
-
|
1178
|
+
raise ErrDimensionMismatch unless square?
|
1139
1179
|
self.class.I(row_count).send(:inverse_from, self)
|
1140
1180
|
end
|
1141
1181
|
alias_method :inv, :inverse
|
@@ -1154,7 +1194,7 @@ class Matrix
|
|
1154
1194
|
akk = v
|
1155
1195
|
end
|
1156
1196
|
end
|
1157
|
-
|
1197
|
+
raise ErrNotRegular if akk == 0
|
1158
1198
|
if i != k
|
1159
1199
|
a[i], a[k] = a[k], a[i]
|
1160
1200
|
@rows[i], @rows[k] = @rows[k], @rows[i]
|
@@ -1190,8 +1230,8 @@ class Matrix
|
|
1190
1230
|
# Non integer exponents will be handled by diagonalizing the matrix.
|
1191
1231
|
#
|
1192
1232
|
# Matrix[[7,6], [3,9]] ** 2
|
1193
|
-
#
|
1194
|
-
#
|
1233
|
+
# # => 67 96
|
1234
|
+
# # 48 99
|
1195
1235
|
#
|
1196
1236
|
def **(other)
|
1197
1237
|
case other
|
@@ -1212,7 +1252,7 @@ class Matrix
|
|
1212
1252
|
v, d, v_inv = eigensystem
|
1213
1253
|
v * self.class.diagonal(*d.each(:diagonal).map{|e| e ** other}) * v_inv
|
1214
1254
|
else
|
1215
|
-
|
1255
|
+
raise ErrOperationNotDefined, ["**", self.class, other.class]
|
1216
1256
|
end
|
1217
1257
|
end
|
1218
1258
|
|
@@ -1220,10 +1260,22 @@ class Matrix
|
|
1220
1260
|
self
|
1221
1261
|
end
|
1222
1262
|
|
1263
|
+
# Unary matrix negation.
|
1264
|
+
#
|
1265
|
+
# -Matrix[[1,5], [4,2]]
|
1266
|
+
# # => -1 -5
|
1267
|
+
# # -4 -2
|
1223
1268
|
def -@
|
1224
1269
|
collect {|e| -e }
|
1225
1270
|
end
|
1226
1271
|
|
1272
|
+
#
|
1273
|
+
# Returns the absolute value elementwise
|
1274
|
+
#
|
1275
|
+
def abs
|
1276
|
+
collect(&:abs)
|
1277
|
+
end
|
1278
|
+
|
1227
1279
|
#--
|
1228
1280
|
# MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
1229
1281
|
#++
|
@@ -1236,10 +1288,10 @@ class Matrix
|
|
1236
1288
|
# Consider using exact types like Rational or BigDecimal instead.
|
1237
1289
|
#
|
1238
1290
|
# Matrix[[7,6], [3,9]].determinant
|
1239
|
-
#
|
1291
|
+
# # => 45
|
1240
1292
|
#
|
1241
1293
|
def determinant
|
1242
|
-
|
1294
|
+
raise ErrDimensionMismatch unless square?
|
1243
1295
|
m = @rows
|
1244
1296
|
case row_count
|
1245
1297
|
# Up to 4x4, give result using Laplacian expansion by minors.
|
@@ -1344,7 +1396,7 @@ class Matrix
|
|
1344
1396
|
# Consider using exact types like Rational or BigDecimal instead.
|
1345
1397
|
#
|
1346
1398
|
# Matrix[[7,6], [3,9]].rank
|
1347
|
-
#
|
1399
|
+
# # => 2
|
1348
1400
|
#
|
1349
1401
|
def rank
|
1350
1402
|
# We currently use Bareiss' multistep integer-preserving gaussian elimination
|
@@ -1392,10 +1444,10 @@ class Matrix
|
|
1392
1444
|
#
|
1393
1445
|
# Returns the trace (sum of diagonal elements) of the matrix.
|
1394
1446
|
# Matrix[[7,6], [3,9]].trace
|
1395
|
-
#
|
1447
|
+
# # => 16
|
1396
1448
|
#
|
1397
1449
|
def trace
|
1398
|
-
|
1450
|
+
raise ErrDimensionMismatch unless square?
|
1399
1451
|
(0...column_count).inject(0) do |tr, i|
|
1400
1452
|
tr + @rows[i][i]
|
1401
1453
|
end
|
@@ -1405,12 +1457,12 @@ class Matrix
|
|
1405
1457
|
#
|
1406
1458
|
# Returns the transpose of the matrix.
|
1407
1459
|
# Matrix[[1,2], [3,4], [5,6]]
|
1408
|
-
#
|
1409
|
-
#
|
1410
|
-
#
|
1460
|
+
# # => 1 2
|
1461
|
+
# # 3 4
|
1462
|
+
# # 5 6
|
1411
1463
|
# Matrix[[1,2], [3,4], [5,6]].transpose
|
1412
|
-
#
|
1413
|
-
#
|
1464
|
+
# # => 1 3 5
|
1465
|
+
# # 2 4 6
|
1414
1466
|
#
|
1415
1467
|
def transpose
|
1416
1468
|
return self.class.empty(column_count, 0) if row_count.zero?
|
@@ -1469,25 +1521,36 @@ class Matrix
|
|
1469
1521
|
#
|
1470
1522
|
# Returns the conjugate of the matrix.
|
1471
1523
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1472
|
-
#
|
1473
|
-
#
|
1524
|
+
# # => 1+2i i 0
|
1525
|
+
# # 1 2 3
|
1474
1526
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
|
1475
|
-
#
|
1476
|
-
#
|
1527
|
+
# # => 1-2i -i 0
|
1528
|
+
# # 1 2 3
|
1477
1529
|
#
|
1478
1530
|
def conjugate
|
1479
1531
|
collect(&:conjugate)
|
1480
1532
|
end
|
1481
1533
|
alias_method :conj, :conjugate
|
1482
1534
|
|
1535
|
+
#
|
1536
|
+
# Returns the adjoint of the matrix.
|
1537
|
+
#
|
1538
|
+
# Matrix[ [i,1],[2,-i] ].adjoint
|
1539
|
+
# # => -i 2
|
1540
|
+
# # 1 i
|
1541
|
+
#
|
1542
|
+
def adjoint
|
1543
|
+
conjugate.transpose
|
1544
|
+
end
|
1545
|
+
|
1483
1546
|
#
|
1484
1547
|
# Returns the imaginary part of the matrix.
|
1485
1548
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1486
|
-
#
|
1487
|
-
#
|
1549
|
+
# # => 1+2i i 0
|
1550
|
+
# # 1 2 3
|
1488
1551
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
|
1489
|
-
#
|
1490
|
-
#
|
1552
|
+
# # => 2i i 0
|
1553
|
+
# # 0 0 0
|
1491
1554
|
#
|
1492
1555
|
def imaginary
|
1493
1556
|
collect(&:imaginary)
|
@@ -1497,11 +1560,11 @@ class Matrix
|
|
1497
1560
|
#
|
1498
1561
|
# Returns the real part of the matrix.
|
1499
1562
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
|
1500
|
-
#
|
1501
|
-
#
|
1563
|
+
# # => 1+2i i 0
|
1564
|
+
# # 1 2 3
|
1502
1565
|
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
|
1503
|
-
#
|
1504
|
-
#
|
1566
|
+
# # => 1 0 0
|
1567
|
+
# # 1 2 3
|
1505
1568
|
#
|
1506
1569
|
def real
|
1507
1570
|
collect(&:real)
|
@@ -1511,7 +1574,7 @@ class Matrix
|
|
1511
1574
|
# Returns an array containing matrices corresponding to the real and imaginary
|
1512
1575
|
# parts of the matrix
|
1513
1576
|
#
|
1514
|
-
#
|
1577
|
+
# m.rect == [m.real, m.imag] # ==> true for all matrices m
|
1515
1578
|
#
|
1516
1579
|
def rect
|
1517
1580
|
[real, imag]
|
@@ -1572,7 +1635,7 @@ class Matrix
|
|
1572
1635
|
|
1573
1636
|
# Deprecated.
|
1574
1637
|
#
|
1575
|
-
# Use map(&:to_f)
|
1638
|
+
# Use <code>map(&:to_f)</code>
|
1576
1639
|
def elements_to_f
|
1577
1640
|
warn "Matrix#elements_to_f is deprecated, use map(&:to_f)", uplevel: 1
|
1578
1641
|
map(&:to_f)
|
@@ -1580,7 +1643,7 @@ class Matrix
|
|
1580
1643
|
|
1581
1644
|
# Deprecated.
|
1582
1645
|
#
|
1583
|
-
# Use map(&:to_i)
|
1646
|
+
# Use <code>map(&:to_i)</code>
|
1584
1647
|
def elements_to_i
|
1585
1648
|
warn "Matrix#elements_to_i is deprecated, use map(&:to_i)", uplevel: 1
|
1586
1649
|
map(&:to_i)
|
@@ -1588,7 +1651,7 @@ class Matrix
|
|
1588
1651
|
|
1589
1652
|
# Deprecated.
|
1590
1653
|
#
|
1591
|
-
# Use map(&:to_r)
|
1654
|
+
# Use <code>map(&:to_r)</code>
|
1592
1655
|
def elements_to_r
|
1593
1656
|
warn "Matrix#elements_to_r is deprecated, use map(&:to_r)", uplevel: 1
|
1594
1657
|
map(&:to_r)
|
@@ -1728,7 +1791,7 @@ class Matrix
|
|
1728
1791
|
when Numeric
|
1729
1792
|
Scalar.new(@value + other)
|
1730
1793
|
when Vector, Matrix
|
1731
|
-
|
1794
|
+
raise ErrOperationNotDefined, ["+", @value.class, other.class]
|
1732
1795
|
else
|
1733
1796
|
apply_through_coercion(other, __method__)
|
1734
1797
|
end
|
@@ -1739,7 +1802,7 @@ class Matrix
|
|
1739
1802
|
when Numeric
|
1740
1803
|
Scalar.new(@value - other)
|
1741
1804
|
when Vector, Matrix
|
1742
|
-
|
1805
|
+
raise ErrOperationNotDefined, ["-", @value.class, other.class]
|
1743
1806
|
else
|
1744
1807
|
apply_through_coercion(other, __method__)
|
1745
1808
|
end
|
@@ -1761,7 +1824,7 @@ class Matrix
|
|
1761
1824
|
when Numeric
|
1762
1825
|
Scalar.new(@value / other)
|
1763
1826
|
when Vector
|
1764
|
-
|
1827
|
+
raise ErrOperationNotDefined, ["/", @value.class, other.class]
|
1765
1828
|
when Matrix
|
1766
1829
|
self * other.inverse
|
1767
1830
|
else
|
@@ -1774,10 +1837,10 @@ class Matrix
|
|
1774
1837
|
when Numeric
|
1775
1838
|
Scalar.new(@value ** other)
|
1776
1839
|
when Vector
|
1777
|
-
|
1840
|
+
raise ErrOperationNotDefined, ["**", @value.class, other.class]
|
1778
1841
|
when Matrix
|
1779
1842
|
#other.powered_by(self)
|
1780
|
-
|
1843
|
+
raise ErrOperationNotImplemented, ["**", @value.class, other.class]
|
1781
1844
|
else
|
1782
1845
|
apply_through_coercion(other, __method__)
|
1783
1846
|
end
|
@@ -1824,8 +1887,8 @@ end
|
|
1824
1887
|
# * #-@
|
1825
1888
|
#
|
1826
1889
|
# Vector functions:
|
1827
|
-
# * #inner_product(v), dot(v)
|
1828
|
-
# * #cross_product(v), cross(v)
|
1890
|
+
# * #inner_product(v), #dot(v)
|
1891
|
+
# * #cross_product(v), #cross(v)
|
1829
1892
|
# * #collect
|
1830
1893
|
# * #collect!
|
1831
1894
|
# * #magnitude
|
@@ -1890,7 +1953,7 @@ class Vector
|
|
1890
1953
|
#
|
1891
1954
|
# Return a zero vector.
|
1892
1955
|
#
|
1893
|
-
# Vector.zero(3) => Vector[0, 0, 0]
|
1956
|
+
# Vector.zero(3) # => Vector[0, 0, 0]
|
1894
1957
|
#
|
1895
1958
|
def Vector.zero(size)
|
1896
1959
|
raise ArgumentError, "invalid size (#{size} for 0..)" if size < 0
|
@@ -1953,7 +2016,7 @@ class Vector
|
|
1953
2016
|
raise ArgumentError, "vector to be set has wrong size" unless range.size == value.size
|
1954
2017
|
@elements[range] = value.elements
|
1955
2018
|
elsif value.is_a?(Matrix)
|
1956
|
-
|
2019
|
+
raise ErrDimensionMismatch unless value.row_count == 1
|
1957
2020
|
@elements[range] = value.row(0).elements
|
1958
2021
|
else
|
1959
2022
|
@elements[range] = Array.new(range.size, value)
|
@@ -1992,7 +2055,7 @@ class Vector
|
|
1992
2055
|
#
|
1993
2056
|
def each2(v) # :yield: e1, e2
|
1994
2057
|
raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
|
1995
|
-
|
2058
|
+
raise ErrDimensionMismatch if size != v.size
|
1996
2059
|
return to_enum(:each2, v) unless block_given?
|
1997
2060
|
size.times do |i|
|
1998
2061
|
yield @elements[i], v[i]
|
@@ -2006,7 +2069,7 @@ class Vector
|
|
2006
2069
|
#
|
2007
2070
|
def collect2(v) # :yield: e1, e2
|
2008
2071
|
raise TypeError, "Integer is not like Vector" if v.kind_of?(Integer)
|
2009
|
-
|
2072
|
+
raise ErrDimensionMismatch if size != v.size
|
2010
2073
|
return to_enum(:collect2, v) unless block_given?
|
2011
2074
|
Array.new(size) do |i|
|
2012
2075
|
yield @elements[i], v[i]
|
@@ -2021,15 +2084,15 @@ class Vector
|
|
2021
2084
|
# Returns +true+ iff all of vectors are linearly independent.
|
2022
2085
|
#
|
2023
2086
|
# Vector.independent?(Vector[1,0], Vector[0,1])
|
2024
|
-
#
|
2087
|
+
# # => true
|
2025
2088
|
#
|
2026
2089
|
# Vector.independent?(Vector[1,2], Vector[2,4])
|
2027
|
-
#
|
2090
|
+
# # => false
|
2028
2091
|
#
|
2029
2092
|
def Vector.independent?(*vs)
|
2030
2093
|
vs.each do |v|
|
2031
2094
|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a?(Vector)
|
2032
|
-
|
2095
|
+
raise ErrDimensionMismatch unless v.size == vs.first.size
|
2033
2096
|
end
|
2034
2097
|
return false if vs.count > vs.first.size
|
2035
2098
|
Matrix[*vs].rank.eql?(vs.count)
|
@@ -2039,10 +2102,10 @@ class Vector
|
|
2039
2102
|
# Returns +true+ iff all of vectors are linearly independent.
|
2040
2103
|
#
|
2041
2104
|
# Vector[1,0].independent?(Vector[0,1])
|
2042
|
-
#
|
2105
|
+
# # => true
|
2043
2106
|
#
|
2044
2107
|
# Vector[1,2].independent?(Vector[2,4])
|
2045
|
-
#
|
2108
|
+
# # => false
|
2046
2109
|
#
|
2047
2110
|
def independent?(*vs)
|
2048
2111
|
self.class.independent?(self, *vs)
|
@@ -2108,7 +2171,7 @@ class Vector
|
|
2108
2171
|
when Matrix
|
2109
2172
|
Matrix.column_vector(self) * x
|
2110
2173
|
when Vector
|
2111
|
-
|
2174
|
+
raise ErrOperationNotDefined, ["*", self.class, x.class]
|
2112
2175
|
else
|
2113
2176
|
apply_through_coercion(x, __method__)
|
2114
2177
|
end
|
@@ -2120,7 +2183,7 @@ class Vector
|
|
2120
2183
|
def +(v)
|
2121
2184
|
case v
|
2122
2185
|
when Vector
|
2123
|
-
|
2186
|
+
raise ErrDimensionMismatch if size != v.size
|
2124
2187
|
els = collect2(v) {|v1, v2|
|
2125
2188
|
v1 + v2
|
2126
2189
|
}
|
@@ -2138,7 +2201,7 @@ class Vector
|
|
2138
2201
|
def -(v)
|
2139
2202
|
case v
|
2140
2203
|
when Vector
|
2141
|
-
|
2204
|
+
raise ErrDimensionMismatch if size != v.size
|
2142
2205
|
els = collect2(v) {|v1, v2|
|
2143
2206
|
v1 - v2
|
2144
2207
|
}
|
@@ -2159,7 +2222,7 @@ class Vector
|
|
2159
2222
|
els = @elements.collect{|e| e / x}
|
2160
2223
|
self.class.elements(els, false)
|
2161
2224
|
when Matrix, Vector
|
2162
|
-
|
2225
|
+
raise ErrOperationNotDefined, ["/", self.class, x.class]
|
2163
2226
|
else
|
2164
2227
|
apply_through_coercion(x, __method__)
|
2165
2228
|
end
|
@@ -2179,10 +2242,10 @@ class Vector
|
|
2179
2242
|
|
2180
2243
|
#
|
2181
2244
|
# Returns the inner product of this vector with the other.
|
2182
|
-
# Vector[4,7].inner_product Vector[10,1]
|
2245
|
+
# Vector[4,7].inner_product Vector[10,1] # => 47
|
2183
2246
|
#
|
2184
2247
|
def inner_product(v)
|
2185
|
-
|
2248
|
+
raise ErrDimensionMismatch if size != v.size
|
2186
2249
|
|
2187
2250
|
p = 0
|
2188
2251
|
each2(v) {|v1, v2|
|
@@ -2194,7 +2257,7 @@ class Vector
|
|
2194
2257
|
|
2195
2258
|
#
|
2196
2259
|
# Returns the cross product of this vector with the others.
|
2197
|
-
# Vector[1, 0, 0].cross_product Vector[0, 1, 0]
|
2260
|
+
# Vector[1, 0, 0].cross_product Vector[0, 1, 0] # => Vector[0, 0, 1]
|
2198
2261
|
#
|
2199
2262
|
# It is generalized to other dimensions to return a vector perpendicular
|
2200
2263
|
# to the arguments.
|
@@ -2209,7 +2272,7 @@ class Vector
|
|
2209
2272
|
raise ArgumentError, "wrong number of arguments (#{vs.size} for #{size - 2})" unless vs.size == size - 2
|
2210
2273
|
vs.each do |v|
|
2211
2274
|
raise TypeError, "expected Vector, got #{v.class}" unless v.is_a? Vector
|
2212
|
-
|
2275
|
+
raise ErrDimensionMismatch unless v.size == size
|
2213
2276
|
end
|
2214
2277
|
case size
|
2215
2278
|
when 2
|
@@ -2249,7 +2312,7 @@ class Vector
|
|
2249
2312
|
|
2250
2313
|
#
|
2251
2314
|
# Returns the modulus (Pythagorean distance) of the vector.
|
2252
|
-
# Vector[5,8,2].r => 9.643650761
|
2315
|
+
# Vector[5,8,2].r # => 9.643650761
|
2253
2316
|
#
|
2254
2317
|
def magnitude
|
2255
2318
|
Math.sqrt(@elements.inject(0) {|v, e| v + e.abs2})
|
@@ -2272,7 +2335,7 @@ class Vector
|
|
2272
2335
|
# Returns a new vector with the same direction but with norm 1.
|
2273
2336
|
# v = Vector[5,8,2].normalize
|
2274
2337
|
# # => Vector[0.5184758473652127, 0.8295613557843402, 0.20739033894608505]
|
2275
|
-
# v.norm => 1.0
|
2338
|
+
# v.norm # => 1.0
|
2276
2339
|
#
|
2277
2340
|
def normalize
|
2278
2341
|
n = magnitude
|
@@ -2287,7 +2350,7 @@ class Vector
|
|
2287
2350
|
#
|
2288
2351
|
def angle_with(v)
|
2289
2352
|
raise TypeError, "Expected a Vector, got a #{v.class}" unless v.is_a?(Vector)
|
2290
|
-
|
2353
|
+
raise ErrDimensionMismatch if size != v.size
|
2291
2354
|
prod = magnitude * v.magnitude
|
2292
2355
|
raise ZeroVectorError, "Can't get angle of zero vector" if prod == 0
|
2293
2356
|
dot = inner_product(v)
|