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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76ae31753ed23d3cb449505dc8d64407f502f80723f5253f329e0d24309d6f04
4
- data.tar.gz: d79a3bd3a4ec37ce78f77c67c3b67820c1b11ff38ac867494eaab1ee4f9a7296
3
+ metadata.gz: dafdb5e3baa2132e9e57ffa5058e7a868a3cf82a9ac3433af6e41744dee5af5c
4
+ data.tar.gz: 76ab3fcd078ceae78238eed7bc479f6038fe24106199406c3caa03b934cd7b3a
5
5
  SHA512:
6
- metadata.gz: 53a78680becf3477e688d561a8494496a6c1aae69397087795129e422d16fdb0eb7282445de27a0143828a9989590b5a72a2694d6bf2436ca7e0bb79dcb0fec2
7
- data.tar.gz: b792b1ca5924a9b603a18a5fc7735b8e3b94ab2f795aadb1ba73e7e8012df086898f2fdeaceb9411ffc6b66e8cf1ff27c5b1ed4084c07485a389c6d9bb21fa2b
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
- Add this line to your application's Gemfile:
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
- Or install it yourself as:
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
- TODO: Write usage instructions here
27
+ ```ruby
28
+ require 'matrix'
29
+ m = Matrix[[1, 2], [3, 4]]
30
+ m.determinant # => -2
31
+ ```
28
32
 
29
33
  ## Development
30
34
 
@@ -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
- require "e2mmap"
15
+ require_relative "matrix/version"
16
16
 
17
17
  module ExceptionForMatrix # :nodoc:
18
- extend Exception2MessageMapper
19
- def_e2message(TypeError, "wrong argument type %s (expected %s)")
20
- def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
21
-
22
- def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
23
- def_exception("ErrNotRegular", "Not Regular Matrix")
24
- def_exception("ErrOperationNotDefined", "Operation(%s) can\\'t be defined: %s op %s")
25
- def_exception("ErrOperationNotImplemented", "Sorry, Operation(%s) not implemented: %s op %s")
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
- # => 25 93
49
- # -1 66
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
- # => 25 93
61
- # -1 66
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
- # => 25 -1
79
- # 93 66
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
- # => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
119
+ # # => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
93
120
  # m = Matrix.build(3) { rand }
94
- # => a 3x3 matrix with random elements
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
- # => 9 0 0
113
- # 0 5 0
114
- # 0 0 -3
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
- # => 5 0
132
- # 0 5
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
- # => 1 0
142
- # 0 1
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
- # => 0 0
156
- # 0 0
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
- # => 4 5 6
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
- # => 4
179
- # 5
180
- # 6
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
- # => true
220
+ # # => true
194
221
  # n = Matrix.empty(0, 3)
195
222
  # n == Matrix.columns([ [], [], [] ])
196
- # => true
223
+ # # => true
197
224
  # m * n
198
- # => Matrix[[0, 0, 0], [0, 0, 0]]
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
- Matrix.Raise ErrDimensionMismatch unless x.row_count == m.row_count && x.column_count == m.column_count
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 Matrix.rows, columns, [], etc... to create.
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
- Matrix.Raise ErrDimensionMismatch unless row_range.size == value.size
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
- Matrix.Raise ErrDimensionMismatch unless value.column_count == 1
416
+ raise ErrDimensionMismatch unless value.column_count == 1
379
417
  value = value.column(0)
380
- Matrix.Raise ErrDimensionMismatch unless row_range.size == value.size
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
- Matrix.Raise ErrDimensionMismatch unless value.row_count == 1
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
- Matrix.Raise ErrDimensionMismatch unless col_range.size == value.size
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
- # => 1 4
468
- # 9 16
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
- # Matrix[ [1,2], [3,4] ].each { |e| puts e }
514
- # # => prints the numbers 1 to 4
515
- # Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3]
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
- # => 9 0 0
666
- # 0 5 0
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
- # => 9 0 0
710
- # 0 0 0
711
- # 0 0 4
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
- # => -108
775
+ # # => -108
739
776
  #
740
777
  def cofactor(row, column)
741
778
  raise RuntimeError, "cofactor of empty matrix is not defined" if empty?
742
- Matrix.Raise ErrDimensionMismatch unless square?
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
- # => 9 -6
753
- # -3 7
789
+ # # => 9 -6
790
+ # # -3 7
754
791
  #
755
792
  def adjugate
756
- Matrix.Raise ErrDimensionMismatch unless square?
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
- # => 45
803
+ # # => 45
767
804
  #
768
805
  # Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0)
