matrix 0.0.1 → 0.4.1

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.
@@ -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: []