numo-linalg 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -9
  3. data/Rakefile +17 -0
  4. data/ext/numo/linalg/blas/blas.c +20 -6
  5. data/ext/numo/linalg/blas/depend.erb +2 -2
  6. data/ext/numo/linalg/blas/extconf.rb +15 -42
  7. data/ext/numo/linalg/blas/numo_blas.h +6 -0
  8. data/ext/numo/linalg/blas/tmpl/mv.c +3 -2
  9. data/ext/numo/linalg/lapack/depend.erb +2 -2
  10. data/ext/numo/linalg/lapack/extconf.rb +14 -19
  11. data/ext/numo/linalg/lapack/gen/spec.rb +5 -0
  12. data/ext/numo/linalg/lapack/lapack.c +49 -6
  13. data/ext/numo/linalg/lapack/numo_lapack.h +3 -0
  14. data/ext/numo/linalg/lapack/tmpl/gqr.c +1 -1
  15. data/ext/numo/linalg/lapack/tmpl/sygvx.c +130 -0
  16. data/ext/numo/linalg/mkmf_linalg.rb +84 -0
  17. data/lib/numo/linalg/autoloader.rb +18 -3
  18. data/lib/numo/linalg/function.rb +317 -92
  19. data/lib/numo/linalg/loader.rb +70 -77
  20. data/lib/numo/linalg/version.rb +1 -1
  21. data/numo-linalg.gemspec +5 -3
  22. data/spec/linalg/autoloader_spec.rb +10 -0
  23. data/spec/linalg/function/cho_fact_spec.rb +31 -0
  24. data/spec/linalg/function/cho_inv_spec.rb +39 -0
  25. data/spec/linalg/function/cho_solve_spec.rb +66 -0
  26. data/spec/linalg/function/cholesky_spec.rb +43 -0
  27. data/spec/linalg/function/cond_spec.rb +57 -0
  28. data/spec/linalg/function/det_spec.rb +21 -0
  29. data/spec/linalg/function/dot_spec.rb +84 -0
  30. data/spec/linalg/function/eig_spec.rb +53 -0
  31. data/spec/linalg/function/eigh_spec.rb +81 -0
  32. data/spec/linalg/function/eigvals_spec.rb +27 -0
  33. data/spec/linalg/function/eigvalsh_spec.rb +60 -0
  34. data/spec/linalg/function/expm_spec.rb +36 -0
  35. data/spec/linalg/function/inv_spec.rb +57 -0
  36. data/spec/linalg/function/ldl_spec.rb +51 -0
  37. data/spec/linalg/function/lstsq_spec.rb +80 -0
  38. data/spec/linalg/function/lu_fact_spec.rb +34 -0
  39. data/spec/linalg/function/lu_inv_spec.rb +21 -0
  40. data/spec/linalg/function/lu_solve_spec.rb +40 -0
  41. data/spec/linalg/function/lu_spec.rb +46 -0
  42. data/spec/linalg/function/matmul_spec.rb +41 -0
  43. data/spec/linalg/function/matrix_power_spec.rb +31 -0
  44. data/spec/linalg/function/matrix_rank_spec.rb +33 -0
  45. data/spec/linalg/function/norm_spec.rb +81 -0
  46. data/spec/linalg/function/null_space_spec.rb +41 -0
  47. data/spec/linalg/function/orth_spec.rb +43 -0
  48. data/spec/linalg/function/pinv_spec.rb +48 -0
  49. data/spec/linalg/function/qr_spec.rb +82 -0
  50. data/spec/linalg/function/slogdet_spec.rb +21 -0
  51. data/spec/linalg/function/solve_spec.rb +98 -0
  52. data/spec/linalg/function/svd_spec.rb +88 -0
  53. data/spec/linalg/function/svdvals_spec.rb +40 -0
  54. data/spec/spec_helper.rb +55 -0
  55. metadata +107 -14
  56. data/spec/lapack_spec.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a9f783654dbe1c2f8ca4dbeef4030053d8e8c92a99f1ccf0fa0ecd551c90f90
