matrix 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Version](https://badge.fury.io/rb/matrix.svg)](https://badge.fury.io/rb/matrix) [![Default Gem](https://img.shields.io/badge/stdgem-default-9c1260.svg)](https://stdgems.org/matrix/) [![Travis](https://travis-ci.com/ruby/matrix.svg)](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)
|