numo-linalg-alt 0.5.0 → 0.7.0

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/README.md +47 -5
  4. data/ext/numo/linalg/blas/blas_common.h +30 -0
  5. data/ext/numo/linalg/blas/blas_util.c +39 -0
  6. data/ext/numo/linalg/blas/blas_util.h +11 -0
  7. data/ext/numo/linalg/{converter.h → blas/converter.h} +0 -2
  8. data/ext/numo/linalg/blas/dot.c +1 -1
  9. data/ext/numo/linalg/blas/dot.h +1 -6
  10. data/ext/numo/linalg/blas/dot_sub.c +1 -1
  11. data/ext/numo/linalg/blas/dot_sub.h +1 -6
  12. data/ext/numo/linalg/blas/gemm.c +21 -21
  13. data/ext/numo/linalg/blas/gemm.h +3 -9
  14. data/ext/numo/linalg/blas/gemv.c +10 -10
  15. data/ext/numo/linalg/blas/gemv.h +3 -9
  16. data/ext/numo/linalg/blas/nrm2.c +1 -1
  17. data/ext/numo/linalg/blas/nrm2.h +1 -6
  18. data/ext/numo/linalg/extconf.rb +33 -6
  19. data/ext/numo/linalg/lapack/gebal.h +1 -1
  20. data/ext/numo/linalg/lapack/gees.c +4 -4
  21. data/ext/numo/linalg/lapack/gees.h +1 -1
  22. data/ext/numo/linalg/lapack/geev.c +8 -24
  23. data/ext/numo/linalg/lapack/geev.h +1 -1
  24. data/ext/numo/linalg/lapack/gehrd.h +1 -1
  25. data/ext/numo/linalg/lapack/gelsd.h +1 -1
  26. data/ext/numo/linalg/lapack/geqrf.h +1 -1
  27. data/ext/numo/linalg/lapack/gerqf.h +1 -1
  28. data/ext/numo/linalg/lapack/gesdd.h +1 -1
  29. data/ext/numo/linalg/lapack/gesv.h +1 -1
  30. data/ext/numo/linalg/lapack/gesvd.h +1 -1
  31. data/ext/numo/linalg/lapack/getrf.h +1 -1
  32. data/ext/numo/linalg/lapack/getri.h +1 -1
  33. data/ext/numo/linalg/lapack/getrs.h +1 -1
  34. data/ext/numo/linalg/lapack/gges.c +4 -4
  35. data/ext/numo/linalg/lapack/gges.h +1 -1
  36. data/ext/numo/linalg/lapack/heev.c +1 -1
  37. data/ext/numo/linalg/lapack/heev.h +1 -1
  38. data/ext/numo/linalg/lapack/heevd.c +1 -1
  39. data/ext/numo/linalg/lapack/heevd.h +1 -1
  40. data/ext/numo/linalg/lapack/heevr.c +1 -1
  41. data/ext/numo/linalg/lapack/heevr.h +1 -1
  42. data/ext/numo/linalg/lapack/hegv.c +1 -1
  43. data/ext/numo/linalg/lapack/hegv.h +1 -1
  44. data/ext/numo/linalg/lapack/hegvd.c +1 -1
  45. data/ext/numo/linalg/lapack/hegvd.h +1 -1
  46. data/ext/numo/linalg/lapack/hegvx.c +1 -1
  47. data/ext/numo/linalg/lapack/hegvx.h +1 -1
  48. data/ext/numo/linalg/lapack/hetrf.h +1 -1
  49. data/ext/numo/linalg/lapack/lange.h +1 -1
  50. data/ext/numo/linalg/lapack/lapack_util.c +57 -0
  51. data/ext/numo/linalg/lapack/lapack_util.h +27 -0
  52. data/ext/numo/linalg/lapack/orghr.h +1 -1
  53. data/ext/numo/linalg/lapack/orgqr.h +1 -1
  54. data/ext/numo/linalg/lapack/orgrq.h +1 -1
  55. data/ext/numo/linalg/lapack/potrf.h +1 -1
  56. data/ext/numo/linalg/lapack/potri.h +1 -1
  57. data/ext/numo/linalg/lapack/potrs.h +1 -1
  58. data/ext/numo/linalg/lapack/syev.c +1 -1
  59. data/ext/numo/linalg/lapack/syev.h +1 -1
  60. data/ext/numo/linalg/lapack/syevd.c +1 -1
  61. data/ext/numo/linalg/lapack/syevd.h +1 -1
  62. data/ext/numo/linalg/lapack/syevr.c +1 -1
  63. data/ext/numo/linalg/lapack/syevr.h +1 -1
  64. data/ext/numo/linalg/lapack/sygv.c +1 -1
  65. data/ext/numo/linalg/lapack/sygv.h +1 -1
  66. data/ext/numo/linalg/lapack/sygvd.c +1 -1
  67. data/ext/numo/linalg/lapack/sygvd.h +1 -1
  68. data/ext/numo/linalg/lapack/sygvx.c +1 -1
  69. data/ext/numo/linalg/lapack/sygvx.h +1 -1
  70. data/ext/numo/linalg/lapack/sytrf.h +1 -1
  71. data/ext/numo/linalg/lapack/trtrs.h +1 -1
  72. data/ext/numo/linalg/lapack/unghr.h +1 -1
  73. data/ext/numo/linalg/lapack/ungqr.h +1 -1
  74. data/ext/numo/linalg/lapack/ungrq.h +1 -1
  75. data/ext/numo/linalg/linalg.c +2 -0
  76. data/ext/numo/linalg/linalg.h +14 -6
  77. data/lib/numo/linalg/version.rb +1 -1
  78. data/lib/numo/linalg.rb +148 -56
  79. metadata +10 -7
  80. data/ext/numo/linalg/util.c +0 -103
  81. data/ext/numo/linalg/util.h +0 -18
  82. /data/ext/numo/linalg/{converter.c → blas/converter.c} +0 -0
