numo-linalg-alt 0.8.0 → 0.9.1

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: 2a0ef106744c6982f932536daa0215fd6f8a92fff153fdc576f7de636045e820
4
- data.tar.gz: 04d3a8fe78f7f47e80d19ab3efca75c329fbe9a285d9b43e260965b96eec3cfa
3
+ metadata.gz: 2be058f70990035c731689a4784185d6eef5ce44f27269dac0069ab463837cf1
4
+ data.tar.gz: 395d611376e5b39da69ee641834d60386caa5903354afa5c2a6374ca7b4e12b2
5
5
  SHA512:
6
- metadata.gz: 782f5396ca2066b7b2b57f0ac6927675daec3e29b1544b24057b1218104363cb5f9265bee3f7d00b84ce8a1cbe42d1c8b78219341d6f9226101888361b462afd
7
- data.tar.gz: 91f8471e9816bec70d8f05ebce014259d07f2a82e9989d872fc60878692cdf7a961c33024d35ba4e87446748772220bd4ccf3533f5b92cd5aa45a1f42d699822
6
+ metadata.gz: 7d848848e62683dd518a043f941bb45c7f9d9b99d92943e08664c4fee6cff7fc8b3838a1aaeeed65bdd3cfb7218adfc085e3523f8e6d24f75d7f41e5cbebbc69
7
+ data.tar.gz: 3cb5325539e038a528e576532e2442fbc99da21031a20428051a4803e6f44d83f135d2c05e9abb2b844639a6378770f2ba80f5cf913f53014ba0834eaec70e15
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [[0.9.1](https://github.com/yoshoku/numo-linalg-alt/compare/v0.9.0...v0.9.1)] - 2026-04-26
2
+
3
+ - bump OpenBLAS from 0.3.30 to 0.3.33.
4
+ - add `ilaver` module function to Numo::Linalg::Lapack.
5
+
6
+ ## [[0.9.0](https://github.com/yoshoku/numo-linalg-alt/compare/v0.8.0...v0.9.0)] - 2026-02-14
7
+
8
+ - add `eigh_tridiagonal` and `eigvalsh_tridiagonal` module functions to Numo::Linalg.
9
+ - add `eig_banded` and `eigvals_banded` module functions to Numo::Linalg.
10
+ - fix CI workflow to correctly run ruby_memcheck.
11
+
1
12
  ## [[0.8.0](https://github.com/yoshoku/numo-linalg-alt/compare/v0.7.2...v0.8.0)] - 2026-02-06
2
13
 
3
14
  - relax numo-narray-alt version constraint to >= 0.9.10, < 0.11.0.
@@ -71,8 +71,8 @@ if build_openblas
71
71
 
72
72
  VENDOR_DIR = File.expand_path("#{__dir__}/../../../vendor")
73
73
  LINALG_DIR = File.expand_path("#{__dir__}/../../../lib/numo/linalg")
74
- OPENBLAS_VER = '0.3.31'
75
- OPENBLAS_KEY = '05050271d9196f65bc4ac3a89c6a3b05'
74
+ OPENBLAS_VER = '0.3.33'
75
+ OPENBLAS_KEY = '96c5cd9013013faefc294bc57830c77d'
76
76
  OPENBLAS_URI = "https://github.com/OpenMathLib/OpenBLAS/archive/v#{OPENBLAS_VER}.tar.gz"
77
77
  OPENBLAS_TGZ = "#{VENDOR_DIR}/tmp/openblas.tgz"
78
78
 
@@ -0,0 +1,112 @@
1
+ #include "hbevx.h"
2
+
3
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, tRtDType, tRtNAryClass, fLapackFunc) \
4
+ struct _hbevx_option_##tDType { \
5
+ int matrix_layout; \
6
+ char jobz; \
7
+ char range; \
8
+ char uplo; \
9
+ tRtDType vl; \
10
+ tRtDType vu; \
11
+ lapack_int il; \
12
+ lapack_int iu; \
13
+ }; \
14
+ \
15
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
16
+ tDType* ab = (tDType*)NDL_PTR(lp, 0); \
17
+ tDType* q = (tDType*)NDL_PTR(lp, 1); \
18
+ int* m = (int*)NDL_PTR(lp, 2); \
19
+ tRtDType* w = (tRtDType*)NDL_PTR(lp, 3); \
20
+ tDType* z = (tDType*)NDL_PTR(lp, 4); \
21
+ int* ifail = (int*)NDL_PTR(lp, 5); \
22
+ int* info = (int*)NDL_PTR(lp, 6); \
23
+ struct _hbevx_option_##tDType* opt = (struct _hbevx_option_##tDType*)(lp->opt_ptr); \
24
+ const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[1]; \
25
+ const lapack_int kd = (lapack_int)NDL_SHAPE(lp, 0)[0] - 1; \
26
+ const lapack_int ldab = n; \
27
+ const lapack_int ldq = n; \
28
+ const lapack_int ldz = opt->range != 'I' ? n : opt->iu - opt->il + 1; \
29
+ const tRtDType abstol = 0.0; \
30
+ const lapack_int i = LAPACKE_##fLapackFunc( \
31
+ opt->matrix_layout, opt->jobz, opt->range, opt->uplo, n, kd, ab, ldab, q, ldq, opt->vl, \
32
+ opt->vu, opt->il, opt->iu, abstol, m, w, z, ldz, ifail \
33
+ ); \
34
+ *info = (int)i; \
35
+ } \
36
+ \
37
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
38
+ VALUE ab_vnary = Qnil; \
39
+ VALUE kw_args = Qnil; \
40
+ rb_scan_args(argc, argv, "1:", &ab_vnary, &kw_args); \
41
+ ID kw_table[8] = { rb_intern("jobz"), rb_intern("range"), rb_intern("uplo"), \
42
+ rb_intern("vl"), rb_intern("vu"), rb_intern("il"), \
43
+ rb_intern("iu"), rb_intern("order") }; \
44
+ VALUE kw_values[8] = { Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef }; \
45
+ rb_get_kwargs(kw_args, kw_table, 0, 8, kw_values); \
46
+ const char jobz = kw_values[0] != Qundef ? get_job(kw_values[0], "jobz") : 'V'; \
47
+ const char range = kw_values[1] != Qundef ? get_range(kw_values[1]) : 'A'; \
48
+ const char uplo = kw_values[2] != Qundef ? get_uplo(kw_values[2]) : 'U'; \
49
+ const tRtDType vl = kw_values[3] != Qundef ? NUM2DBL(kw_values[3]) : 0.0; \
50
+ const tRtDType vu = kw_values[4] != Qundef ? NUM2DBL(kw_values[4]) : 0.0; \
51
+ const lapack_int il = kw_values[5] != Qundef ? NUM2INT(kw_values[5]) : 0; \
52
+ const lapack_int iu = kw_values[6] != Qundef ? NUM2INT(kw_values[6]) : 0; \
53
+ const int matrix_layout = \
54
+ kw_values[7] != Qundef ? get_matrix_layout(kw_values[7]) : LAPACK_ROW_MAJOR; \
55
+ \
56
+ if (CLASS_OF(ab_vnary) != tNAryClass) { \
57
+ ab_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, ab_vnary); \
58
+ } \
59
+ if (!RTEST(nary_check_contiguous(ab_vnary))) { \
60
+ ab_vnary = nary_dup(ab_vnary); \
61
+ } \
62
+ \
63
+ narray_t* ab_nary = NULL; \
64
+ GetNArray(ab_vnary, ab_nary); \
65
+ if (NA_NDIM(ab_nary) != 2) { \
66
+ rb_raise(rb_eArgError, "input array ab must be 2-dimensional"); \
67
+ return Qnil; \
68
+ } \
69
+ if (range == 'V' && vu <= vl) { \
70
+ rb_raise(rb_eArgError, "vu must be greater than vl"); \
71
+ return Qnil; \
72
+ } \
73
+ const size_t n = NA_SHAPE(ab_nary)[1]; \
74
+ if (range == 'I' && (il < 1 || il > (lapack_int)n)) { \
75
+ rb_raise(rb_eArgError, "il must satisfy 1 <= il <= n"); \
76
+ return Qnil; \
77
+ } \
78
+ if (range == 'I' && (iu < 1 || iu > (lapack_int)n)) { \
79
+ rb_raise(rb_eArgError, "iu must satisfy 1 <= iu <= n"); \
80
+ return Qnil; \
81
+ } \
82
+ if (range == 'I' && iu < il) { \
83
+ rb_raise(rb_eArgError, "iu must be greater than or equal to il"); \
84
+ return Qnil; \
85
+ } \
86
+ \
87
+ size_t m = range != 'I' ? n : (size_t)(iu - il + 1); \
88
+ size_t q_shape[2] = { n, n }; \
89
+ size_t w_shape[1] = { m }; \
90
+ size_t z_shape[2] = { n, m }; \
91
+ size_t ifail_shape[1] = { m }; \
92
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
93
+ ndfunc_arg_out_t aout[6] = { { tNAryClass, 2, q_shape }, { numo_cInt32, 0 }, \
94
+ { tRtNAryClass, 1, w_shape }, { tNAryClass, 2, z_shape }, \
95
+ { numo_cInt32, 1, ifail_shape }, { numo_cInt32, 0 } }; \
96
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 6, ain, aout }; \
97
+ struct _hbevx_option_##tDType opt = { matrix_layout, jobz, range, uplo, vl, vu, il, iu }; \
98
+ VALUE ret = na_ndloop3(&ndf, &opt, 1, ab_vnary); \
99
+ \
100
+ RB_GC_GUARD(ab_vnary); \
101
+ return ret; \
102
+ }
103
+
104
+ DEF_LINALG_FUNC(lapack_complex_double, numo_cDComplex, double, numo_cDFloat, zhbevx)
105
+ DEF_LINALG_FUNC(lapack_complex_float, numo_cSComplex, float, numo_cSFloat, chbevx)
106
+
107
+ #undef DEF_LINALG_FUNC
108
+
109
+ void define_linalg_lapack_hbevx(VALUE mLapack) {
110
+ rb_define_module_function(mLapack, "zhbevx", _linalg_lapack_zhbevx, -1);
111
+ rb_define_module_function(mLapack, "chbevx", _linalg_lapack_chbevx, -1);
112
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_HBEVX_H
2
+ #define NUMO_LINALG_ALT_LAPACK_HBEVX_H 1
3
+
4
+ #include <lapacke.h>
5
+
6
+ #include <ruby.h>
7
+
8
+ #include <numo/narray.h>
9
+ #include <numo/template.h>
10
+
11
+ #include "lapack_util.h"
12
+
13
+ void define_linalg_lapack_hbevx(VALUE mLapack);
14
+
15
+ #endif /* NUMO_LINALG_ALT_LAPACK_HBEVX_H */
@@ -0,0 +1,112 @@
1
+ #include "sbevx.h"
2
+
3
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
4
+ struct _sbevx_option_##tDType { \
5
+ int matrix_layout; \
6
+ char jobz; \
7
+ char range; \
8
+ char uplo; \
9
+ tDType vl; \
10
+ tDType vu; \
11
+ lapack_int il; \
12
+ lapack_int iu; \
13
+ }; \
14
+ \
15
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
16
+ tDType* ab = (tDType*)NDL_PTR(lp, 0); \
17
+ tDType* q = (tDType*)NDL_PTR(lp, 1); \
18
+ int* m = (int*)NDL_PTR(lp, 2); \
19
+ tDType* w = (tDType*)NDL_PTR(lp, 3); \
20
+ tDType* z = (tDType*)NDL_PTR(lp, 4); \
21
+ int* ifail = (int*)NDL_PTR(lp, 5); \
22
+ int* info = (int*)NDL_PTR(lp, 6); \
23
+ struct _sbevx_option_##tDType* opt = (struct _sbevx_option_##tDType*)(lp->opt_ptr); \
24
+ const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[1]; \
25
+ const lapack_int kd = (lapack_int)NDL_SHAPE(lp, 0)[0] - 1; \
26
+ const lapack_int ldab = n; \
27
+ const lapack_int ldq = n; \
28
+ const lapack_int ldz = opt->range != 'I' ? n : opt->iu - opt->il + 1; \
29
+ const tDType abstol = 0.0; \
30
+ const lapack_int i = LAPACKE_##fLapackFunc( \
31
+ opt->matrix_layout, opt->jobz, opt->range, opt->uplo, n, kd, ab, ldab, q, ldq, opt->vl, \
32
+ opt->vu, opt->il, opt->iu, abstol, m, w, z, ldz, ifail \
33
+ ); \
34
+ *info = (int)i; \
35
+ } \
36
+ \
37
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
38
+ VALUE ab_vnary = Qnil; \
39
+ VALUE kw_args = Qnil; \
40
+ rb_scan_args(argc, argv, "1:", &ab_vnary, &kw_args); \
41
+ ID kw_table[8] = { rb_intern("jobz"), rb_intern("range"), rb_intern("uplo"), \
42
+ rb_intern("vl"), rb_intern("vu"), rb_intern("il"), \
43
+ rb_intern("iu"), rb_intern("order") }; \
44
+ VALUE kw_values[8] = { Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef }; \
45
+ rb_get_kwargs(kw_args, kw_table, 0, 8, kw_values); \
46
+ const char jobz = kw_values[0] != Qundef ? get_job(kw_values[0], "jobz") : 'V'; \
47
+ const char range = kw_values[1] != Qundef ? get_range(kw_values[1]) : 'A'; \
48
+ const char uplo = kw_values[2] != Qundef ? get_uplo(kw_values[2]) : 'U'; \
49
+ const tDType vl = kw_values[3] != Qundef ? NUM2DBL(kw_values[3]) : 0.0; \
50
+ const tDType vu = kw_values[4] != Qundef ? NUM2DBL(kw_values[4]) : 0.0; \
51
+ const lapack_int il = kw_values[5] != Qundef ? NUM2INT(kw_values[5]) : 0; \
52
+ const lapack_int iu = kw_values[6] != Qundef ? NUM2INT(kw_values[6]) : 0; \
53
+ const int matrix_layout = \
54
+ kw_values[7] != Qundef ? get_matrix_layout(kw_values[7]) : LAPACK_ROW_MAJOR; \
55
+ \
56
+ if (CLASS_OF(ab_vnary) != tNAryClass) { \
57
+ ab_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, ab_vnary); \
58
+ } \
59
+ if (!RTEST(nary_check_contiguous(ab_vnary))) { \
60
+ ab_vnary = nary_dup(ab_vnary); \
61
+ } \
62
+ \
63
+ narray_t* ab_nary = NULL; \
64
+ GetNArray(ab_vnary, ab_nary); \
65
+ if (NA_NDIM(ab_nary) != 2) { \
66
+ rb_raise(rb_eArgError, "input array ab must be 2-dimensional"); \
67
+ return Qnil; \
68
+ } \
69
+ if (range == 'V' && vu <= vl) { \
70
+ rb_raise(rb_eArgError, "vu must be greater than vl"); \
71
+ return Qnil; \
72
+ } \
73
+ const size_t n = NA_SHAPE(ab_nary)[1]; \
74
+ if (range == 'I' && (il < 1 || il > (lapack_int)n)) { \
75
+ rb_raise(rb_eArgError, "il must satisfy 1 <= il <= n"); \
76
+ return Qnil; \
77
+ } \
78
+ if (range == 'I' && (iu < 1 || iu > (lapack_int)n)) { \
79
+ rb_raise(rb_eArgError, "iu must satisfy 1 <= iu <= n"); \
80
+ return Qnil; \
81
+ } \
82
+ if (range == 'I' && iu < il) { \
83
+ rb_raise(rb_eArgError, "iu must be greater than or equal to il"); \
84
+ return Qnil; \
85
+ } \
86
+ \
87
+ size_t m = range != 'I' ? n : (size_t)(iu - il + 1); \
88
+ size_t q_shape[2] = { n, n }; \
89
+ size_t w_shape[1] = { m }; \
90
+ size_t z_shape[2] = { n, m }; \
91
+ size_t ifail_shape[1] = { m }; \
92
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
93
+ ndfunc_arg_out_t aout[6] = { { tNAryClass, 2, q_shape }, { numo_cInt32, 0 }, \
94
+ { tNAryClass, 1, w_shape }, { tNAryClass, 2, z_shape }, \
95
+ { numo_cInt32, 1, ifail_shape }, { numo_cInt32, 0 } }; \
96
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 6, ain, aout }; \
97
+ struct _sbevx_option_##tDType opt = { matrix_layout, jobz, range, uplo, vl, vu, il, iu }; \
98
+ VALUE ret = na_ndloop3(&ndf, &opt, 1, ab_vnary); \
99
+ \
100
+ RB_GC_GUARD(ab_vnary); \
101
+ return ret; \
102
+ }
103
+
104
+ DEF_LINALG_FUNC(double, numo_cDFloat, dsbevx)
105
+ DEF_LINALG_FUNC(float, numo_cSFloat, ssbevx)
106
+
107
+ #undef DEF_LINALG_FUNC
108
+
109
+ void define_linalg_lapack_sbevx(VALUE mLapack) {
110
+ rb_define_module_function(mLapack, "dsbevx", _linalg_lapack_dsbevx, -1);
111
+ rb_define_module_function(mLapack, "ssbevx", _linalg_lapack_ssbevx, -1);
112
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_SBEVX_H
2
+ #define NUMO_LINALG_ALT_LAPACK_SBEVX_H 1
3
+
4
+ #include <lapacke.h>
5
+
6
+ #include <ruby.h>
7
+
8
+ #include <numo/narray.h>
9
+ #include <numo/template.h>
10
+
11
+ #include "lapack_util.h"
12
+
13
+ void define_linalg_lapack_sbevx(VALUE mLapack);
14
+
15
+ #endif /* NUMO_LINALG_ALT_LAPACK_SBEVX_H */
@@ -0,0 +1,122 @@
1
+ #include "stevx.h"
2
+
3
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
4
+ struct _stevx_option_##tDType { \
5
+ int matrix_layout; \
6
+ char jobz; \
7
+ char range; \
8
+ tDType vl; \
9
+ tDType vu; \
10
+ lapack_int il; \
11
+ lapack_int iu; \
12
+ }; \
13
+ \
14
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
15
+ tDType* d = (tDType*)NDL_PTR(lp, 0); \
16
+ tDType* e = (tDType*)NDL_PTR(lp, 1); \
17
+ int* m = (int*)NDL_PTR(lp, 2); \
18
+ tDType* w = (tDType*)NDL_PTR(lp, 3); \
19
+ tDType* z = (tDType*)NDL_PTR(lp, 4); \
20
+ int* ifail = (int*)NDL_PTR(lp, 5); \
21
+ int* info = (int*)NDL_PTR(lp, 6); \
22
+ struct _stevx_option_##tDType* opt = (struct _stevx_option_##tDType*)(lp->opt_ptr); \
23
+ const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[0]; \
24
+ const tDType abstol = 0.0; \
25
+ const lapack_int ldz = opt->range != 'I' ? n : opt->iu - opt->il + 1; \
26
+ const lapack_int i = LAPACKE_##fLapackFunc( \
27
+ opt->matrix_layout, opt->jobz, opt->range, n, d, e, opt->vl, opt->vu, opt->il, opt->iu, \
28
+ abstol, m, w, z, ldz, ifail \
29
+ ); \
30
+ *info = (int)i; \
31
+ } \
32
+ \
33
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
34
+ VALUE d_vnary = Qnil; \
35
+ VALUE e_vnary = Qnil; \
36
+ VALUE kw_args = Qnil; \
37
+ rb_scan_args(argc, argv, "2:", &d_vnary, &e_vnary, &kw_args); \
38
+ ID kw_table[7] = { rb_intern("jobz"), rb_intern("range"), rb_intern("vl"), \
39
+ rb_intern("vu"), rb_intern("il"), rb_intern("iu"), \
40
+ rb_intern("order") }; \
41
+ VALUE kw_values[7] = { Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef }; \
42
+ rb_get_kwargs(kw_args, kw_table, 0, 7, kw_values); \
43
+ const char jobz = kw_values[0] != Qundef ? get_job(kw_values[0], "jobz") : 'V'; \
44
+ const char range = kw_values[1] != Qundef ? get_range(kw_values[1]) : 'A'; \
45
+ const tDType vl = kw_values[2] != Qundef ? NUM2DBL(kw_values[2]) : 0.0; \
46
+ const tDType vu = kw_values[3] != Qundef ? NUM2DBL(kw_values[3]) : 0.0; \
47
+ const lapack_int il = kw_values[4] != Qundef ? NUM2INT(kw_values[4]) : 0; \
48
+ const lapack_int iu = kw_values[5] != Qundef ? NUM2INT(kw_values[5]) : 0; \
49
+ const int matrix_layout = \
50
+ kw_values[6] != Qundef ? get_matrix_layout(kw_values[6]) : LAPACK_ROW_MAJOR; \
51
+ \
52
+ if (CLASS_OF(d_vnary) != tNAryClass) { \
53
+ d_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, d_vnary); \
54
+ } \
55
+ if (!RTEST(nary_check_contiguous(d_vnary))) { \
56
+ d_vnary = nary_dup(d_vnary); \
57
+ } \
58
+ if (CLASS_OF(e_vnary) != tNAryClass) { \
59
+ e_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, e_vnary); \
60
+ } \
61
+ if (!RTEST(nary_check_contiguous(e_vnary))) { \
62
+ e_vnary = nary_dup(e_vnary); \
63
+ } \
64
+ \
65
+ narray_t* d_nary = NULL; \
66
+ GetNArray(d_vnary, d_nary); \
67
+ if (NA_NDIM(d_nary) != 1) { \
68
+ rb_raise(rb_eArgError, "input array d must be 1-dimensional"); \
69
+ return Qnil; \
70
+ } \
71
+ narray_t* e_nary = NULL; \
72
+ GetNArray(e_vnary, e_nary); \
73
+ if (NA_NDIM(e_nary) != 1) { \
74
+ rb_raise(rb_eArgError, "input array e must be 1-dimensional"); \
75
+ return Qnil; \
76
+ } \
77
+ if (range == 'V' && vu <= vl) { \
78
+ rb_raise(rb_eArgError, "vu must be greater than vl"); \
79
+ return Qnil; \
80
+ } \
81
+ const size_t n = NA_SHAPE(d_nary)[0]; \
82
+ if (range == 'I' && (il < 1 || il > (lapack_int)n)) { \
83
+ rb_raise(rb_eArgError, "il must satisfy 1 <= il <= n"); \
84
+ return Qnil; \
85
+ } \
86
+ if (range == 'I' && (iu < 1 || iu > (lapack_int)n)) { \
87
+ rb_raise(rb_eArgError, "iu must satisfy 1 <= iu <= n"); \
88
+ return Qnil; \
89
+ } \
90
+ if (range == 'I' && iu < il) { \
91
+ rb_raise(rb_eArgError, "iu must be greater than or equal to il"); \
92
+ return Qnil; \
93
+ } \
94
+ \
95
+ size_t m = range != 'I' ? n : (size_t)(iu - il + 1); \
96
+ size_t w_shape[1] = { m }; \
97
+ size_t z_shape[2] = { n, m }; \
98
+ size_t ifail_shape[1] = { m }; \
99
+ ndfunc_arg_in_t ain[2] = { { OVERWRITE, 1 }, { OVERWRITE, 1 } }; \
100
+ ndfunc_arg_out_t aout[5] = { { numo_cInt32, 0 }, \
101
+ { tNAryClass, 1, w_shape }, \
102
+ { tNAryClass, 2, z_shape }, \
103
+ { numo_cInt32, 1, ifail_shape }, \
104
+ { numo_cInt32, 0 } }; \
105
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 2, 5, ain, aout }; \
106
+ struct _stevx_option_##tDType opt = { matrix_layout, jobz, range, vl, vu, il, iu }; \
107
+ VALUE ret = na_ndloop3(&ndf, &opt, 2, d_vnary, e_vnary); \
108
+ \
109
+ RB_GC_GUARD(d_vnary); \
110
+ RB_GC_GUARD(e_vnary); \
111
+ return ret; \
112
+ }
113
+
114
+ DEF_LINALG_FUNC(double, numo_cDFloat, dstevx)
115
+ DEF_LINALG_FUNC(float, numo_cSFloat, sstevx)
116
+
117
+ #undef DEF_LINALG_FUNC
118
+
119
+ void define_linalg_lapack_stevx(VALUE mLapack) {
120
+ rb_define_module_function(mLapack, "dstevx", _linalg_lapack_dstevx, -1);
121
+ rb_define_module_function(mLapack, "sstevx", _linalg_lapack_sstevx, -1);
122
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_STEVX_H
2
+ #define NUMO_LINALG_ALT_LAPACK_STEVX_H 1
3
+
4
+ #include <lapacke.h>
5
+
6
+ #include <ruby.h>
7
+
8
+ #include <numo/narray.h>
9
+ #include <numo/template.h>
10
+
11
+ #include "lapack_util.h"
12
+
13
+ void define_linalg_lapack_stevx(VALUE mLapack);
14
+
15
+ #endif /* NUMO_LINALG_ALT_LAPACK_STEVX_H */
@@ -202,6 +202,16 @@ static VALUE linalg_dot(VALUE self, VALUE a_, VALUE b_) {
202
202
  return ret;
203
203
  }
204
204
 
205
+ static VALUE linalg_lapack_ilaver(VALUE self) {
206
+ lapack_int vers_major;
207
+ lapack_int vers_minor;
208
+ lapack_int vers_patch;
209
+ LAPACKE_ilaver(&vers_major, &vers_minor, &vers_patch);
210
+ VALUE version_arr =
211
+ rb_ary_new3(3, INT2NUM(vers_major), INT2NUM(vers_minor), INT2NUM(vers_patch));
212
+ return version_arr;
213
+ }
214
+
205
215
  void Init_linalg(void) {
206
216
  rb_require("numo/narray");
207
217
 
@@ -256,6 +266,13 @@ void Init_linalg(void) {
256
266
  * Numo::Linalg::Blas.call(:gemv, a, b)
257
267
  */
258
268
  rb_define_singleton_method(rb_mLinalgBlas, "call", linalg_blas_call, -1);
269
+ /**
270
+ * Returns the version of LAPACKE used in background library.
271
+ *
272
+ * @overload ilaver() -> Array<Integer>
273
+ * @return [Array<Integer>] [major, minor, patch]
274
+ */
275
+ rb_define_module_function(rb_mLinalgLapack, "ilaver", linalg_lapack_ilaver, 0);
259
276
 
260
277
  define_linalg_blas_dot(rb_mLinalgBlas);
261
278
  define_linalg_blas_dot_sub(rb_mLinalgBlas);
@@ -291,6 +308,9 @@ void Init_linalg(void) {
291
308
  define_linalg_lapack_heevd(rb_mLinalgLapack);
292
309
  define_linalg_lapack_syevr(rb_mLinalgLapack);
293
310
  define_linalg_lapack_heevr(rb_mLinalgLapack);
311
+ define_linalg_lapack_sbevx(rb_mLinalgLapack);
312
+ define_linalg_lapack_hbevx(rb_mLinalgLapack);
313
+ define_linalg_lapack_stevx(rb_mLinalgLapack);
294
314
  define_linalg_lapack_sygv(rb_mLinalgLapack);
295
315
  define_linalg_lapack_hegv(rb_mLinalgLapack);
296
316
  define_linalg_lapack_sygvd(rb_mLinalgLapack);
@@ -74,6 +74,7 @@
74
74
  #include "lapack/getri.h"
75
75
  #include "lapack/getrs.h"
76
76
  #include "lapack/gges.h"
77
+ #include "lapack/hbevx.h"
77
78
  #include "lapack/heev.h"
78
79
  #include "lapack/heevd.h"
79
80
  #include "lapack/heevr.h"
@@ -91,6 +92,8 @@
91
92
  #include "lapack/potrf.h"
92
93
  #include "lapack/potri.h"
93
94
  #include "lapack/potrs.h"
95
+ #include "lapack/sbevx.h"
96
+ #include "lapack/stevx.h"
94
97
  #include "lapack/syev.h"
95
98
  #include "lapack/syevd.h"
96
99
  #include "lapack/syevr.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.8.0'
8
+ VERSION = '0.9.1'
9
9
  end
10
10
  end
data/lib/numo/linalg.rb CHANGED
@@ -1699,6 +1699,163 @@ module Numo
1699
1699
  eigh(a, b, vals_only: true, vals_range: vals_range, uplo: uplo, turbo: turbo)[0]
1700
1700
  end
1701
1701
 
1702
+ # Computes the eigenvalues and eigenvectors of a symmetric / Hermitian banded matrix.
1703
+ #
1704
+ # @example
1705
+ # require 'numo/linalg'
1706
+ #
1707
+ # # Banded matrix A:
1708
+ # # [4 2 1 0 0]
1709
+ # # [2 5 2 1 0]
1710
+ # # [1 2 6 2 1]
1711
+ # # [0 1 2 7 2]
1712
+ # # [0 0 1 2 8]
1713
+ # #
1714
+ # ab = Numo::DFloat[[0, 0, 1, 1, 1],
1715
+ # [0, 2, 2, 2, 2],
1716
+ # [4, 5, 6, 7, 8]]
1717
+ #
1718
+ # w, v = Numo::Linalg.eig_banded(ab)
1719
+ #
1720
+ # b = v.dot(w.diag).dot(v.transpose)
1721
+ # b[b<1e-10] = 0.0
1722
+ # pp b
1723
+ # # =>
1724
+ # # Numo::DFloat#shape=[5,5]
1725
+ # # [[4, 2, 1, 0, 0],
1726
+ # # [2, 5, 2, 1, 0],
1727
+ # # [1, 2, 6, 2, 1],
1728
+ # # [0, 1, 2, 7, 2],
1729
+ # # [0, 0, 1, 2, 8]]
1730
+ #
1731
+ # @param ab [Numo::NArray] The (kd+1)-by-n array representing the banded matrix.
1732
+ # @param vals_only [Boolean] The flag indicating whether to compute only eigenvalues.
1733
+ # @param vals_range [Range/Array]
1734
+ # The range of indices of the eigenvalues (in ascending order) and corresponding eigenvectors to be returned.
1735
+ # If nil, all eigenvalues and eigenvectors are computed.
1736
+ # @param lower [Boolean] The flag indicating whether to be in the lower-banded form.
1737
+ # @return [Array<Numo::NArray>] The eigenvalues and eigenvectors.
1738
+ def eig_banded(ab, vals_only: false, vals_range: nil, lower: false)
1739
+ raise Numo::NArray::ShapeError, 'input array ab must be 2-dimensional' if ab.ndim != 2
1740
+
1741
+ bchr = blas_char(ab)
1742
+ raise ArgumentError, "invalid array type: #{ab.class}" if bchr == 'n'
1743
+
1744
+ jobz = vals_only ? 'N' : 'V'
1745
+ uplo = lower ? 'L' : 'U'
1746
+ fnc = %w[d s].include?(bchr) ? "#{bchr}sbevx" : "#{bchr}hbevx"
1747
+
1748
+ if vals_range.nil?
1749
+ _, _, vals, vecs, _, info = Numo::Linalg::Lapack.send(fnc.to_sym, ab.dup, range: 'A', jobz: jobz, uplo: uplo)
1750
+ else
1751
+ il = vals_range.first(1)[0] + 1
1752
+ iu = vals_range.last(1)[0] + 1
1753
+ _, _, vals, vecs, _, info = Numo::Linalg::Lapack.send(fnc.to_sym, ab.dup,
1754
+ range: 'I', jobz: jobz, uplo: uplo, il: il, iu: iu)
1755
+ end
1756
+
1757
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1758
+
1759
+ vecs = nil if vals_only
1760
+
1761
+ [vals, vecs]
1762
+ end
1763
+
1764
+ # Computes the eigenvalues a symmetric / Hermitian banded matrix.
1765
+ #
1766
+ # @param ab [Numo::NArray] The (kd+1)-by-n array representing the banded matrix.
1767
+ # @param vals_range [Range/Array]
1768
+ # The range of indices of the eigenvalues (in ascending order) to be returned.
1769
+ # If nil, all eigenvalues are computed.
1770
+ # @param lower [Boolean] The flag indicating whether to be in the lower-banded form.
1771
+ # @return [Numo::NArray] The eigenvalues.
1772
+ def eigvals_banded(ab, vals_range: nil, lower: false)
1773
+ eig_banded(ab, vals_only: true, vals_range: vals_range, lower: lower)[0]
1774
+ end
1775
+
1776
+ # Computes the eigenvalues and eigenvectors of a real symmetric tridiagonal matrix.
1777
+ #
1778
+ # @example
1779
+ # require 'numo/linalg'
1780
+ #
1781
+ # # symmetric tridiagonal matrix A:
1782
+ # # [4 2 0 0 0]
1783
+ # # [2 5 2 0 0]
1784
+ # # [0 2 6 2 0]
1785
+ # # [0 0 2 7 2]
1786
+ # # [0 0 0 2 8]
1787
+ # d = Numo::DFloat[4, 5, 6, 7, 8]
1788
+ # e = Numo::DFloat[2, 2, 2, 2]
1789
+ #
1790
+ # w, v = Numo::Linalg.eigh_tridiagonal(d, e)
1791
+ #
1792
+ # b = v.dot(w.diag).dot(v.transpose)
1793
+ # b[b<1e-10] = 0.0
1794
+ # pp b
1795
+ # # =>
1796
+ # # Numo::DFloat#shape=[5,5]
1797
+ # # [[4, 2, 0, 0, 0],
1798
+ # # [2, 5, 2, 0, 0],
1799
+ # # [0, 2, 6, 2, 0],
1800
+ # # [0, 0, 2, 7, 2],
1801
+ # # [0, 0, 0, 2, 8]]
1802
+ #
1803
+ # @param d [Numo::NArray] The 1-dimensional array of length n representing the diagonal elements of the matrix.
1804
+ # @param e [Numo::NArray] The 1-dimensional array of length n-1 representing the off-diagonal elements of the matrix.
1805
+ # @param vals_only [Boolean] The flag indicating whether to compute only eigenvalues.
1806
+ # @param vals_range [Range/Array]
1807
+ # The range of indices of the eigenvalues (in ascending order) and corresponding eigenvectors to be returned.
1808
+ # If nil, all eigenvalues and eigenvectors are computed.
1809
+ # @return [Array<Numo::NArray>] The eigenvalues and eigenvectors.
1810
+ def eigh_tridiagonal(d, e, vals_only: false, vals_range: nil) # rubocop:disable Metrics/AbcSize
1811
+ raise Numo::NArray::ShapeError, 'input array d must be 1-dimensional' if d.ndim != 1
1812
+ raise Numo::NArray::ShapeError, 'input array e must be 1-dimensional' if e.ndim != 1
1813
+
1814
+ if d.shape[0] != e.shape[0] + 1
1815
+ raise Numo::NArray::ShapeError,
1816
+ "incompatible dimensions: d.shape[0] (#{d.shape[0]}) != e.shape[0] + 1 (#{e.shape[0] + 1})"
1817
+ end
1818
+
1819
+ if d.is_a?(Numo::DComplex) || d.is_a?(Numo::SComplex) || e.is_a?(Numo::DComplex) || e.is_a?(Numo::SComplex)
1820
+ raise ArgumentError, 'eigh_tridiagonal does not support complex arrays'
1821
+ end
1822
+
1823
+ bchr = blas_char(d)
1824
+ raise ArgumentError, "invalid array type: #{d.class}" if bchr == 'n'
1825
+
1826
+ jobz = vals_only ? 'N' : 'V'
1827
+ fnc = "#{bchr}stevx"
1828
+
1829
+ e_w_zero = e.concatenate(0)
1830
+
1831
+ if vals_range.nil?
1832
+ _, vals, vecs, _, info = Numo::Linalg::Lapack.send(fnc.to_sym, d.dup, e_w_zero, range: 'A', jobz: jobz)
1833
+ else
1834
+ il = vals_range.first(1)[0] + 1
1835
+ iu = vals_range.last(1)[0] + 1
1836
+ _, vals, vecs, _, info = Numo::Linalg::Lapack.send(fnc.to_sym, d.dup, e_w_zero,
1837
+ range: 'I', jobz: jobz, il: il, iu: iu)
1838
+ end
1839
+
1840
+ raise LapackError, "the #{info.abs}-th argument of #{fnc} had illegal value" if info.negative?
1841
+
1842
+ vecs = nil if vals_only
1843
+
1844
+ [vals, vecs]
1845
+ end
1846
+
1847
+ # Computes the eigenvalues of a real symmetric tridiagonal matrix.
1848
+ #
1849
+ # @param d [Numo::NArray] The 1-dimensional array of length n representing the diagonal elements of the matrix.
1850
+ # @param e [Numo::NArray] The 1-dimensional array of length n-1 representing the off-diagonal elements of the matrix.
1851
+ # @param vals_range [Range/Array]
1852
+ # The range of indices of the eigenvalues (in ascending order) and corresponding eigenvectors to be returned.
1853
+ # If nil, all eigenvalues and eigenvectors are computed.
1854
+ # @return [Numo::NArray] The eigenvalues.
1855
+ def eigvalsh_tridiagonal(d, e, vals_range: nil)
1856
+ eigh_tridiagonal(d, e, vals_only: true, vals_range: vals_range)[0]
1857
+ end
1858
+
1702
1859
  # Computes the Bunch-Kaufman decomposition of a symmetric / Hermitian matrix.
1703
1860
  # The factorization has the form `A = U * D * U^T` or `A = L * D * L^T`,
1704
1861
  # where `U` (or `L`) is a product of permutation and unit upper
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.8.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
@@ -89,6 +89,8 @@ files:
89
89
  - ext/numo/linalg/lapack/getrs.h
90
90
  - ext/numo/linalg/lapack/gges.c
91
91
  - ext/numo/linalg/lapack/gges.h
92
+ - ext/numo/linalg/lapack/hbevx.c
93
+ - ext/numo/linalg/lapack/hbevx.h
92
94
  - ext/numo/linalg/lapack/heev.c
93
95
  - ext/numo/linalg/lapack/heev.h
94
96
  - ext/numo/linalg/lapack/heevd.c
@@ -125,6 +127,10 @@ files:
125
127
  - ext/numo/linalg/lapack/potri.h
126
128
  - ext/numo/linalg/lapack/potrs.c
127
129
  - ext/numo/linalg/lapack/potrs.h
130
+ - ext/numo/linalg/lapack/sbevx.c
131
+ - ext/numo/linalg/lapack/sbevx.h
132
+ - ext/numo/linalg/lapack/stevx.c
133
+ - ext/numo/linalg/lapack/stevx.h
128
134
  - ext/numo/linalg/lapack/syev.c
129
135
  - ext/numo/linalg/lapack/syev.h
130
136
  - ext/numo/linalg/lapack/syevd.c
@@ -159,7 +165,7 @@ metadata:
159
165
  homepage_uri: https://github.com/yoshoku/numo-linalg-alt
160
166
  source_code_uri: https://github.com/yoshoku/numo-linalg-alt
161
167
  changelog_uri: https://github.com/yoshoku/numo-linalg-alt/blob/main/CHANGELOG.md
162
- documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.8.0/
168
+ documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.9.1/
163
169
  rubygems_mfa_required: 'true'
164
170
  rdoc_options: []
165
171
  require_paths:
@@ -175,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
181
  - !ruby/object:Gem::Version
176
182
  version: '0'
177
183
  requirements: []
178
- rubygems_version: 4.0.3
184
+ rubygems_version: 4.0.6
179
185
  specification_version: 4
180
186
  summary: Numo::Linalg Alternative (numo-linalg-alt) is an alternative to Numo::Linalg.
181
187
  test_files: []