numo-linalg 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7c0b667ffa1e3720ba31c4b03b984cbb2fb357c82df6d6ad4ce063be4f38fe4
4
- data.tar.gz: 52ecb22fc5d7a483aa0fbe82b04bd38747457661f4f6846693d2b2bbb7c9c19b
3
+ metadata.gz: f1a7f32e07db68cc87340dc3245d9205026bd33c4ebc18b1cbef28f605f1a1d6
4
+ data.tar.gz: 1cb21ea35b2dacb1fb02d44317fb3684d9827635e4191aa7ecffd069edd214b1
5
5
  SHA512:
6
- metadata.gz: 38a2dc9a2bb4af3c273a11c22213a4a6db25d8d93be85e51cf3b418717e92336a14beff65b1202b7215254701593ce15970cf063be502a17640d8bc9d70b12c0
7
- data.tar.gz: 3f7b0c47d0ced6ba5a1a58b1298bb342712a37ed6c24103bd5a41d399aa94c4cac066e6c8791cb3f283fad398e4dafe796723d7aadceca2b2a99f439882ce46c
6
+ metadata.gz: c6125b1b665a2fbd87ecda093e1afea1ef85ca057e62921d95fa424dbe7e30d41d26c5c4caca57719d4c284ec33e179508b13d12c4de5e535c65c186eedc42eb
7
+ data.tar.gz: 1d7b3ac0fa98d70bb772674b4491d4d0285ef3303668a59299075c7a1595ff1796df745b73c30f34e295260d0b79df0aaf395b2742a912a292c1a618d92f116b
@@ -19,13 +19,15 @@ module Numo
19
19
  # @return [String] name of loaded backend library (mkl/openblas/lapack)
20
20
  def load_library
21
21
  mkl_dirs = ['/opt/intel/lib', '/opt/intel/lib64', '/opt/intel/mkl/lib', '/opt/intel/mkl/lib64']
22
- openblas_dirs = ['/opt/openblas/lib', '/opt/openblas/lib64', '/usr/local/opt/openblas/lib']
22
+ openblas_dirs = ['/opt/OpenBLAS/lib', '/opt/OpenBLAS/lib64', '/opt/openblas/lib', '/opt/openblas/lib64',
23
+ '/usr/local/opt/openblas/lib']
23
24
  atlas_dirs = ['/opt/atlas/lib', '/opt/atlas/lib64',
24
25
  '/usr/lib/atlas', '/usr/lib64/atlas', '/usr/local/opt/atlas/lib']
25
26
  lapacke_dirs = ['/opt/lapack/lib', '/opt/lapack/lib64', '/opt/local/lib/lapack',
26
27
  '/usr/local/opt/lapack/lib']
27
28
  opt_dirs = ['/opt/local/lib', '/opt/local/lib64', '/opt/lib', '/opt/lib64']
28
- base_dirs = ['/usr/local/lib', '/usr/local/lib64', '/usr/lib', '/usr/lib64']
29
+ base_dirs = ['/usr/local/lib', '/usr/local/lib64', '/usr/lib', '/usr/lib64',
30
+ "/usr/lib/#{RbConfig::CONFIG['host_cpu']}-#{RbConfig::CONFIG['host_os']}"]
29
31
  base_dirs.unshift(*ENV['LD_LIBRARY_PATH'].split(':')) unless ENV['LD_LIBRARY_PATH'].nil?
30
32
 
31
33
  mkl_libs = find_mkl_libs([*base_dirs, *opt_dirs, *mkl_dirs])
@@ -12,12 +12,19 @@ module Numo; module Linalg
12
12
  # defined from data-types of arguments.
13
13
  # @param [Symbol] func function name without BLAS char.
14
14
  # @param args arguments passed to Blas function.
15
+ # @param kwargs keyword arguments passed to Blas function.
15
16
  # @example
16
17
  # c = Numo::Linalg::Blas.call(:gemm, a, b)
17
- def self.call(func,*args)
18
+ def self.call(func, *args, **kwargs)
18
19
  fn = (Linalg.blas_char(*args) + func.to_s).to_sym
19
20
  fn = FIXNAME[fn] || fn
20
- send(fn,*args)
21
+ if kwargs.empty?
22
+ # This conditional branch is necessary to prevent ArgumentError
23
+ # that occurs in Ruby 2.6 or earlier.
24
+ send(fn, *args)
25
+ else
26
+ send(fn, *args, **kwargs)
27
+ end
21
28
  end