@@ -8,7 +8,7 @@
8
8
  #include <numo/narray.h>
9
9
  #include <numo/template.h>
10
10
 
11
- #include "../util.h"
11
+ #include "lapack_util.h"
12
12
 
13
13
  void define_linalg_lapack_sytrf(VALUE mLapack);
14
14
 
@@ -8,7 +8,7 @@
8
8
  #include <numo/narray.h>
9
9
  #include <numo/template.h>
10
10
 
11
- #include "../util.h"
11
+ #include "lapack_util.h"
12
12
 
13
13
  void define_linalg_lapack_trtrs(VALUE mLapack);
14
14
 
@@ -8,7 +8,7 @@
8
8
  #include <numo/narray.h>
9
9
  #include <numo/template.h>
10
10
 
11
- #include "../util.h"
11
+ #include "lapack_util.h"
12
12
 
13
13
  void define_linalg_lapack_unghr(VALUE mLapack);
14
14
 
@@ -8,7 +8,7 @@
8
8
  #include <numo/narray.h>
9
9
  #include <numo/template.h>
10
10
 
11
- #include "../util.h"
11
+ #include "lapack_util.h"
12
12
 
13
13
  void define_linalg_lapack_ungqr(VALUE mLapack);
14
14
 
@@ -8,7 +8,7 @@
8
8
  #include <numo/narray.h>
9
9
  #include <numo/template.h>
10
10
 
11
- #include "../util.h"
11
+ #include "lapack_util.h"
12
12
 
13
13
  void define_linalg_lapack_ungrq(VALUE mLapack);
14
14
 
