numo-linalg 0.1.3 → 0.1.4

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: ef1ecaaf8a71faee9a7cef26bc35fae50230224856ab5dd6186cee93e5cca69d
4
- data.tar.gz: f2e5e5944ad4832ef4ad4db05f6e94142fefb780e19282d94ece2a055cf447a0
3
+ metadata.gz: c7c0b667ffa1e3720ba31c4b03b984cbb2fb357c82df6d6ad4ce063be4f38fe4
4
+ data.tar.gz: 52ecb22fc5d7a483aa0fbe82b04bd38747457661f4f6846693d2b2bbb7c9c19b
5
5
  SHA512:
6
- metadata.gz: 3fcf1506aa63ccbba57208e358102ae0dc537cd80b530e4b359b07d01a7cb1da11261dfd6d7028224175ae0f38014ec0373b99fc339caa2b952ad48c0fb26fd7
7
- data.tar.gz: c7a9eb8b65719571120a6a122721e1eaadc240164e182a5095ff45018453a90f4cc48f99ef219305827beace8839bdebb0d27d35dfb5f64ec64f54d5406a8910
6
+ metadata.gz: 38a2dc9a2bb4af3c273a11c22213a4a6db25d8d93be85e51cf3b418717e92336a14beff65b1202b7215254701593ce15970cf063be502a17640d8bc9d70b12c0
7
+ data.tar.gz: 3f7b0c47d0ced6ba5a1a58b1298bb342712a37ed6c24103bd5a41d399aa94c4cac066e6c8791cb3f283fad398e4dafe796723d7aadceca2b2a99f439882ce46c
data/README.md CHANGED
@@ -13,13 +13,13 @@ Under development!
13
13
  This is a binding of BLAS/LAPACK for Numo::NArray using dynamic linking loader.
14
14
  This desgin allows you to change backend libraries without re-compiling.
15
15
 
16
- ### [Numo::Linalg API](http://ruby-numo.github.io/linalg/yard/Numo/Linalg.html)
16
+ ### [Numo::Linalg API](http://ruby-numo.github.io/numo-linalg/yard/Numo/Linalg.html)
17
17
 
18
18
  * Matrix and vector products
19
19
  * dot, matmul
20
20
  * Decomposition
21
21
  * lu, lu\_fact, lu\_inv, lu\_solve, ldl, cholesky, cho\_fact, cho\_inv, cho\_solve,
22
- qr, svd, svdvals
22
+ qr, svd, svdvals, orth, null_space
23
23
  * Matrix eigenvalues
24
24
  * eig, eigh, eigvals, eigvalsh
25
25
  * Norms and other numbers
@@ -29,8 +29,8 @@ This desgin allows you to change backend libraries without re-compiling.
29
29
 
30
30
  ### Low-level modules
31
31
 