22
29
 
23
30
  end
@@ -34,12 +41,19 @@ module Numo; module Linalg
34
41
  # defined from data-types of arguments.
35
42
  # @param [Symbol,String] func function name without BLAS char.
36
43
  # @param args arguments passed to Lapack function.
44
+ # @param kwargs keyword arguments passed to Lapack function.
37
45
  # @example
38
46
  # s = Numo::Linalg::Lapack.call(:gesv, a)
39
- def self.call(func,*args)
47
+ def self.call(func, *args, **kwargs)
40
48
  fn = (Linalg.blas_char(*args) + func.to_s).to_sym
41
49
  fn = FIXNAME[fn] || fn
42
- send(fn,*args)
50
+ if kwargs.empty?
51
+ # This conditional branch is necessary to prevent ArgumentError
52
+ # that occurs in Ruby 2.6 or earlier.
53
+ send(fn, *args)
54
+ else
55
+ send(fn, *args, **kwargs)
56
+ end
43
57
  end
44
58
 
45
59
  end
@@ -1084,14 +1098,11 @@ module Numo; module Linalg
1084
1098
  when n
1085
1099
  resids = (x[n..-1,true].abs**2).sum(axis:0)
1086
1100
  when NArray
1087
- if true
1088
- resids = (x[false,n..-1,true].abs**2).sum(axis:-2)
1089
- else
1090
- resids = x[false,0,true].new_zeros
1091
- mask = rank.eq(n)
1092
- # NArray does not suppurt this yet.
1093
- resids[mask,true] = (x[mask,n..-1,true].abs**2).sum(axis:-2)
1094
- end
1101
+ resids = (x[false,n..-1,true].abs**2).sum(axis:-2)
1102
+ ## NArray does not suppurt this yet.
1103
+ # resids = x[false,0,true].new_zeros
1104
+ # mask = rank.eq(n)
1105
+ # resids[mask,true] = (x[mask,n..-1,true].abs**2).sum(axis:-2)
1095
1106
  end
1096
1107
  end
1097
1108
  x = x[false,0...n,true]
@@ -1163,6 +1174,49 @@ module Numo; module Linalg
1163
1174
  end
1164
1175
  end
1165
1176
 
1177
+ # Compute the matrix exponential using Pade approximation method.
1178
+ #
1179
+ # @param a [Numo::NArray] square matrix (>= 2-dimensinal NArray)
1180
+ # @param ord [Integer] order of approximation
1181
+ # @return [Numo::NArray]
1182
+ # @example
1183
+ # a = Numo::Linalg.expm(Numo::DFloat.zeros([2,2]))
1184
+ # => Numo::DFloat#shape=[2,2]
1185
+ # [[1, 0],
1186
+ # [0, 1]]
1187
+ # b = Numo::Linalg.expm(Numo::DFloat[[1, 2], [-1, 3]] * Complex::I)
1188
+ # => Numo::DComplex#shape=[2,2]
1189
+ # [[0.426459+1.89218i, -2.13721-0.978113i],
1190
+ # [1.06861+0.489056i, -1.71076+0.914063i]]
1191
+
1192
+ def expm(a, ord=8)
1193
+ raise NArray::ShapeError, 'matrix a is not square matrix' if a.shape[0] != a.shape[1]
1194
+
1195
+ inf_norm = norm(a, 'inf')
1196
+ n_squarings = inf_norm.zero? ? 0 : [0, Math.log2(inf_norm).ceil.to_i].max
1197
+ a = a / (2**n_squarings)
1198
+
1199
+ sz_mat = a.shape[0]
1200
+ c = 1
1201
+ s = -1
1202
+ x = Numo::DFloat.eye(sz_mat)
1203
+ n = Numo::DFloat.eye(sz_mat)
1204
+ d = Numo::DFloat.eye(sz_mat)
1205
+
1206
+ (1..ord).each do |k|
1207
+ c *= (ord - k + 1).fdiv((2 * ord - k + 1) * k)
1208
+ x = a.dot(x)
1209
+ cx = c * x
1210
+ n += cx
1211
+ d += s * cx
1212
+ s *= -1
1213
+ end
1214
+
1215
+ res = solve(d, n)
1216
+ n_squarings.times { res = res.dot(res) }
1217
+ res
1218
+ end
1219
+
1166
1220
  # @!visibility private
