matrix 0.1.0 → 0.4.2

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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Matrix
4
+ VERSION = "0.4.2"
5
+ end
data/matrix.gemspec CHANGED
@@ -1,21 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ require_relative "lib/matrix/version"
5
+ rescue LoadError
6
+ # for Ruby core repository
7
+ require_relative "version"
8
+ end
9
+
3
10
  Gem::Specification.new do |spec|
4
11
  spec.name = "matrix"
5
- spec.version = "0.1.0"
12
+ spec.version = Matrix::VERSION
6
13
  spec.authors = ["Marc-Andre Lafortune"]
7
14
  spec.email = ["ruby-core@marc-andre.ca"]
8
15
 
9
16
  spec.summary = %q{An implementation of Matrix and Vector classes.}
10
17
  spec.description = %q{An implementation of Matrix and Vector classes.}
11
18
  spec.homepage = "https://github.com/ruby/matrix"
12
- spec.license = "BSD-2-Clause"
19
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
20
+ spec.required_ruby_version = ">= 2.5.0"
13
21
 
14
- spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/matrix.rb", "matrix.gemspec"]
22
+ spec.files = ["LICENSE.txt", "lib/matrix.rb", "lib/matrix/eigenvalue_decomposition.rb", "lib/matrix/lup_decomposition.rb", "lib/matrix/version.rb", "matrix.gemspec"]
15
23
  spec.bindir = "exe"
16
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.executables = []
17
25
  spec.require_paths = ["lib"]
18
-
19
- spec.add_development_dependency "bundler"
20
- spec.add_development_dependency "rake"
21
26
  end
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-Andre Lafortune
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-12-04 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
11
+ date: 2021-06-18 00:00:00.000000000 Z
12
+ dependencies: []
41
13
  description: An implementation of Matrix and Vector classes.
42
14
  email:
43
15
  - ruby-core@marc-andre.ca
@@ -45,21 +17,18 @@ executables: []
45
17
  extensions: []
46
18
  extra_rdoc_files: []
47
19
  files:
48
- - ".gitignore"
49
- - ".travis.yml"
50
- - Gemfile
51
20
  - LICENSE.txt
52
- - README.md
53
- - Rakefile
54
- - bin/console
55
- - bin/setup
56
21
  - lib/matrix.rb
22
+ - lib/matrix/eigenvalue_decomposition.rb
23
+ - lib/matrix/lup_decomposition.rb
24
+ - lib/matrix/version.rb
57
25
  - matrix.gemspec
58
26
  homepage: https://github.com/ruby/matrix
59
27
  licenses:
28
+ - Ruby
60
29
  - BSD-2-Clause
61
30
  metadata: {}
62
- post_install_message:
31
+ post_install_message:
63
32
  rdoc_options: []
64
33
  require_paths:
65
34
  - lib
@@ -67,16 +36,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
36
  requirements:
68
37
  - - ">="
69
38
  - !ruby/object:Gem::Version
70
- version: '0'
39
+ version: 2.5.0
71
40
  required_rubygems_version: !ruby/object:Gem::Requirement
72
41
  requirements:
73
42
  - - ">="
74
43
  - !ruby/object:Gem::Version
75
44
  version: '0'
76
45
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.7.6
79
- signing_key:
46
+ rubygems_version: 3.3.0.dev
47
+ signing_key:
80
48
  specification_version: 4
81
49
  summary: An implementation of Matrix and Vector classes.
82
50
  test_files: []
data/.gitignore DELETED
@@ -1,9 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - ruby-head
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
-
5
- # Specify your gem's dependencies in matrix.gemspec
6
- gemspec
data/README.md DELETED
@@ -1,41 +0,0 @@
1
- # Matrix
2
-
3
- An implementation of `Matrix` and `Vector` classes.
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).
6
-
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
-
9
- ## Installation
10
-
11
- Add this line to your application's Gemfile:
12
-
13
- ```ruby
14
- gem 'matrix'
15
- ```
16
-
17
- And then execute:
18
-
19
- $ bundle
20
-
21
- Or install it yourself as:
22
-
23
- $ gem install matrix
24
-
25
- ## Usage
26
-
27
- TODO: Write usage instructions here
28
-
29
- ## Development
30
-
31
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
32
-
33
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
-
35
- ## Contributing
36
-
37
- Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/matrix.
38
-
39
- ## License
40
-
41
- The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
data/Rakefile DELETED
@@ -1,10 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test" << "test/lib"
6
- t.libs << "lib"
7
- t.test_files = FileList['test/**/test_*.rb']
8
- end
9
-
10
- task :default => [:test]
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "matrix"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)