32
- * [Numo::Linalg::Blas](http://ruby-numo.github.io/linalg/yard/Numo/Linalg/Blas.html) - Low-level BLAS functions
33
- * [Numo::Linalg::Lapack](http://ruby-numo.github.io/linalg/yard/Numo/Linalg/Lapack.html) - Low-level LAPACK functions
32
+ * [Numo::Linalg::Blas](http://ruby-numo.github.io/numo-linalg/yard/Numo/Linalg/Blas.html) - Low-level BLAS functions
33
+ * [Numo::Linalg::Lapack](http://ruby-numo.github.io/numo-linalg/yard/Numo/Linalg/Lapack.html) - Low-level LAPACK functions
34
34
 
35
35
  ## Installation
36
36
 
@@ -82,7 +82,7 @@ require "numo/linalg"
82
82
  * Makoto Kishimoto
83
83
  * Atsushi Tatsuma
84
84
 
85
- ## Acknowledgement
85
+ ## Acknowledgments
86
86
 
87
87
  * This work is partly supported by 2016 Ruby Association Grant.
88
88
 
@@ -89,14 +89,58 @@ module Numo; module Linalg
89
89
  func = blas_char(a, b) =~ /c|z/ ? :dotu : :dot
90
90
  Blas.call(func, a, b)
91
91
  else
92
- Blas.call(:gemv, b, a, trans:'t')
92
+ if b.contiguous?
93
+ trans = 't'
94
+ else
95
+ if b.fortran_contiguous?
96
+ trans = 'n'
97
+ b = b.transpose
98
+ else
99
+ trans = 't'
100
+ b = b.dup
101
+ end
102
+ end
103
+ Blas.call(:gemv, b, a, trans:trans)
93
104
  end
94
105
  else
95
106
  case b.ndim
96
107
  when 1
97
- Blas.call(:gemv, a, b)
108
+ if a.contiguous?
109
+ trans = 'n'
110
+ else
111
+ if a.fortran_contiguous?
112
+ trans = 't'
113
+ a = a.transpose
114
+ else
115
+ trans = 'n'
116
+ a = a.dup
117
+ end
118
+ end
119
+ Blas.call(:gemv, a, b, trans:trans)
98
120
  else
99
- Blas.call(:gemm, a, b)
121
+ if a.contiguous?
122
+ transa = 'n'
123
+ else
124
+ if a.fortran_contiguous?
125
+ transa = 't'
126
+ a = a.transpose
127
+ else
128
+ transa = 'n'
129
+ a = a.dup
130
+ end
131
+ end
132
+ if b.contiguous?
133
+ transb = 'n'
134
+ else
135
+ if b.fortran_contiguous?
136
+ transb='t'
137
+ b = b.transpose
138
+ else
139
+ transb='n'
140
+ b = b.dup
141
+ end
142
+ end
143
+ Blas.call(:gemm, a, b, transa:transa, transb:transb)
100
144
  end
101
145
  end
102
146
  end
@@ -296,6 +340,42 @@ module Numo; module Linalg
296
340
  end
297
341
  end
298
342
 
343
+ # Computes an orthonormal basis for the range of matrix A.
344
+ #
345
+ # @param a [Numo::NArray] m-by-n matrix A (>= 2-dimensional NArray).
346
+ # @param rcond [Float] (optional)
347
+ # rcond is used to determine the effective rank of A.
348
+ # Singular values `s[i] <= rcond * s.max` are treated as zero.
349
+ # If rcond < 0, machine precision is used instead.
350
+ # @return [Numo::NArray] The orthonormal basis for the range of matrix A.
351
+
352
+ def orth(a, rcond: -1)
353
+ raise NArray::ShapeError, '2-d array is required' if a.ndim < 2
354
+ s, u, = svd(a)
355
+ tol = s.max * (rcond.nil? || rcond < 0 ? a.class::EPSILON * a.shape.max : rcond)
356
+ k = (s > tol).count
357
+ u[true, 0...k]
358
+ end
359
+
360
+ # Computes an orthonormal basis for the null space of matrix A.
361
+ #
362
+ # @param a [Numo::NArray] m-by-n matrix A (>= 2-dimensional NArray).
363
+ # @param rcond [Float] (optional)
364
+ # rcond is used to determine the effective rank of A.
365
+ # Singular values `s[i] <= rcond * s.max` are treated as zero.
366
+ # If rcond < 0, machine precision is used instead.
367
+ # @return [Numo::NArray] The orthonormal basis for the null space of matrix A.
368
+
369
+ def null_space(a, rcond: -1)
370
+ raise NArray::ShapeError, '2-d array is required' if a.ndim < 2
371
+ s, _u, vh = svd(a)
372
+ tol = s.max * (rcond.nil? || rcond < 0 ? a.class::EPSILON * a.shape.max : rcond)
373
+ k = (s > tol).count
374
+ return a.class.new if k == vh.shape[0]
375
+ r = vh[k..-1, true].transpose.dup
376
+ blas_char(vh) =~ /c|z/ ? r.conj : r
377
+ end
378
+
299
379
  # Computes an LU factorization of a M-by-N matrix A
300
380
  # using partial pivoting with row interchanges.
301
381
  #
@@ -1,5 +1,5 @@
1
1
  module Numo
2
2
  module Linalg
3
- VERSION = "0.1.3"
3
+ VERSION = "0.1.4"
4
4
  end
5
5
  end
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.extensions = ["ext/numo/linalg/blas/extconf.rb",
21
21
  "ext/numo/linalg/lapack/extconf.rb"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.3"
24
- spec.add_development_dependency "rake", "~> 12.0"
25
- spec.add_development_dependency "rspec", "~> 3.0"
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
26
  spec.add_runtime_dependency "numo-narray", ">= 0.9.0.7"
27
27
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Numo::Linalg do
6
+ describe 'null_space' do
7
+ let(:r) { 2 }
8
+ let(:m) { 6 }
9
+ let(:n) { 4 }
10
+ let(:mat_a) { rand_rect_real_mat(m, r).dot(rand_rect_real_mat(r, n)) }
11
+ let(:mat_b) { rand_rect_complex_mat(m, r).dot(rand_rect_complex_mat(r, n)) }
12
+ let(:mat_c) { mat_a + 1.0e-6 * Numo::DFloat.new(m, n).rand }
13
+
14
+ it 'raises ShapeError given a vector' do
15
+ expect { described_class.lu(Numo::DFloat.new(3).rand) }.to raise_error(Numo::NArray::ShapeError)
16
+ end
17
+
18
+ it 'calculates an orthonormal basis for the null space of a real matrix' do
19
+ basis = described_class.null_space(mat_a)
20
+ expect(basis.shape[0]).to eq(n)
21
+ expect(basis.shape[1]).to eq(r)
22
+ expect((basis.transpose.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
23
+ end
24
+
25
+ it 'calculates an orthonormal basis for the null space of a complex matrix' do
26
+ basis = described_class.null_space(mat_b)
27
+ expect(basis.shape[0]).to eq(n)
28
+ expect(basis.shape[1]).to eq(r)
29
+ expect((basis.transpose.conj.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
30
+ end
31
+
32
+ it 'calculates an orthonormal basis according to the given rcond value' do
33
+ basis = described_class.null_space(mat_c, rcond: 1.0e-4)
34
+ expect(basis.shape[0]).to eq(n)
35
+ expect(basis.shape[1]).to eq(r)
36
+ expect((basis.transpose.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
37
+ basis = described_class.null_space(mat_c, rcond: 1.0e-8)
38
+ expect(basis.shape).to be_empty
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Numo::Linalg do
6
+ describe 'orth' do
7
+ let(:r) { 2 }
8
+ let(:m) { 6 }
9
+ let(:n) { 3 }
10
+ let(:mat_a) { rand_rect_real_mat(m, r).dot(rand_rect_real_mat(r, n)) }
11
+ let(:mat_b) { rand_rect_complex_mat(m, r).dot(rand_rect_complex_mat(r, n)) }
12
+ let(:mat_c) { mat_a + 1.0e-6 * Numo::DFloat.new(m, n).rand }
13
+
14
+ it 'raises ShapeError given a vector' do
15
+ expect { described_class.lu(Numo::DFloat.new(3).rand) }.to raise_error(Numo::NArray::ShapeError)
16
+ end
17
+
18
+ it 'calculates an orthonormal basis for the range of a real matrix' do
19
+ basis = described_class.orth(mat_a)
20
+ expect(basis.shape[0]).to eq(m)
21
+ expect(basis.shape[1]).to eq(r)
22
+ expect((basis.transpose.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
23
+ end
24
+
25
+ it 'calculates an orthonormal basis for the range of a complex matrix' do
26
+ basis = described_class.orth(mat_b)
27
+ expect(basis.shape[0]).to eq(m)
28
+ expect(basis.shape[1]).to eq(r)
29
+ expect((basis.transpose.conj.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
30
+ end
31
+
32
+ it 'calculates an orthonormal basis according to the given rcond value' do
33
+ basis = described_class.orth(mat_c, rcond: 1.0e-4)
34
+ expect(basis.shape[0]).to eq(m)
35
+ expect(basis.shape[1]).to eq(r)
36
+ expect((basis.transpose.dot(basis) - Numo::DFloat.eye(r)).abs.max).to be < ERR_TOL
37
+ basis = described_class.orth(mat_c, rcond: 1.0e-8)
38
+ expect(basis.shape[0]).to eq(m)
39
+ expect(basis.shape[1]).to eq(n)
40
+ expect((basis.transpose.dot(basis) - Numo::DFloat.eye(n)).abs.max).to be < ERR_TOL
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numo-linalg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahiro TANAKA
@@ -9,50 +9,50 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-08-23 00:00:00.000000000 Z
12
+ date: 2019-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1.3'
20
+ version: '0'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '1.3'
27
+ version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '12.0'
34
+ version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '12.0'
41
+ version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '3.0'
48
+ version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: '3.0'
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: numo-narray
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -185,6 +185,8 @@ files:
185
185
  - spec/linalg/function/matrix_power_spec.rb
186
186
  - spec/linalg/function/matrix_rank_spec.rb
187
187
  - spec/linalg/function/norm_spec.rb
188
+ - spec/linalg/function/null_space_spec.rb
189
+ - spec/linalg/function/orth_spec.rb
188
190
  - spec/linalg/function/pinv_spec.rb
189
191
  - spec/linalg/function/qr_spec.rb
190
192
  - spec/linalg/function/slogdet_spec.rb
@@ -211,8 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
213
  - !ruby/object:Gem::Version
212
214
  version: '0'
213
215
  requirements: []
214
- rubyforge_project:
215
- rubygems_version: 2.7.3
216
+ rubygems_version: 3.0.1
216
217
  signing_key:
217
218
  specification_version: 4
218
219
  summary: Ruby/Numo Linear Algebra library with BLAS/LAPACK
@@ -240,6 +241,8 @@ test_files:
240
241
  - spec/linalg/function/matrix_power_spec.rb
241
242
  - spec/linalg/function/matrix_rank_spec.rb
242
243
  - spec/linalg/function/norm_spec.rb
244
+ - spec/linalg/function/null_space_spec.rb
245
+ - spec/linalg/function/orth_spec.rb
243
246
  - spec/linalg/function/pinv_spec.rb
244
247
  - spec/linalg/function/qr_spec.rb
245
248
  - spec/linalg/function/slogdet_spec.rb