matrix 0.0.1 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: false
2
+ class Matrix
3
+ # Adapted from JAMA: http://math.nist.gov/javanumerics/jama/
4
+
5
+ #
6
+ # For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
7
+ # unit lower triangular matrix L, an n-by-n upper triangular matrix U,
8
+ # and a m-by-m permutation matrix P so that L*U = P*A.
9
+ # If m < n, then L is m-by-m and U is m-by-n.
10
+ #
11
+ # The LUP decomposition with pivoting always exists, even if the matrix is
12
+ # singular, so the constructor will never fail. The primary use of the
13
+ # LU decomposition is in the solution of square systems of simultaneous
14
+ # linear equations. This will fail if singular? returns true.
15
+ #
16
+
17
+ class LUPDecomposition
18
+ # Returns the lower triangular factor +L+
19
+
20
+ include Matrix::ConversionHelper
21
+
22
+ def l
23
+ Matrix.build(@row_count, [@column_count, @row_count].min) do |i, j|
24
+ if (i > j)
25
+ @lu[i][j]
26
+ elsif (i == j)
27
+ 1
28
+ else
29
+ 0
30
+ end
31
+ end
32
+ end
33
+
34
+ # Returns the upper triangular factor +U+
35
+
36
+ def u
37
+ Matrix.build([@column_count, @row_count].min, @column_count) do |i, j|
38
+ if (i <= j)
39
+ @lu[i][j]
40
+ else
41
+ 0
42
+ end
43
+ end
44
+ end
45
+
46
+ # Returns the permutation matrix +P+
47
+
48
+ def p
49
+ rows = Array.new(@row_count){Array.new(@row_count, 0)}
50
+ @pivots.each_with_index{|p, i| rows[i][p] = 1}
51
+ Matrix.send :new, rows, @row_count
52
+ end
53
+
54
+ # Returns +L+, +U+, +P+ in an array
55
+
56
+ def to_ary
57
+ [l, u, p]
58
+ end
59
+ alias_method :to_a, :to_ary
60
+
61
+ # Returns the pivoting indices
62
+
63
+ attr_reader :pivots
64
+
65
+ # Returns +true+ if +U+, and hence +A+, is singular.
66
+
67
+ def singular?
68
+ @column_count.times do |j|
69
+ if (@lu[j][j] == 0)
70
+ return true
71
+ end
72
+ end
73
+ false
74
+ end
75
+
76
+ # Returns the determinant of +A+, calculated efficiently
77
+ # from the factorization.
78
+
79
+ def det
80
+ if (@row_count != @column_count)
81
+ raise Matrix::ErrDimensionMismatch
82
+ end
83
+ d = @pivot_sign
84
+ @column_count.times do |j|
85
+ d *= @lu[j][j]
86
+ end
87
+ d
88
+ end
89
+ alias_method :determinant, :det
90
+
91
+ # Returns +m+ so that <tt>A*m = b</tt>,
92
+ # or equivalently so that <tt>L*U*m = P*b</tt>
93
+ # +b+ can be a Matrix or a Vector
94
+
95
+ def solve b
96
+ if (singular?)
97
+ raise Matrix::ErrNotRegular, "Matrix is singular."
98
+ end
99
+ if b.is_a? Matrix
100
+ if (b.row_count != @row_count)
101
+ raise Matrix::ErrDimensionMismatch
102
+ end
103
+
104
+ # Copy right hand side with pivoting
105
+ nx = b.column_count
106
+ m = @pivots.map{|row| b.row(row).to_a}
107
+
108
+ # Solve L*Y = P*b
109
+ @column_count.times do |k|
110
+ (k+1).upto(@column_count-1) do |i|
111
+ nx.times do |j|
112
+ m[i][j] -= m[k][j]*@lu[i][k]
113
+ end
114
+ end
115
+ end
116
+ # Solve U*m = Y
117
+ (@column_count-1).downto(0) do |k|
118
+ nx.times do |j|
119
+ m[k][j] = m[k][j].quo(@lu[k][k])
120
+ end
121
+ k.times do |i|
122
+ nx.times do |j|
123
+ m[i][j] -= m[k][j]*@lu[i][k]
124
+ end
125
+ end
126
+ end
127
+ Matrix.send :new, m, nx
128
+ else # same algorithm, specialized for simpler case of a vector
129
+ b = convert_to_array(b)
130
+ if (b.size != @row_count)
131
+ raise Matrix::ErrDimensionMismatch
132
+ end
133
+
134
+ # Copy right hand side with pivoting
135
+ m = b.values_at(*@pivots)
136
+
137
+ # Solve L*Y = P*b
138
+ @column_count.times do |k|
139
+ (k+1).upto(@column_count-1) do |i|
140
+ m[i] -= m[k]*@lu[i][k]
141
+ end
142
+ end
143
+ # Solve U*m = Y
144
+ (@column_count-1).downto(0) do |k|
145
+ m[k] = m[k].quo(@lu[k][k])
146
+ k.times do |i|
147
+ m[i] -= m[k]*@lu[i][k]
148
+ end
149
+ end
150
+ Vector.elements(m, false)
151
+ end
152
+ end
153
+
154
+ def initialize a
155
+ raise TypeError, "Expected Matrix but got #{a.class}" unless a.is_a?(Matrix)
156
+ # Use a "left-looking", dot-product, Crout/Doolittle algorithm.
157
+ @lu = a.to_a
158
+ @row_count = a.row_count
159
+ @column_count = a.column_count
160
+ @pivots = Array.new(@row_count)
161
+ @row_count.times do |i|
162
+ @pivots[i] = i
163
+ end
164
+ @pivot_sign = 1
165
+ lu_col_j = Array.new(@row_count)
166
+
167
+ # Outer loop.
168
+
169
+ @column_count.times do |j|
170
+
171
+ # Make a copy of the j-th column to localize references.
172
+
173
+ @row_count.times do |i|
174
+ lu_col_j[i] = @lu[i][j]
175
+ end
176
+
177
+ # Apply previous transformations.
178
+
179
+ @row_count.times do |i|
180
+ lu_row_i = @lu[i]
181
+
182
+ # Most of the time is spent in the following dot product.
183
+
184
+ kmax = [i, j].min
185
+ s = 0
186
+ kmax.times do |k|
187
+ s += lu_row_i[k]*lu_col_j[k]
188
+ end
189
+
190
+ lu_row_i[j] = lu_col_j[i] -= s
191
+ end
192
+
193
+ # Find pivot and exchange if necessary.
194
+
195
+ p = j
196
+ (j+1).upto(@row_count-1) do |i|
197
+ if (lu_col_j[i].abs > lu_col_j[p].abs)
198
+ p = i
199
+ end
200
+ end
201
+ if (p != j)
202
+ @column_count.times do |k|
203
+ t = @lu[p][k]; @lu[p][k] = @lu[j][k]; @lu[j][k] = t
204
+ end
205
+ k = @pivots[p]; @pivots[p] = @pivots[j]; @pivots[j] = k
206
+ @pivot_sign = -@pivot_sign
207
+ end
208
+
209
+ # Compute multipliers.
210
+
211
+ if (j < @row_count && @lu[j][j] != 0)
212
+ (j+1).upto(@row_count-1) do |i|
213
+ @lu[i][j] = @lu[i][j].quo(@lu[j][j])
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -1,3 +1,5 @@
1
- module Matrix
2
- VERSION = "0.0.1"
1
+ # frozen_string_literal: true
2
+
3
+ class Matrix
4
+ VERSION = "0.4.1"
3
5
  end