1167
1221
  def _make_complex_eigvecs(w, vin) # :nodoc:
1168
1222
  v = w.class.cast(vin)
@@ -1,5 +1,5 @@
1
1
  module Numo
2
2
  module Linalg
3
- VERSION = "0.1.4"
3
+ VERSION = "0.1.5"
4
4
  end
5
5
  end
@@ -23,5 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec"
26
- spec.add_runtime_dependency "numo-narray", ">= 0.9.0.7"
26
+ spec.add_runtime_dependency "numo-narray", ">= 0.9.1.4"
27
27
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Numo::Linalg do
6
+ describe 'det' do
7
+ it 'raises ShapeError given a rectangular matrix as matrix A' do
8
+ expect { described_class.expm(Numo::DFloat.new(2, 3).rand) }.to raise_error(Numo::NArray::ShapeError)
9
+ end
10
+
11
+ it 'calculates matrix exponential of matrix without full eigenvectors' do
12
+ e = Math.exp(1)
13
+ err = (described_class.expm(Numo::DFloat[[1, 2], [0, 1]]) - Numo::DFloat[[e, 2 * e], [0, e]]).abs.sum(1).max
14
+ expect(err).to be < 1e-6
15
+ end
16
+
17
+ it 'calculates matrix exponential for matrix with large norm' do
18
+ tmp = Numo::DFloat[[-0.0995741, 0.0746806], [-0.199148, 0.149361]]
19
+ err = (described_class.expm(Numo::DFloat[[-147, 72], [-192, 93]]) - tmp).abs.sum(1).max
20
+ expect(err).to be < 1e-6
21
+ end
22
+
23
+ it 'calculates matrix exponential for diagonal matrix' do
24
+ err = (described_class.expm(Numo::DFloat[2, 3].diag) - Numo::NMath.exp(Numo::DFloat[2, 3]).diag).abs.sum(1).max
25
+ expect(err).to be < 1e-6
26
+ end
27
+
28
+ it 'returns identity matrix when given zero matrix' do
29
+ expect(described_class.expm(Numo::DFloat.zeros([2, 2]))).to eq(Numo::DFloat.eye(2))
30
+ end
31
+
32
+ it 'returns complex matrix when given complex matrix' do
33
+ expect(described_class.expm(rand_rect_complex_mat(2, 2))).to be_a(Numo::DComplex)
34
+ end
35
+ end
36
+ 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.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masahiro TANAKA
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-10 00:00:00.000000000 Z
12
+ date: 2019-12-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 0.9.0.7
62
+ version: 0.9.1.4
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 0.9.0.7
69
+ version: 0.9.1.4
70
70
  description: Ruby/Numo Linear Algebra library with interface to BLAS/LAPACK.
71
71
  email:
72
72
  - masa16.tanaka@gmail.com
@@ -174,6 +174,7 @@ files:
174
174
  - spec/linalg/function/eigh_spec.rb
175
175
  - spec/linalg/function/eigvals_spec.rb
176
176
  - spec/linalg/function/eigvalsh_spec.rb
177
+ - spec/linalg/function/expm_spec.rb
177
178
  - spec/linalg/function/inv_spec.rb
178
179
  - spec/linalg/function/ldl_spec.rb
179
180
  - spec/linalg/function/lstsq_spec.rb
@@ -213,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
214
  - !ruby/object:Gem::Version
214
215
  version: '0'
215
216
  requirements: []
216
- rubygems_version: 3.0.1
217
+ rubygems_version: 3.1.2
217
218
  signing_key:
218
219
  specification_version: 4
219
220
  summary: Ruby/Numo Linear Algebra library with BLAS/LAPACK
@@ -230,6 +231,7 @@ test_files:
230
231
  - spec/linalg/function/eigh_spec.rb
231
232
  - spec/linalg/function/eigvals_spec.rb
232
233
  - spec/linalg/function/eigvalsh_spec.rb
234
+ - spec/linalg/function/expm_spec.rb
233
235
  - spec/linalg/function/inv_spec.rb
234
236
  - spec/linalg/function/ldl_spec.rb
235
237
  - spec/linalg/function/lstsq_spec.rb