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 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)