4
- data.tar.gz: 46f3558e6bd86db15fb0d3ab9558e1f4e565ca844db500684b9eaac0e6ec57c7
3
+ metadata.gz: 8315eaaebc86b1e549f1dd1132ba0e25e895c10f6a68b7b461c734bb3fd7612e
4
+ data.tar.gz: ead727d78cff037a15476917751d0373e08abe1cce5cb14931ea8a82628ab8a1
5
5
  SHA512:
6
- metadata.gz: f1c478c9f017babd63b40dcea4eeb6ca9222226f680cc6870b01c1f305f54080ab7c035ead34c39d9f70aa431c6b2d9c9ec1be0642f7bab66eea32ee97c39363
7
- data.tar.gz: d55a4aa11afffbb51486007df3c80b221a3e90e990e86b76eadc996d560abf8d3e16df62aa25e3f65f050175dca8d45d5b791c1dc4b2b2c3ac66031da0c70c7b
6
+ metadata.gz: a228a21cc9e6cc3b44f7c11b66b1dcea76dbdc22e51b09e35ca62118a721dea4d4a6dcc729a0603f0aec64411d2c9c72d63ff922a2bb57ea0d93b5363bdab50b
7
+ data.tar.gz: d9651310d52d9f1c1e41caad01bb8f706fe1a631557eaed076cd355702a1ef1ea55e88fe9b2e29ba95476f55569410c5cc737230b67e0843b623844e61f3ece8
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Numo::Linalg : Linear Algebra library with BLAS/LAPACK binding to Numo::NArray
2
2
 