@@ -224,8 +224,10 @@ void Init_linalg(void) {
224
224
  */
225
225
  rb_mLinalgLapack = rb_define_module_under(rb_mLinalg, "Lapack");
226
226
 
227
+ #ifdef HAVE_OPENBLAS_CONFIG_H
227
228
  /* The version of OpenBLAS used in background library. */
228
229
  rb_define_const(rb_mLinalg, "OPENBLAS_VERSION", rb_str_new_cstr(OPENBLAS_VERSION));
230
+ #endif
229
231
 
230
232
  /**
231
233
  * Returns BLAS char ([sdcz]) defined by data-type of arguments.
@@ -35,15 +35,23 @@
35
35
 
36
36
  #include <ruby.h>
37
37
 
38
- #include <cblas.h>
39
- #include <lapacke.h>
40
- #include <openblas_config.h>
41
-
42
38
  #include <numo/narray.h>
43
39
  #include <numo/template.h>
44
40
 
45
- #include "converter.h"
46
- #include "util.h"
41
+ #ifndef _DEFINED_SCOMPLEX
42
+ #define _DEFINED_SCOMPLEX 1
43
+ #endif
44
+ #ifndef _DEFINED_DCOMPLEX
45
+ #define _DEFINED_DCOMPLEX 1
46
+ #endif
47
+
48
+ #include <cblas.h>
49
+ #include <lapacke.h>
50
+
51
+ #include "extconf.h"
52
+ #ifdef HAVE_OPENBLAS_CONFIG_H
53
+ #include <openblas_config.h>
54
+ #endif
47
55
 
48
56
  #include "blas/dot.h"
49
57
  #include "blas/dot_sub.h"
@@ -5,6 +5,6 @@ module Numo
5
5
  # Numo::Linalg Alternative (numo-linalg-alt) is an alternative to Numo::Linalg.
6
6
  module Linalg
7
7
  # The version of numo-linalg-alt you install.
8
- VERSION = '0.5.0'
8
+ VERSION = '0.7.0'
9
9
  end
10
10
  end
data/lib/numo/linalg.rb CHANGED
@@ -8,6 +8,9 @@ require_relative 'linalg/linalg'
8
8
  module Numo
9
9
  # Numo::Linalg Alternative (numo-linalg-alt) is an alternative to Numo::Linalg.
10
10
  module Linalg # rubocop:disable Metrics/ModuleLength
11
+ # Exception class for errors occurred in LAPACK functions.
12
+ class LapackError < StandardError; end
13
+
11
14
  module_function
12
15
 
13
16
  # Computes the eigenvalues and eigenvectors of a symmetric / Hermitian matrix
@@ -340,7 +343,9 @@ module Numo
340
343
  raise ArgumentError, "invalid array type: #{a.class}" if bchr == 'n'
341
344
 
342
345
  fnc = :"#{bchr}potrs"
343
- x, _info = Numo::Linalg::Lapack.send(fnc, a, b.dup, uplo: uplo)
346
+ x, info = Numo::Linalg::Lapack.send(fnc, a, b.dup, uplo: uplo)
347
+ raise LapackError, "the #{-info}-th argument of potrs had illegal value" if info.negative?
348
+
344
349
  x
345
350
  end
346
351
 
@@ -364,17 +369,17 @@ module Numo
364
369
 
365
370
  getrf = :"#{bchr}getrf"
366
371
  lu, piv, info = Numo::Linalg::Lapack.send(getrf, a.dup)
372
+ raise LapackError, "the #{-info}-th argument of getrf had illegal value" if info.negative?
367
373
 
368
- if info.zero?
369
- det_l = 1
370
- det_u = lu.diagonal.prod
371
- det_p = piv.map_with_index { |v, i| v == i + 1 ? 1 : -1 }.prod
372
- det_l * det_u * det_p
373
- elsif info.positive?
374
- raise 'the factor U is singular, and the inverse matrix could not be computed.'
375
- else
376
- raise "the #{-info}-th argument of getrf had illegal value"
377
- end
374
+ # info > 0 means the factor U has a zero diagonal element and is singular.
375
+ # In this case, the determinant is zero. The method should simply return 0.0.
376
+ # Therefore, the error is not raised here.
377
+ # raise 'the factor U is singular, ...' if info.positive?
378
+
379
+ det_l = 1
380
+ det_u = lu.diagonal.prod
381
+ det_p = piv.map_with_index { |v, i| v == i + 1 ? 1 : -1 }.prod
382
+ det_l * det_u * det_p
378
383
  end
379
384
 
380
385
  # Computes the inverse matrix of a square matrix.
@@ -407,13 +412,13 @@ module Numo
407
412
  getri = :"#{bchr}getri"
408
413
 
409
414
  lu, piv, info = Numo::Linalg::Lapack.send(getrf, a.dup)
410
- if info.zero?
411
- Numo::Linalg::Lapack.send(getri, lu, piv)[0]
412
- elsif info.positive?
413
- raise 'the factor U is singular, and the inverse matrix could not be computed.'
414
- else
415
- raise "the #{-info}-th argument of getrf had illegal value"
416
- end
415
+ raise LapackError, "the #{-info}-th argument of getrf had illegal value" if info.negative?
416
+
417
+ a_inv, info = Numo::Linalg::Lapack.send(getri, lu, piv)
418
+ raise LapackError, "the #{-info}-th argument of getrf had illegal value" if info.negative?
419
+ raise LapackError, 'The matrix is singular, and the inverse matrix could not be computed.' if info.positive?
420
+
421
+ a_inv
417
422
  end
418
423
 
419
424
  # Computes the (Moore-Penrose) pseudo-inverse of a matrix using singular value decomposition.
@@ -441,7 +446,7 @@ module Numo
441
446
  rank = s.gt(rcond * s[0]).count
442
447
 
443
448
  u = u[true, 0...rank] / s[0...rank]
444
- u.dot(vh[0...rank, true]).conj.transpose
449
+ u.dot(vh[0...rank, true]).conj.transpose.dup
445
450
  end
446
451
 
447
452
  # Computes the polar decomposition of a matrix.
@@ -612,7 +617,7 @@ module Numo
612
617
 
613
618
  fnc = :"#{bchr}gerqf"
614
619
  rq, tau, info = Numo::Linalg::Lapack.send(fnc, a.dup)
615
- raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
620
+ raise LapackError, "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
616
621
 
617
622
  m, n = rq.shape
618
623
  r = rq.triu(n - m).dup
@@ -630,7 +635,7 @@ module Numo
630
635
  end
631
636
 
632
637
  q, info = Numo::Linalg::Lapack.send(fnc, tmp, tau)
633
- raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
638
+ raise LapackError, "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
634
639
 
635
640
  [r, q]
636
641
  end
@@ -675,8 +680,21 @@ module Numo
675
680
  aa, bb, _alpha, _beta, q, z, _sdim, info = Numo::Linalg::Lapack.send(fnc, a.dup, b.dup)
676
681
  end
677
682
 
678
- raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
679
- raise 'the QZ algorithm failed.' if info.positive?
683
+ n = a.shape[0]
684
+ raise LapackError, "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
685
+ raise LapackError, 'something other than QZ iteration failed.' if info == n + 1
686
+ raise LapackError, "reordering failed in #{bchr}tgsen" if info == n + 3
687
+
688
+ if info == n + 2
689
+ raise LapackError, 'after reordering, roundoff changed values of some eigenvalues ' \
690
+ 'so that leading eigenvalues in the Generalized Schur form no ' \
691
+ 'longer satisfy the sorting condition.'
692
+ end
693
+
694
+ if info.positive? && info <= n
695
+ warn('the QZ iteration failed. (a, b) are not in Schur form, ' \
696
+ "but alpha[i] and beta[i] for i = #{info},...,n are correct.")
697
+ end
680
698
 
681
699
  [aa, bb, q, z]
682
700
  end
@@ -732,10 +750,15 @@ module Numo
732
750
  end
733
751
 
734
752
  n = a.shape[0]
735
- raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
736
- raise 'the QR algorithm failed to compute all the eigenvalues.' if info.positive? && info <= n
737
- raise 'the eigenvalues could not be reordered.' if info == n + 1
738
- raise 'after reordering, roundoff changed values of some complex eigenvalues.' if info == n + 2
753
+ raise LapackError, "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
754
+ raise LapackError, 'the QR algorithm failed to compute all the eigenvalues.' if info.positive? && info <= n
755
+ raise LapackError, 'the eigenvalues could not be reordered.' if info == n + 1
756
+
757
+ if info == n + 2
758
+ raise LapackError, 'after reordering, roundoff changed values of some eigenvalues ' \
759
+ 'so that leading eigenvalues in the Schur form no longer satisfy ' \
760
+ 'the sorting condition.'
761
+ end
739
762
 
740
763
  [b, v, sdim]
741
764
  end
@@ -779,12 +802,12 @@ module Numo
779
802
  func = :"#{bchr}gebal"
780
803
  b, ilo, ihi, _, info = Numo::Linalg::Lapack.send(func, a.dup)
781
804
 
782
- raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
805
+ raise LapackError, "the #{-info}-th argument of #{func} had illegal value" if info.negative?
783
806
 
784
807
  func = :"#{bchr}gehrd"
785
808
  hq, tau, info = Numo::Linalg::Lapack.send(func, b, ilo: ilo, ihi: ihi)
786
809
 
787
- raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
810
+ raise LapackError, "the #{-info}-th argument of #{func} had illegal value" if info.negative?
788
811
 
789
812
  h = hq.triu(-1)
790
813
  return h unless calc_q
@@ -792,7 +815,7 @@ module Numo
792
815
  func = %w[d s].include?(bchr) ? :"#{bchr}orghr" : :"#{bchr}unghr"
793
816
  q, info = Numo::Linalg::Lapack.send(func, hq, tau, ilo: ilo, ihi: ihi)
794
817
 
795
- raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
818
+ raise LapackError, "the #{-info}-th argument of #{func} had illegal value" if info.negative?
796
819
 
797
820
  [h, q]
798
821
  end
@@ -830,7 +853,15 @@ module Numo
830
853
  raise ArgumentError, "invalid array type: #{a.class}, #{b.class}" if bchr == 'n'
831
854
 
832
855
  gesv = :"#{bchr}gesv"
833
- Numo::Linalg::Lapack.send(gesv, a.dup, b.dup)[1]
856
+ _lu, x, _ipiv, info = Numo::Linalg::Lapack.send(gesv, a.dup, b.dup)
857
+ raise LapackError, "the #{-info}-th argument of getrf had illegal value" if info.negative?
858
+
859
+ if info.positive?
860
+ warn('the factorization has been completed, but the factor is singular, ' \
861
+ 'so the solution could not be computed.')
862
+ end
863
+
864
+ x
834
865
  end
835
866
 
836
867
  # Solves linear equation `A * x = b` or `A * X = B` for `x` assuming `A` is a triangular matrix.
@@ -867,7 +898,7 @@ module Numo
867
898
  trtrs = :"#{bchr}trtrs"
868
899
  uplo = lower ? 'L' : 'U'
869
900
  x, info = Numo::Linalg::Lapack.send(trtrs, a, b.dup, uplo: uplo)
870
- raise "wrong value is given to the #{info}-th argument of #{trtrs} used internally" if info.negative?
901
+ raise LapackError, "wrong value is given to the #{info}-th argument of #{trtrs} used internally" if info.negative?
871
902
 
872
903
  x
873
904
  end
@@ -923,9 +954,9 @@ module Numo
923
954
  raise ArgumentError, "invalid driver: #{driver}"
924
955
  end
925
956
 
926
- raise "the #{info.abs}-th argument had illegal value" if info.negative?
927
- raise 'input array has a NAN entry' if info == -4
928
- raise 'svd did not converge' if info.positive?
957
+ raise LapackError, "the #{info.abs}-th argument had illegal value" if info.negative?
958
+ raise LapackError, 'the input array has a NAN entry' if info == -4
959
+ raise LapackError, 'the did not converge' if info.positive?
929
960
 
930
961
  [s, u, vt]
931
962
  end
@@ -1012,9 +1043,9 @@ module Numo
1012
1043
  raise ArgumentError, "invalid driver: #{driver}"
1013
1044
  end
1014
1045
 
1015
- raise "the #{info.abs}-th argument had illegal value" if info.negative?
1016
- raise 'input array has a NAN entry' if info == -4
1017
- raise 'svd did not converge' if info.positive?
1046
+ raise LapackError, "the #{info.abs}-th argument had illegal value" if info.negative?
1047
+ raise LapackError, 'the input array has a NAN entry' if info == -4
1048
+ raise LapackError, 'the decomposition did not converge' if info.positive?
1018
1049
 
1019
1050
  s
1020
1051
  end
@@ -1140,8 +1171,12 @@ module Numo
1140
1171
  getrf = :"#{bchr}getrf"
1141
1172
  lu, piv, info = Numo::Linalg::Lapack.send(getrf, a.dup)
1142
1173
 
1143
- raise "the #{info.abs}-th argument of getrf had illegal value" if info.negative?
1144
- raise "the U(#{info}, #{info}) is exactly zero. The factorization has been completed." if info.positive?
1174
+ raise LapackError, "the #{info.abs}-th argument of getrf had illegal value" if info.negative?
1175
+
1176
+ if info.positive?
1177
+ warn("the factorization has been completed, but the factor U[#{info - 1}, #{info - 1}] is " \
1178
+ 'exactly zero, indicating that the matrix is singular.')
1179
+ end
1145
1180
 
1146
1181
  [lu, piv]
1147
1182
  end
@@ -1179,7 +1214,7 @@ module Numo
1179
1214
  getrs = :"#{bchr}getrs"
1180
1215
  x, info = Numo::Linalg::Lapack.send(getrs, lu, ipiv, b.dup)
1181
1216
 
1182
- raise "the #{info.abs}-th argument of getrs had illegal value" if info.negative?
1217
+ raise LapackError, "the #{info.abs}-th argument of getrs had illegal value" if info.negative?
1183
1218
 
1184
1219
  x
1185
1220
  end
@@ -1200,8 +1235,12 @@ module Numo
1200
1235
  fnc = :"#{bchr}potrf"
1201
1236
  c, info = Numo::Linalg::Lapack.send(fnc, a.dup, uplo: uplo)
1202
1237
 
1203
- raise "the #{info}-th leading minor of the array is not positive definite, and the factorization could not be completed." if info.positive?
1204
- raise "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
1238
+ raise LapackError, "the #{-info}-th argument of #{fnc} had illegal value" if info.negative?
1239
+
1240
+ if info.positive?
1241
+ raise LapackError, "the leading principal minor of order #{info} is not positive, " \
1242
+ 'and the factorization could not be completed.'
1243
+ end
1205
1244
 
1206
1245
  c
1207
1246
  end
@@ -1297,7 +1336,7 @@ module Numo
1297
1336
  fnc = :"#{bchr}gebal"
1298
1337
  b, lo, hi, prm_scl, info = Numo::Linalg::Lapack.send(fnc, a.dup, job: job)
1299
1338
 
1300
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1339
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1301
1340
 
1302
1341
  # convert from Fortran style index to Ruby style index.
1303
1342
  lo -= 1
@@ -1374,8 +1413,8 @@ module Numo
1374
1413
  wr, wi, vl, vr, info = Numo::Linalg::Lapack.send(fnc, a.dup, jobvl: jobvl, jobvr: jobvr)
1375
1414
  end
1376
1415
 
1377
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1378
- raise 'the QR algorithm failed to compute all the eigenvalues.' if info.positive?
1416
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1417
+ raise LapackError, 'the QR algorithm failed to compute all the eigenvalues.' if info.positive?
1379
1418
 
1380
1419
  if %w[d s].include?(bchr)
1381
1420
  w = wr + (wi * 1.0i)
@@ -1419,8 +1458,8 @@ module Numo
1419
1458
  w = wr + (wi * 1.0i)
1420
1459
  end
1421
1460
 
1422
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1423
- raise 'the QR algorithm failed to compute all the eigenvalues.' if info.positive?
1461
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1462
+ raise LapackError, 'the QR algorithm failed to compute all the eigenvalues.' if info.positive?
1424
1463
 
1425
1464
  w
1426
1465
  end
@@ -1470,8 +1509,12 @@ module Numo
1470
1509
  lud = a.dup
1471
1510
  ipiv, info = Numo::Linalg::Lapack.send(fnc, lud, uplo: uplo)
1472
1511
 
1473
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1474
- raise 'the factorization has been completed' if info.positive?
1512
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1513
+
1514
+ if info.positive?
1515
+ warn("the factorization has been completed, but the D[#{info - 1}, #{info - 1}] is " \
1516
+ 'exactly zero, indicating that the block diagonal matrix is singular.')
1517
+ end
1475
1518
 
1476
1519
  _lud_permutation(lud, ipiv, uplo: uplo, hermitian: hermitian)
1477
1520
  end
@@ -1559,8 +1602,8 @@ module Numo
1559
1602
  fnc = :"#{bchr}gelsd"
1560
1603
  s, rank, info = Numo::Linalg::Lapack.send(fnc, a.dup, x, rcond: rcond)
1561
1604
 
1562
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1563
- raise 'the algorithm for computing the SVD failed to converge' if info.positive?
1605
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1606
+ raise LapackError, 'the algorithm for computing the SVD failed to converge' if info.positive?
1564
1607
 
1565
1608
  resids = x.class[]
1566
1609
  if m > n
@@ -1616,6 +1659,22 @@ module Numo
1616
1659
  a_expm
1617
1660
  end
1618
1661
 
1662
+ # Computes the matrix logarithm using its eigenvalue decomposition.
1663
+ #
1664
+ # @param a [Numo::NArray] The n-by-n square matrix.
1665
+ # @return [Numo::NArray] The matrix logarithm of `a`.
1666
+ def logm(a)
1667
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1668
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1669
+
1670
+ ev, vl, = eig(a, left: true, right: false)
1671
+ v = vl.transpose.conj
1672
+ inv_v = Numo::Linalg.inv(v)
1673
+ log_ev = Numo::NMath.log(ev)
1674
+
1675
+ inv_v.dot(log_ev.diag).dot(v)
1676
+ end
1677
+
1619
1678
  # Computes the matrix sine using the matrix exponential.
1620
1679
  #
1621
1680
  # @param a [Numo::NArray] The n-by-n square matrix.
@@ -1705,6 +1764,35 @@ module Numo
1705
1764
  a_sinh.dot(Numo::Linalg.inv(a_cosh))
1706
1765
  end
1707
1766
 
1767
+ # Computes the square root of a matrix using its eigenvalue decomposition.
1768
+ #
1769
+ # @param a [Numo::NArray] The n-by-n square matrix.
1770
+ # @return [Numo::NArray] The matrix square root of `a`.
1771
+ def sqrtm(a)
1772
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1773
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1774
+
1775
+ ev, vl, = eig(a, left: true, right: false)
1776
+ v = vl.transpose.conj
1777
+ inv_v = Numo::Linalg.inv(v)
1778
+ sqrt_ev = Numo::NMath.sqrt(ev)
1779
+
1780
+ inv_v.dot(sqrt_ev.diag).dot(v)
1781
+ end
1782
+
1783
+ # Computes the matrix sign function using its inverse and square root matrices.
1784
+ #
1785
+ # @param a [Numo::NArray] The n-by-n square matrix.
1786
+ # @return [Numo::NArray] The matrix sign function of `a`.
1787
+ def signm(a)
1788
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1789
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1790
+
1791
+ a_sqrt = sqrtm(a.dot(a))
1792
+ a_inv = Numo::Linalg.inv(a)
1793
+ a_inv.dot(a_sqrt)
1794
+ end
1795
+
1708
1796
  # Computes the inverse of a matrix using its LU decomposition.
1709
1797
  #
1710
1798
  # @param lu [Numo::NArray] The LU decomposition of the n-by-n matrix `A`.
@@ -1717,8 +1805,8 @@ module Numo
1717
1805
  fnc = :"#{bchr}getri"
1718
1806
  inv, info = Numo::Linalg::Lapack.send(fnc, lu.dup, ipiv)
1719
1807
 
1720
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1721
- raise 'the matrix is singular and its inverse could not be computed' if info.positive?
1808
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1809
+ raise LapackError, 'the matrix is singular and its inverse could not be computed' if info.positive?
1722
1810
 
1723
1811
  inv
1724
1812
  end
@@ -1748,8 +1836,12 @@ module Numo
1748
1836
  fnc = :"#{bchr}potri"
1749
1837
  inv, info = Numo::Linalg::Lapack.send(fnc, a.dup, uplo: uplo)
1750
1838
 
1751
- raise "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1752
- raise "the (#{info}, #info)-th element of the factor U or L is zero, and the inverse could not be computed." if info.positive?
1839
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1840
+
1841
+ if info.positive?
1842
+ raise LapackError, "the (#{info - 1}, #{info - 1})-th element of the factor U or L is zero, " \
1843
+ 'and the inverse could not be computed.'
1844
+ end
1753
1845
 
1754
1846
  inv
1755
1847
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numo-linalg-alt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
@@ -37,6 +37,11 @@ files:
37
37
  - CODE_OF_CONDUCT.md
38
38
  - LICENSE.txt
39
39
  - README.md
40
+ - ext/numo/linalg/blas/blas_common.h
41
+ - ext/numo/linalg/blas/blas_util.c
42
+ - ext/numo/linalg/blas/blas_util.h
43
+ - ext/numo/linalg/blas/converter.c
44
+ - ext/numo/linalg/blas/converter.h
40
45
  - ext/numo/linalg/blas/dot.c
41
46
  - ext/numo/linalg/blas/dot.h
42
47
  - ext/numo/linalg/blas/dot_sub.c
@@ -47,8 +52,6 @@ files:
47
52
  - ext/numo/linalg/blas/gemv.h
48
53
  - ext/numo/linalg/blas/nrm2.c
49
54
  - ext/numo/linalg/blas/nrm2.h
50
- - ext/numo/linalg/converter.c
51
- - ext/numo/linalg/converter.h
52
55
  - ext/numo/linalg/extconf.rb
53
56
  - ext/numo/linalg/lapack/gebal.c
54
57
  - ext/numo/linalg/lapack/gebal.h
@@ -94,6 +97,8 @@ files:
94
97
  - ext/numo/linalg/lapack/hetrf.h
95
98
  - ext/numo/linalg/lapack/lange.c
96
99
  - ext/numo/linalg/lapack/lange.h
100
+ - ext/numo/linalg/lapack/lapack_util.c
101
+ - ext/numo/linalg/lapack/lapack_util.h
97
102
  - ext/numo/linalg/lapack/orghr.c
98
103
  - ext/numo/linalg/lapack/orghr.h
99
104
  - ext/numo/linalg/lapack/orgqr.c
@@ -130,8 +135,6 @@ files:
130
135
  - ext/numo/linalg/lapack/ungrq.h
131
136
  - ext/numo/linalg/linalg.c
132
137
  - ext/numo/linalg/linalg.h
133
- - ext/numo/linalg/util.c
134
- - ext/numo/linalg/util.h
135
138
  - lib/numo/linalg.rb
136
139
  - lib/numo/linalg/version.rb
137
140
  - vendor/tmp/.gitkeep
@@ -142,7 +145,7 @@ metadata:
142
145
  homepage_uri: https://github.com/yoshoku/numo-linalg-alt
143
146
  source_code_uri: https://github.com/yoshoku/numo-linalg-alt
144
147
  changelog_uri: https://github.com/yoshoku/numo-linalg-alt/blob/main/CHANGELOG.md
145
- documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.5.0/
148
+ documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.7.0/
146
149
  rubygems_mfa_required: 'true'
147
150
  rdoc_options: []
148
151
  require_paths:
@@ -158,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
161
  - !ruby/object:Gem::Version
159
162
  version: '0'
160
163
  requirements: []
161
- rubygems_version: 3.6.9
164
+ rubygems_version: 3.7.2
162
165
  specification_version: 4
163
166
  summary: Numo::Linalg Alternative (numo-linalg-alt) is an alternative to Numo::Linalg.
164
167
  test_files: []
@@ -1,103 +0,0 @@
1
- #include "util.h"
2
-
3
- lapack_int get_itype(VALUE val) {
4
- const lapack_int itype = NUM2INT(val);
5
-
6
- if (itype != 1 && itype != 2 && itype != 3) {
7
- rb_raise(rb_eArgError, "itype must be 1, 2 or 3");
8
- }
9
-
10
- return itype;
11
- }
12
-
13
- char get_jobz(VALUE val) {
14
- const char jobz = NUM2CHR(val);
15
-
16
- if (jobz != 'N' && jobz != 'V') {
17
- rb_raise(rb_eArgError, "jobz must be 'N' or 'V'");
18
- }
19
-
20
- return jobz;
21
- }
22
-
23
- char get_jobvs(VALUE val) {
24
- const char jobvs = NUM2CHR(val);
25
- if (jobvs != 'N' && jobvs != 'V') {
26
- rb_raise(rb_eArgError, "jobvs must be 'N' or 'V'");
27
- }
28
- return jobvs;
29
- }
30
-
31
- char get_range(VALUE val) {
32
- const char range = NUM2CHR(val);
33
-
34
- if (range != 'A' && range != 'V' && range != 'I') {
35
- rb_raise(rb_eArgError, "range must be 'A', 'V' or 'I'");
36
- }
37
-
38
- return range;
39
- }
40
-
41
- char get_uplo(VALUE val) {
42
- const char uplo = NUM2CHR(val);
43
-
44
- if (uplo != 'U' && uplo != 'L') {
45
- rb_raise(rb_eArgError, "uplo must be 'U' or 'L'");
46
- }
47
-
48
- return uplo;
49
- }
50
-
51
- int get_matrix_layout(VALUE val) {
52
- const char option = NUM2CHR(val);
53
-
54
- switch (option) {
55
- case 'r':
56
- case 'R':
57
- break;
58
- case 'c':
59
- case 'C':
60
- rb_warn("Numo::Linalg does not support column major.");
61
- break;
62
- }
63
-
64
- return LAPACK_ROW_MAJOR;
65
- }
66
-
67
- enum CBLAS_TRANSPOSE get_cblas_trans(VALUE val) {
68
- const char option = NUM2CHR(val);
69
- enum CBLAS_TRANSPOSE res = CblasNoTrans;
70
-
71
- switch (option) {
72
- case 'n':
73
- case 'N':
74
- res = CblasNoTrans;
75
- break;
76
- case 't':
77
- case 'T':
78
- res = CblasTrans;
79
- break;
80
- case 'c':
81
- case 'C':
82
- res = CblasConjTrans;
83
- break;
84
- }
85
-
86
- return res;
87
- }
88
-
89
- enum CBLAS_ORDER get_cblas_order(VALUE val) {
90
- const char option = NUM2CHR(val);
91
-
92
- switch (option) {
93
- case 'r':
94
- case 'R':
95
- break;
96
- case 'c':
97
- case 'C':
98
- rb_warn("Numo::Linalg does not support column major.");
99
- break;
100
- }
101
-
102
- return CblasRowMajor;
103
- }
@@ -1,18 +0,0 @@
1
- #ifndef NUMO_LINALG_ALT_UTIL_H
2
- #define NUMO_LINALG_ALT_UTIL_H 1
3
-
4
- #include <ruby.h>
5
-
6
- #include <cblas.h>
7
- #include <lapacke.h>
8
-
9
- lapack_int get_itype(VALUE val);
10
- char get_jobz(VALUE val);
11
- char get_jobvs(VALUE val);
12
- char get_range(VALUE val);
13
- char get_uplo(VALUE val);
14
- int get_matrix_layout(VALUE val);
15
- enum CBLAS_TRANSPOSE get_cblas_trans(VALUE val);
16
- enum CBLAS_ORDER get_cblas_order(VALUE val);
17
-
18
- #endif // NUMO_LINALG_ALT_UTIL_H
File without changes