@@ -1,23 +1,29 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'matrix/version'
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require_relative "lib/matrix/version"
5
+ rescue LoadError
6
+ # for Ruby core repository
7
+ require_relative "version"
8
+ end
5
9
 
6
10
  Gem::Specification.new do |spec|
7
11
  spec.name = "matrix"
8
12
  spec.version = Matrix::VERSION
9
- spec.authors = ["Timo Borreck"]
10
- spec.email = ["timo@borreck.org"]
11
- spec.description = %q{This gem is under construction.}
12
- spec.summary = %q{This gem is under construction.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
13
+ spec.authors = ["Marc-Andre Lafortune"]
14
+ spec.email = ["ruby-core@marc-andre.ca"]
15
+
16
+ spec.summary = %q{An implementation of Matrix and Vector classes.}
17
+ spec.description = %q{An implementation of Matrix and Vector classes.}
18
+ spec.homepage = "https://github.com/ruby/matrix"
19
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
20
+ spec.required_ruby_version = ">= 2.5.0"
15
21
 
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/matrix.rb", "lib/matrix/eigenvalue_decomposition.rb", "lib/matrix/lup_decomposition.rb", "lib/matrix/version.rb", "matrix.gemspec"]
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
25
  spec.require_paths = ["lib"]
20
26
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "bundler"
22
28
  spec.add_development_dependency "rake"
23
29
  end
metadata CHANGED
@@ -1,80 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
- - Timo Borreck
8
- autorequire:
9
- bindir: bin
7
+ - Marc-Andre Lafortune
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-02-07 00:00:00.000000000 Z
11
+ date: 2021-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description: This gem is under construction.
41
+ description: An implementation of Matrix and Vector classes.
42
42
  email:
43
- - timo@borreck.org
43
+ - ruby-core@marc-andre.ca
44
44
  executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
- - .gitignore
48
+ - ".gitignore"
49
49
  - Gemfile
50
50
  - LICENSE.txt
51
51
  - README.md
52
52
  - Rakefile
53
+ - bin/console
54
+ - bin/setup
53
55
  - lib/matrix.rb
56
+ - lib/matrix/eigenvalue_decomposition.rb
57
+ - lib/matrix/lup_decomposition.rb
54
58
  - lib/matrix/version.rb
55
59
  - matrix.gemspec
56
- homepage: ''
60
+ homepage: https://github.com/ruby/matrix
57
61
  licenses:
58
- - MIT
62
+ - Ruby
63
+ - BSD-2-Clause
59
64
  metadata: {}
60
- post_install_message:
65
+ post_install_message:
61
66
  rdoc_options: []
62
67
  require_paths:
63
68
  - lib
64
69
  required_ruby_version: !ruby/object:Gem::Requirement
65
70
  requirements:
66
- - - '>='
71
+ - - ">="
67
72
  - !ruby/object:Gem::Version
68
- version: '0'
73
+ version: 2.5.0
69
74
  required_rubygems_version: !ruby/object:Gem::Requirement
70
75
  requirements:
71
- - - '>='
76
+ - - ">="
72
77
  - !ruby/object:Gem::Version
73
78
  version: '0'
74
79
  requirements: []
75
- rubyforge_project:
76
- rubygems_version: 2.1.5
77
- signing_key:
80
+ rubygems_version: 3.2.3
81
+ signing_key:
78
82
  specification_version: 4
79
- summary: This gem is under construction.
83
+ summary: An implementation of Matrix and Vector classes.
80
84
  test_files: []