3
3
  [![Binder](http://mybinder.org/badge.svg)](http://mybinder.org/repo/ruby-numo/numo-linalg)
4
- [![Build Status](https://travis-ci.org/ruby-numo/numo-linalg.svg?branch=master)](https://travis-ci.org/ruby-numo/numo-linalg)
4
+ [![Build Status](https://github.com/ruby-numo/numo-linalg/workflows/build/badge.svg)](https://github.com/ruby-numo/numo-linalg/actions)
5
5
 
6
6
  [GitHub](https://github.com/ruby-numo/numo-linalg) |
7
7
  [RubyGems](https://rubygems.org/gems/numo-linalg)
@@ -11,15 +11,15 @@ Under development!
11
11
  ## Introduction
12
12
 
13
13
  This is a binding of BLAS/LAPACK for Numo::NArray using dynamic linking loader.
14
- This desgin allows you to change backend libraries without re-compiling.
14
+ This design 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
- * lu\_fact, lu\_inv, lu\_solve, cho\_fact, cho\_inv, cho\_solve
22
- qr, svd, svdvals
21
+ * lu, lu\_fact, lu\_inv, lu\_solve, ldl, cholesky, cho\_fact, cho\_inv, cho\_solve,
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
 
@@ -78,8 +78,12 @@ require "numo/linalg"
78
78
 
79
79
  ## Authors
80
80
 
81
- * Masahiro TANAKA
82
- * Makoto KISHIMOTO
81
+ * Masahiro Tanaka
82
+ * Makoto Kishimoto
83
+ * Atsushi Tatsuma
84
+
85
+ ## Acknowledgments
86
+
83
87
  * This work is partly supported by 2016 Ruby Association Grant.
84
88
 
85
89
  ## ToDo
data/Rakefile CHANGED
@@ -16,3 +16,20 @@ end
16
16
  task :cleandoc do
17
17
  sh "rm -r yard .yardoc"
18
18
  end
19
+
20
+ require 'rake/extensiontask'
21
+ Rake::ExtensionTask.new 'numo/linalg/blas'
22
+ Rake::ExtensionTask.new 'numo/linalg/lapack'
23
+
24
+ CLOBBER.include('lib/numo/linalg/site_conf.rb')
25
+ task :compile do
26
+ site_conf = Dir['./tmp/**/numo/linalg/blas/**/lib/site_conf.rb'].first
27
+ cp site_conf, 'lib/numo/linalg'
28
+ end
29
+
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |t|
32
+ t.rspec_opts = '--color --format documentation --require spec_helper'
33
+ end
34
+
35
+ task :default => [:clobber, :compile, :spec]
@@ -259,11 +259,17 @@ numo_cblas_check_func(void **func, const char *name)
259
259
  s = alloca(strlen(blas_prefix)+strlen(name)+1);
260
260
  strcpy(s,blas_prefix);
261
261
  strcat(s,name);
262
+ #if defined(HAVE_DLFCN_H)
262
263
  dlerror();
264
+ #endif
263
265
  *func = dlsym(blas_handle, s);
264
- error = dlerror();
265
- if (error != NULL) {
266
- rb_raise(rb_eRuntimeError, "%s", error);
266
+ #if defined(HAVE_DLFCN_H)
267
+ if ((error = dlerror()) != 0) {
268
+ func = 0;
269
+ }
270
+ #endif
271
+ if ( !func ) {
272
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", s);
267
273
  }
268
274
  }
269
275
  }
@@ -291,14 +297,22 @@ blas_s_dlopen(int argc, VALUE *argv, VALUE mod)
291
297
  if (i==2) {
292
298
  f = NUM2INT(flag);
293
299
  } else {
294
- f = RTLD_LAZY | RTLD_LOCAL;
300
+ f = RTLD_LAZY;
295
301
  }
302
+ #if defined(HAVE_DLFCN_H)
296
303
  dlerror();
304
+ #endif
297
305
  handle = dlopen(StringValueCStr(lib), f);
298
- error = dlerror();
299
- if (error != NULL) {
306
+ #if defined(HAVE_DLFCN_H)
307
+ if ( !handle && (error = dlerror()) ) {
300
308
  rb_raise(rb_eRuntimeError, "%s", error);
301
309
  }
310
+ #else
311
+ if ( !handle ) {
312
+ error = dlerror();
313
+ rb_raise(rb_eRuntimeError, "%s", error);
314
+ }
315
+ #endif
302
316
  blas_handle = handle;
303
317
  return Qnil;
304
318
  }
@@ -1,5 +1,5 @@
1
- COGEN=ruby gen/cogen.rb -l
2
- GENDEPS=gen/*.rb tmpl/*.c
1
+ COGEN=<%= "ruby #{__dir__}/gen/cogen.rb -l" %>
2
+ GENDEPS=<%= "#{__dir__}/gen/*.rb #{__dir__}/tmpl/*.c" %>
3
3
 
4
4
  <%
5
5
  srcs = %w[s d c z].map{|c| [c, "blas_#{c}.c"]}
@@ -1,35 +1,5 @@
1
1
  require 'mkmf'
2
- require 'numo/narray'
3
- require 'erb'
4
-
5
- ldirs = [
6
- dir_config("mkl")[1],
7
- dir_config("openblas")[1],
8
- dir_config("atlas")[1],
9
- dir_config("blas")[1],
10
- dir_config("lapack")[1],
11
- ]
12
- bked = with_config("backend")
13
-
14
- FileUtils.mkdir_p "lib"
15
- open("lib/site_conf.rb","w"){|f| f.write "
16
- module Numo
17
- module Linalg
18
- BACKEND = #{bked.inspect}
19
- MKL_LIBPATH = #{ldirs[0].inspect}
20
- OPENBLAS_LIBPATH = #{ldirs[1].inspect}
21
- ATLAS_LIBPATH = #{ldirs[2].inspect}
22
- BLAS_LIBPATH = #{ldirs[3].inspect}
23
- LAPACK_LIBPATH = #{ldirs[4].inspect}
24
- end
25
- end"}
26
-
27
- $LOAD_PATH.each do |x|
28
- if File.exist? File.join(x,'numo/numo/narray.h')
29
- $INCFLAGS = "-I#{x}/numo " + $INCFLAGS
30
- break
31
- end
32
- end
2
+ require_relative '../mkmf_linalg'
33
3
 
34
4
  srcs = %w(
35
5
  blas
@@ -40,13 +10,24 @@ blas_z
40
10
  )
41
11
  $objs = srcs.collect{|i| i+".o"}
42
12
 
43
- if !have_header('numo/narray.h')
13
+ dir_config("narray")
14
+
15
+ find_narray_h
16
+ if !have_header("numo/narray.h")
44
17
  puts "
45
18
  Header numo/narray.h was not found. Give pathname as follows:
46
19
  % ruby extconf.rb --with-narray-include=narray_h_dir"
47
20
  exit(1)
48
21
  end
49
22
 
23
+ if RUBY_PLATFORM =~ /mswin|cygwin|mingw/
24
+ find_libnarray_a
25
+ unless have_library("narray","nary_new")
26
+ puts "libnarray.a not found"
27
+ exit(1)
28
+ end
29
+ end
30
+
50
31
  if have_header("dlfcn.h")
51
32
  exit(1) unless have_library("dl")
52
33
  exit(1) unless have_func("dlopen")
@@ -54,14 +35,6 @@ elsif have_header("windows.h")
54
35
  exit(1) unless have_func("LoadLibrary")
55
36
  end
56
37
 
57
- dep_path = File.join(__dir__, "depend")
58
- File.open(dep_path, "w") do |dep|
59
- dep_erb_path = File.join(__dir__, "depend.erb")
60
- File.open(dep_erb_path, "r") do |dep_erb|
61
- erb = ERB.new(dep_erb.read)
62
- erb.filename = dep_erb_path
63
- dep.print(erb.result)
64
- end
65
- end
66
-
38
+ create_site_conf
39
+ create_depend(__dir__)
67
40
  create_makefile('numo/linalg/blas')
@@ -31,6 +31,12 @@ extern void numo_cblas_check_func(void **func, const char *name);
31
31
  #define SWAP_IFROW(order,a,b,tmp) \
32
32
  { if ((order)==CblasRowMajor) {(tmp)=(a);(a)=(b);(b)=(tmp);} }
33
33
 
34
+ #define SWAP_IFNOTRANS(trans,a,b,tmp) \
35
+ { if ((trans)==CblasNoTrans) {(tmp)=(a);(a)=(b);(b)=(tmp);} }
36
+
37
+ #define SWAP_IFTRANS(trans,a,b,tmp) \
38
+ { if ((trans)!=CblasNoTrans) {(tmp)=(a);(a)=(b);(b)=(tmp);} }
39
+
34
40
  #define SWAP_IFCOLTR(order,trans,a,b,tmp) \
35
41
  { if (((order)==CblasRowMajor && (trans)!=CblasNoTrans) || \
36
42
  ((order)!=CblasRowMajor && (trans)==CblasNoTrans)) \
@@ -79,7 +79,7 @@ static void
79
79
  opt("beta"),
80
80
  !is_ge && opt("side"),
81
81
  !is_ge && opt("uplo"),
82
- is_ge || is_tr && opt("trans"),
82
+ (is_ge || is_tr) && opt("trans"),
83
83
  opt("order")
84
84
  ].select{|x| x}.join("\n ")
85
85
  %>
@@ -143,9 +143,10 @@ static VALUE
143
143
  CHECK_DIM_GE(na2,1);
144
144
  nx = COL_SIZE(na2);
145
145
  #if GE
146
- SWAP_IFCOLTR(g.order,g.trans, ma,na, tmp);
146
+ SWAP_IFCOL(g.order, ma, na, tmp);
147
147
  g.m = ma;
148
148
  g.n = na;
149
+ SWAP_IFTRANS(g.trans, ma, na, tmp);
149
150
  #else
150
151
  CHECK_SQUARE("a",na1);
151
152
  #endif
@@ -1,5 +1,5 @@
1
- COGEN=ruby gen/cogen.rb -l
2
- GENDEPS=gen/*.rb tmpl/*.c
1
+ COGEN=<%= "ruby #{__dir__}/gen/cogen.rb -l" %>
2
+ GENDEPS=<%= "#{__dir__}/gen/*.rb #{__dir__}/tmpl/*.c" %>
3
3
 
4
4
  <%
5
5
  srcs = %w[s d c z].map{|c| [c, "lapack_#{c}.c"]}
@@ -1,13 +1,6 @@
1
1
  require 'mkmf'
2
2
  require 'numo/narray'
3
- require 'erb'
4
-
5
- $LOAD_PATH.each do |x|
6
- if File.exist? File.join(x,'numo/numo/narray.h')
7
- $INCFLAGS = "-I#{x}/numo " + $INCFLAGS
8
- break
9
- end
10
- end
3
+ require_relative '../mkmf_linalg'
11
4
 
12
5
  srcs = %w(
13
6
  lapack
@@ -18,13 +11,24 @@ lapack_z
18
11
  )
19
12
  $objs = srcs.collect{|i| i+".o"}
20
13
 
21
- if !have_header('numo/narray.h')
14
+ dir_config("narray")
15
+
16
+ find_narray_h
17
+ if !have_header("numo/narray.h")
22
18
  puts "
23
19
  Header numo/narray.h was not found. Give pathname as follows:
24
20
  % ruby extconf.rb --with-narray-include=narray_h_dir"
25
21
  exit(1)
26
22
  end
27
23
 
24
+ if RUBY_PLATFORM =~ /cygwin|mingw/
25
+ find_libnarray_a
26
+ unless have_library("narray","nary_new")
27
+ puts "libnarray.a not found"
28
+ exit(1)
29
+ end
30
+ end
31
+
28
32
  if have_header("dlfcn.h")
29
33
  exit(1) unless have_library("dl")
30
34
  exit(1) unless have_func("dlopen")
@@ -32,14 +36,5 @@ elsif have_header("windows.h")
32
36
  exit(1) unless have_func("LoadLibrary")
33
37
  end
34
38
 
35
- dep_path = File.join(__dir__, "depend")
36
- File.open(dep_path, "w") do |dep|
37
- dep_erb_path = File.join(__dir__, "depend.erb")
38
- File.open(dep_erb_path, "r") do |dep_erb|
39
- erb = ERB.new(dep_erb.read)
40
- erb.filename = dep_erb_path
41
- dep.print(erb.result)
42
- end
43
- end
44
-
39
+ create_depend(__dir__)
45
40
  create_makefile('numo/linalg/lapack')
@@ -6,6 +6,9 @@ def_id "jobz"
6
6
  def_id "jobvl"
7
7
  def_id "jobvr"
8
8
  def_id "trans"
9
+ def_id "range"
10
+ def_id "il"
11
+ def_id "iu"
9
12
  def_id "rcond"
10
13
  def_id "itype"
11
14
  def_id "norm"
@@ -58,11 +61,13 @@ when /c|z/
58
61
  decl "?heevd", "syev"
59
62
  decl "?hegv", "sygv"
60
63
  decl "?hegvd", "sygv"
64
+ decl "?hegvx", "sygvx"
61
65
  else
62
66
  decl "?syev"
63
67
  decl "?syevd", "syev"
64
68
  decl "?sygv"
65
69
  decl "?sygvd", "sygv"
70
+ decl "?sygvx"
66
71
  end
67
72
 
68
73
  # factorize
@@ -124,6 +124,35 @@ numo_lapacke_option_job(VALUE job, char true_char, char false_char)
124
124
  return 0;
125
125
  }
126
126
 
127
+ char
128
+ numo_lapacke_option_range(VALUE job, char true_char, char false_char)
129
+ {
130
+ char *ptr, c;
131
+
132
+ switch(TYPE(job)) {
133
+ case T_NIL:
134
+ case T_UNDEF:
135
+ case T_TRUE:
136
+ return true_char;
137
+ case T_FALSE:
138
+ return false_char;
139
+ case T_SYMBOL:
140
+ job = rb_sym2str(job);
141
+ case T_STRING:
142
+ ptr = RSTRING_PTR(job);
143
+ if (RSTRING_LEN(job) > 0) {
144
+ c = ptr[0];
145
+ if (c >= 'a' && c <= 'z') {
146
+ c -= 'a'-'A';
147
+ }
148
+ return c;
149
+ }
150
+ break;
151
+ }
152
+ rb_raise(rb_eArgError,"invalid value for JOB option");
153
+ return 0;
154
+ }
155
+
127
156
  char
128
157
  numo_lapacke_option_trans(VALUE trans)
129
158
  {
@@ -295,11 +324,17 @@ numo_lapacke_check_func(void **func, const char *name)
295
324
  s = alloca(strlen(lapack_prefix)+strlen(name)+1);
296
325
  strcpy(s,lapack_prefix);
297
326
  strcat(s,name);
327
+ #if defined(HAVE_DLFCN_H)
298
328
  dlerror();
329
+ #endif
299
330
  *func = dlsym(lapack_handle, s);
300
- error = dlerror();
301
- if (error != NULL) {
302
- rb_raise(rb_eRuntimeError, "%s", error);
331
+ #if defined(HAVE_DLFCN_H)
332
+ if ((error = dlerror()) != 0) {
333
+ func = 0;
334
+ }
335
+ #endif
336
+ if ( !func ) {
337
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", s);
303
338
  }
304
339
  }
305
340
  }
@@ -327,14 +362,22 @@ lapack_s_dlopen(int argc, VALUE *argv, VALUE mod)
327
362
  if (i==2) {
328
363
  f = NUM2INT(flag);
329
364
  } else {
330
- f = RTLD_LAZY | RTLD_LOCAL;
365
+ f = RTLD_LAZY;
331
366
  }
367
+ #if defined(HAVE_DLFCN_H)
332
368
  dlerror();
369
+ #endif
333
370
  handle = dlopen(StringValueCStr(lib), f);
334
- error = dlerror();
335
- if (error != NULL) {
371
+ #if defined(HAVE_DLFCN_H)
372
+ if ( !handle && (error = dlerror()) ) {
336
373
  rb_raise(rb_eRuntimeError, "%s", error);
337
374
  }
375
+ #else
376
+ if ( !handle ) {
377
+ error = dlerror();
378
+ rb_raise(rb_eRuntimeError, "%s", error);
379
+ }
380
+ #endif
338
381
  lapack_handle = handle;
339
382
  return Qnil;
340
383
  }
@@ -15,6 +15,9 @@ extern int numo_lapacke_option_order(VALUE order);
15
15
  #define option_job numo_lapacke_option_job
16
16
  extern char numo_lapacke_option_job(VALUE job, char true_char, char false_char);
17
17
 
18
+ #define option_range numo_lapacke_option_range
19
+ extern char numo_lapacke_option_range(VALUE range, char true_char, char false_char);
20
+
18
21
  #define option_trans numo_lapacke_option_trans
19
22
  extern char numo_lapacke_option_trans(VALUE trans);
20
23
 
@@ -30,7 +30,7 @@ static void
30
30
  SWAP_IFCOL(g->order,m,n);
31
31
  lda = NDL_STEP(lp,0) / sizeof(dtype);
32
32
 
33
- printf("order=%d m=%d n=%d k=%d lda=%d \n",g->order,m,n,k,lda);
33
+ //printf("order=%d m=%d n=%d k=%d lda=%d \n",g->order,m,n,k,lda);
34
34
 
35
35
  *info = (*func_p)(g->order, m, n, k, a, lda, tau);
36
36
  CHECK_ERROR(*info);