769
- # => Vector[3, -2]
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
856
- rows.each_with_index do |row, i|
857
- column_count.times do |j|
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 += row[k] * rows[k][j]
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrDimensionMismatch unless square?
949
- rows.each_with_index do |row, i|
950
- column_count.times do |j|
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 += row[k].conj * rows[k][j]
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
- # => 2 4
1017
- # 6 8
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
- rows = @rows.collect {|row|
1060
+ new_rows = @rows.collect {|row|
1023
1061
  row.collect {|e| e * m }
1024
1062
  }
1025
- return new_matrix rows, column_count
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
- Matrix.Raise ErrDimensionMismatch if column_count != m.row_count
1032
-
1033
- rows = Array.new(row_count) {|i|
1034
- Array.new(m.column_count) {|j|
1035
- (0 ... column_count).inject(0) do |vij, k|
1036
- vij + self[i, k] * m[k, j]
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
- return new_matrix rows, m.column_count
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
- # => 6 0
1050
- # -4 12
1089
+ # # => 6 0
1090
+ # # -4 12
1051
1091
  #
1052
1092
  def +(m)
1053
1093
  case m
1054
1094
  when Numeric
1055
- Matrix.Raise ErrOperationNotDefined, "+", self.class, m.class
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
- Matrix.Raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
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
- # => -8 2
1077
- # 8 1
1116
+ # # => -8 2
1117
+ # # 8 1
1078
1118
  #
1079
1119
  def -(m)
1080
1120
  case m
1081
1121
  when Numeric
1082
- Matrix.Raise ErrOperationNotDefined, "-", self.class, m.class
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
- Matrix.Raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count
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
- # => -7 1
1104
- # -3 -6
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
- # => 1 4
1124
- # 9 8
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
- # => -1 1
1135
- # 0 -1
1174
+ # # => -1 1
1175
+ # # 0 -1
1136
1176
  #
1137
1177
  def inverse
1138
- Matrix.Raise ErrDimensionMismatch unless square?
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
- Matrix.Raise ErrNotRegular if akk == 0
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
- # => 67 96
1194
- # 48 99
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
- Matrix.Raise ErrOperationNotDefined, "**", self.class, other.class
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
- # => 45
1291
+ # # => 45
1240
1292
  #
1241
1293
  def determinant
1242
- Matrix.Raise ErrDimensionMismatch unless square?
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
- # => 2
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
- # => 16
1447
+ # # => 16
1396
1448
  #
1397
1449
  def trace
1398
- Matrix.Raise ErrDimensionMismatch unless square?
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
- # => 1 2
1409
- # 3 4
1410
- # 5 6
1460
+ # # => 1 2
1461
+ # # 3 4
1462
+ # # 5 6
1411
1463
  # Matrix[[1,2], [3,4], [5,6]].transpose
1412
- # => 1 3 5
1413
- # 2 4 6
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
- # => 1+2i i 0
1473
- # 1 2 3
1524
+ # # => 1+2i i 0
1525
+ # # 1 2 3
1474
1526
  # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
1475
- # => 1-2i -i 0
1476
- # 1 2 3
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
- # => 1+2i i 0
1487
- # 1 2 3
1549
+ # # => 1+2i i 0
1550
+ # # 1 2 3
1488
1551
  # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
1489
- # => 2i i 0
1490
- # 0 0 0
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
- # => 1+2i i 0
1501
- # 1 2 3
1563
+ # # => 1+2i i 0
1564
+ # # 1 2 3
1502
1565
  # Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
1503
- # => 1 0 0
1504
- # 1 2 3
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
- # m.rect == [m.real, m.imag] # ==> true for all matrices m
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
- Scalar.Raise ErrOperationNotDefined, "+", @value.class, other.class
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
- Scalar.Raise ErrOperationNotDefined, "-", @value.class, other.class
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
- Scalar.Raise ErrOperationNotDefined, "/", @value.class, other.class
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
- Scalar.Raise ErrOperationNotDefined, "**", @value.class, other.class
1840
+ raise ErrOperationNotDefined, ["**", @value.class, other.class]
1778
1841
  when Matrix
1779
1842
  #other.powered_by(self)
1780
- Scalar.Raise ErrOperationNotImplemented, "**", @value.class, other.class
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
- Matrix.Raise ErrDimensionMismatch unless value.row_count == 1
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
- Vector.Raise ErrDimensionMismatch if size != v.size
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
- Vector.Raise ErrDimensionMismatch if size != v.size
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
- # => true
2087
+ # # => true
2025
2088
  #
2026
2089
  # Vector.independent?(Vector[1,2], Vector[2,4])
2027
- # => false
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
- Vector.Raise ErrDimensionMismatch unless v.size == vs.first.size
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
- # => true
2105
+ # # => true
2043
2106
  #
2044
2107
  # Vector[1,2].independent?(Vector[2,4])
2045
- # => false
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
- Vector.Raise ErrOperationNotDefined, "*", self.class, x.class
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
- Vector.Raise ErrDimensionMismatch if size != v.size
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
- Vector.Raise ErrDimensionMismatch if size != v.size
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
- Vector.Raise ErrOperationNotDefined, "/", self.class, x.class
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] => 47
2245
+ # Vector[4,7].inner_product Vector[10,1] # => 47
2183
2246
  #
2184
2247
  def inner_product(v)
2185
- Vector.Raise ErrDimensionMismatch if size != v.size
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] => Vector[0, 0, 1]
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
- Vector.Raise ErrDimensionMismatch unless v.size == size
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
- Vector.Raise ErrDimensionMismatch if size != v.size
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)