numo-linalg-alt 0.4.1 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc07e81b983e8ac3353509992185849f458f1559e6e484786c92f2a8d717de0e
4
- data.tar.gz: 660ae0a6cc21ca8beec6858a2f7c1efeee990261fdc649710f080becbb3ccc50
3
+ metadata.gz: 25f768b7f68b0526d390891b70e65e41ef16ef61a31614100c53250bb3d29baa
4
+ data.tar.gz: ebeb6d483949b617d5567f0265b2cd2cdee992fe8494006875595aa2dbb80adf
5
5
  SHA512:
6
- metadata.gz: 674d3e13ce4ac8b340eb66a77d83d33420af54c8f5e7836c31d398d5e3a86d5811e89baa737cb29d00f4a770f0616b4c3ff3393e17692a4dbf2ac3c9dfccdf54
7
- data.tar.gz: b6f0a374232dc259e0ea49e4e9d13c421aab685f38b0d01ef4d602f1e0f74a17835330e9864cfb335e9571fa246a80f015f29e904e2926646eb19680b176ba5d
6
+ metadata.gz: bba4f496a60bd9fe7aad51f07c6123855d8cbf4c1f1d2d4bb2858482c8ad3daeea5de8425176b242c5d84376874a0d0f93e80e46b0e39a2ff671721acb083fb3
7
+ data.tar.gz: 40d7100c495cad8021d5678ba1a0a3a3a9bdcfb53262e985234c653d207270c5d88f4a8d67ae8d00caab578f94142b1bdae198cf5ee3799cfc997f55486525cc
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## [[0.4.1](https://github.com/yoshoku/numo-linalg-alt/compare/v0.3.0...v0.4.0)] - 2025-10-19
1
+ ## [[0.5.0](https://github.com/yoshoku/numo-linalg-alt/compare/v0.4.1...v0.5.0)] - 2025-10-25
2
+
3
+ - FIX: correct Numo::Linalg::Lapack.xlange return type to Float for Numo::DComplex and Numo::SComplex.
4
+ - add `coshm`, `sinhm`, and `tanhm` module functions to Numo::Linalg.
5
+ - add `hessenberg` module function to Numo::Linalg.
6
+
7
+ ## [[0.4.1](https://github.com/yoshoku/numo-linalg-alt/compare/v0.4.0...v0.4.1)] - 2025-10-19
2
8
 
3
9
  - FIX: remove incorrect usage of RUBY_METHOD_FUNC macro: [#2](https://github.com/yoshoku/numo-linalg-alt/pull/2)
4
10
  - add `matrix_balance` moudle function to Numo::Linalg.
data/README.md CHANGED
@@ -63,6 +63,11 @@ Ubuntu:
63
63
  $ gem install numo-linalg-alt
64
64
  ```
65
65
 
66
+ ## Documentation
67
+
68
+ - [API Documentation](https://gemdocs.org/gems/numo-linalg-alt/0.4.1/)
69
+ - [Comparison with scipy.linalg and numpy.linalg](https://github.com/yoshoku/numo-linalg-alt/wiki/Comparison-with-scipy.linalg-and-numpy.linalg)
70
+
66
71
  ## Usage
67
72
 
68
73
  An example of singular value decomposition.
@@ -94,6 +99,37 @@ puts (x - z).abs.max
94
99
  # => 4.440892098500626e-16
95
100
  ```
96
101
 
102
+ ## Development
103
+
104
+ preparation:
105
+
106
+ ```shell
107
+ $ git clone https://github.com/yoshoku/numo-linalg-alt
108
+ $ cd numo-linalg-alt
109
+ $ bundle install
110
+ ```
111
+
112
+ build and test:
113
+
114
+ ```
115
+ $ bundle exec rake compile
116
+ $ bundle exec rake test
117
+ ```
118
+
119
+ linter:
120
+
121
+ ```shell
122
+ $ bundle exec rubocop
123
+ $ clang-format --dry-run --Werror --style=file ext/**/*.h ext/**/*.c
124
+ ```
125
+
126
+ This project follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
127
+ Please run `npm install` to set up husky and commitlint for commit message validation:
128
+
129
+ ```shell
130
+ $ npm install
131
+ ```
132
+
97
133
  ## Contributing
98
134
 
99
135
  Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/numo-linalg-alt.
@@ -96,4 +96,5 @@ $srcs = Dir.glob("#{$srcdir}/**/*.c").map { |path| File.basename(path) }
96
96
  $VPATH << '$(srcdir)/blas'
97
97
  $VPATH << '$(srcdir)/lapack'
98
98
 
99
+ create_header
99
100
  create_makefile('numo/linalg/linalg')
@@ -0,0 +1,77 @@
1
+ #include "gehrd.h"
2
+
3
+ struct _gehrd_option {
4
+ int matrix_layout;
5
+ int ilo;
6
+ int ihi;
7
+ };
8
+
9
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
10
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
11
+ tDType* a = (tDType*)NDL_PTR(lp, 0); \
12
+ tDType* tau = (tDType*)NDL_PTR(lp, 1); \
13
+ int* info = (int*)NDL_PTR(lp, 2); \
14
+ struct _gehrd_option* opt = (struct _gehrd_option*)(lp->opt_ptr); \
15
+ const lapack_int ilo = opt->ilo; \
16
+ const lapack_int ihi = opt->ihi; \
17
+ const lapack_int n = \
18
+ (lapack_int)(opt->matrix_layout == LAPACK_ROW_MAJOR ? NDL_SHAPE(lp, 0)[0] \
19
+ : NDL_SHAPE(lp, 0)[1]); \
20
+ const lapack_int lda = n; \
21
+ lapack_int i = LAPACKE_##fLapackFunc(opt->matrix_layout, n, ilo, ihi, a, lda, tau); \
22
+ *info = (int)i; \
23
+ } \
24
+ \
25
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
26
+ VALUE a_vnary = Qnil; \
27
+ VALUE kw_args = Qnil; \
28
+ rb_scan_args(argc, argv, "1:", &a_vnary, &kw_args); \
29
+ ID kw_table[3] = { rb_intern("ilo"), rb_intern("ihi"), rb_intern("order") }; \
30
+ VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
31
+ rb_get_kwargs(kw_args, kw_table, 2, 1, kw_values); \
32
+ const int ilo = NUM2INT(kw_values[0]); \
33
+ const int ihi = NUM2INT(kw_values[1]); \
34
+ const int matrix_layout = \
35
+ kw_values[2] != Qundef ? get_matrix_layout(kw_values[2]) : LAPACK_ROW_MAJOR; \
36
+ \
37
+ if (CLASS_OF(a_vnary) != tNAryClass) { \
38
+ a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
39
+ } \
40
+ if (!RTEST(nary_check_contiguous(a_vnary))) { \
41
+ a_vnary = nary_dup(a_vnary); \
42
+ } \
43
+ \
44
+ narray_t* a_nary = NULL; \
45
+ GetNArray(a_vnary, a_nary); \
46
+ const int n_dims = NA_NDIM(a_nary); \
47
+ if (n_dims != 2) { \
48
+ rb_raise(rb_eArgError, "input array a must be 2-dimensional"); \
49
+ return Qnil; \
50
+ } \
51
+ \
52
+ size_t n = matrix_layout == LAPACK_ROW_MAJOR ? NA_SHAPE(a_nary)[0] : NA_SHAPE(a_nary)[1]; \
53
+ size_t shape_tau[1] = { n - 1 }; \
54
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
55
+ ndfunc_arg_out_t aout[2] = { { tNAryClass, 1, shape_tau }, { numo_cInt32, 0 } }; \
56
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 2, ain, aout }; \
57
+ struct _gehrd_option opt = { matrix_layout, ilo, ihi }; \
58
+ VALUE res = na_ndloop3(&ndf, &opt, 1, a_vnary); \
59
+ VALUE ret = rb_ary_concat(rb_ary_new3(1, a_vnary), res); \
60
+ \
61
+ RB_GC_GUARD(a_vnary); \
62
+ return ret; \
63
+ }
64
+
65
+ DEF_LINALG_FUNC(double, numo_cDFloat, dgehrd)
66
+ DEF_LINALG_FUNC(float, numo_cSFloat, sgehrd)
67
+ DEF_LINALG_FUNC(lapack_complex_double, numo_cDComplex, zgehrd)
68
+ DEF_LINALG_FUNC(lapack_complex_float, numo_cSComplex, cgehrd)
69
+
70
+ #undef DEF_LINALG_FUNC
71
+
72
+ void define_linalg_lapack_gehrd(VALUE mLapack) {
73
+ rb_define_module_function(mLapack, "dgehrd", _linalg_lapack_dgehrd, -1);
74
+ rb_define_module_function(mLapack, "sgehrd", _linalg_lapack_sgehrd, -1);
75
+ rb_define_module_function(mLapack, "zgehrd", _linalg_lapack_zgehrd, -1);
76
+ rb_define_module_function(mLapack, "cgehrd", _linalg_lapack_cgehrd, -1);
77
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_GEHRD_H
2
+ #define NUMO_LINALG_ALT_LAPACK_GEHRD_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 "../util.h"
12
+
13
+ void define_linalg_lapack_gehrd(VALUE mLapack);
14
+
15
+ #endif // NUMO_LINALG_ALT_LAPACK_GEHRD_H
@@ -5,10 +5,10 @@ struct _lange_option {
5
5
  char norm;
6
6
  };
7
7
 
8
- #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
8
+ #define DEF_LINALG_FUNC(tDType, tRtDType, tNAryClass, tRtNAryClass, fLapackFunc) \
9
9
  static void _iter_##fLapackFunc(na_loop_t* const lp) { \
10
10
  tDType* a = (tDType*)NDL_PTR(lp, 0); \
11
- tDType* d = (tDType*)NDL_PTR(lp, 1); \
11
+ tRtDType* d = (tRtDType*)NDL_PTR(lp, 1); \
12
12
  struct _lange_option* opt = (struct _lange_option*)(lp->opt_ptr); \
13
13
  const lapack_int m = (lapack_int)NDL_SHAPE(lp, 0)[0]; \
14
14
  const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[1]; \
@@ -42,8 +42,7 @@ struct _lange_option {
42
42
  } \
43
43
  \
44
44
  ndfunc_arg_in_t ain[1] = { { tNAryClass, 2 } }; \
45
- size_t shape_out[1] = { 1 }; \
46
- ndfunc_arg_out_t aout[1] = { { tNAryClass, 0, shape_out } }; \
45
+ ndfunc_arg_out_t aout[1] = { { tRtNAryClass, 0 } }; \
47
46
  ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 1, ain, aout }; \
48
47
  struct _lange_option opt = { matrix_layout, norm }; \
49
48
  VALUE ret = na_ndloop3(&ndf, &opt, 1, a_vnary); \
@@ -52,10 +51,10 @@ struct _lange_option {
52
51
  return ret; \
53
52
  }
54
53
 
55
- DEF_LINALG_FUNC(double, numo_cDFloat, dlange)
56
- DEF_LINALG_FUNC(float, numo_cSFloat, slange)
57
- DEF_LINALG_FUNC(lapack_complex_double, numo_cDComplex, zlange)
58
- DEF_LINALG_FUNC(lapack_complex_float, numo_cSComplex, clange)
54
+ DEF_LINALG_FUNC(double, double, numo_cDFloat, numo_cDFloat, dlange)
55
+ DEF_LINALG_FUNC(float, float, numo_cSFloat, numo_cSFloat, slange)
56
+ DEF_LINALG_FUNC(lapack_complex_double, double, numo_cDComplex, numo_cDFloat, zlange)
57
+ DEF_LINALG_FUNC(lapack_complex_float, float, numo_cSComplex, numo_cSFloat, clange)
59
58
 
60
59
  #undef DEF_LINALG_FUNC
61
60
 
@@ -0,0 +1,82 @@
1
+ #include "orghr.h"
2
+
3
+ struct _orghr_option {
4
+ int matrix_layout;
5
+ int ilo;
6
+ int ihi;
7
+ };
8
+
9
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
10
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
11
+ tDType* a = (tDType*)NDL_PTR(lp, 0); \
12
+ tDType* tau = (tDType*)NDL_PTR(lp, 1); \
13
+ int* info = (int*)NDL_PTR(lp, 2); \
14
+ struct _orghr_option* opt = (struct _orghr_option*)(lp->opt_ptr); \
15
+ const lapack_int ilo = opt->ilo; \
16
+ const lapack_int ihi = opt->ihi; \
17
+ const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[0]; \
18
+ const lapack_int lda = n; \
19
+ const lapack_int i = LAPACKE_##fLapackFunc(opt->matrix_layout, n, ilo, ihi, a, lda, tau); \
20
+ *info = (int)i; \
21
+ } \
22
+ \
23
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
24
+ VALUE a_vnary = Qnil; \
25
+ VALUE tau_vnary = Qnil; \
26
+ VALUE kw_args = Qnil; \
27
+ rb_scan_args(argc, argv, "2:", &a_vnary, &tau_vnary, &kw_args); \
28
+ ID kw_table[3] = { rb_intern("ilo"), rb_intern("ihi"), rb_intern("order") }; \
29
+ VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
30
+ rb_get_kwargs(kw_args, kw_table, 2, 1, kw_values); \
31
+ const int ilo = NUM2INT(kw_values[0]); \
32
+ const int ihi = NUM2INT(kw_values[1]); \
33
+ const int matrix_layout = \
34
+ kw_values[2] != Qundef ? get_matrix_layout(kw_values[2]) : LAPACK_ROW_MAJOR; \
35
+ \
36
+ if (CLASS_OF(a_vnary) != tNAryClass) { \
37
+ a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
38
+ } \
39
+ if (!RTEST(nary_check_contiguous(a_vnary))) { \
40
+ a_vnary = nary_dup(a_vnary); \
41
+ } \
42
+ if (CLASS_OF(tau_vnary) != tNAryClass) { \
43
+ tau_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, tau_vnary); \
44
+ } \
45
+ if (!RTEST(nary_check_contiguous(tau_vnary))) { \
46
+ tau_vnary = nary_dup(tau_vnary); \
47
+ } \
48
+ \
49
+ narray_t* a_nary = NULL; \
50
+ GetNArray(a_vnary, a_nary); \
51
+ if (NA_NDIM(a_nary) != 2) { \
52
+ rb_raise(rb_eArgError, "input array a must be 2-dimensional"); \
53
+ return Qnil; \
54
+ } \
55
+ narray_t* tau_nary = NULL; \
56
+ GetNArray(tau_vnary, tau_nary); \
57
+ if (NA_NDIM(tau_nary) != 1) { \
58
+ rb_raise(rb_eArgError, "input array tau must be 1-dimensional"); \
59
+ return Qnil; \
60
+ } \
61
+ \
62
+ ndfunc_arg_in_t ain[2] = { { OVERWRITE, 2 }, { tNAryClass, 1 } }; \
63
+ ndfunc_arg_out_t aout[1] = { { numo_cInt32, 0 } }; \
64
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 2, 1, ain, aout }; \
65
+ struct _orghr_option opt = { matrix_layout, ilo, ihi }; \
66
+ VALUE res = na_ndloop3(&ndf, &opt, 2, a_vnary, tau_vnary); \
67
+ VALUE ret = rb_ary_new3(2, a_vnary, res); \
68
+ \
69
+ RB_GC_GUARD(a_vnary); \
70
+ RB_GC_GUARD(tau_vnary); \
71
+ return ret; \
72
+ }
73
+
74
+ DEF_LINALG_FUNC(double, numo_cDFloat, dorghr)
75
+ DEF_LINALG_FUNC(float, numo_cSFloat, sorghr)
76
+
77
+ #undef DEF_LINALG_FUNC
78
+
79
+ void define_linalg_lapack_orghr(VALUE mLapack) {
80
+ rb_define_module_function(mLapack, "dorghr", _linalg_lapack_dorghr, -1);
81
+ rb_define_module_function(mLapack, "sorghr", _linalg_lapack_sorghr, -1);
82
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_ORGHR_H
2
+ #define NUMO_LINALG_ALT_LAPACK_ORGHR_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 "../util.h"
12
+
13
+ void define_linalg_lapack_orghr(VALUE mLapack);
14
+
15
+ #endif /* NUMO_LINALG_ALT_LAPACK_ORGHR_H */
@@ -0,0 +1,82 @@
1
+ #include "unghr.h"
2
+
3
+ struct _unghr_option {
4
+ int matrix_layout;
5
+ int ilo;
6
+ int ihi;
7
+ };
8
+
9
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
10
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
11
+ tDType* a = (tDType*)NDL_PTR(lp, 0); \
12
+ tDType* tau = (tDType*)NDL_PTR(lp, 1); \
13
+ int* info = (int*)NDL_PTR(lp, 2); \
14
+ struct _unghr_option* opt = (struct _unghr_option*)(lp->opt_ptr); \
15
+ const lapack_int ilo = opt->ilo; \
16
+ const lapack_int ihi = opt->ihi; \
17
+ const lapack_int n = (lapack_int)NDL_SHAPE(lp, 0)[0]; \
18
+ const lapack_int lda = n; \
19
+ const lapack_int i = LAPACKE_##fLapackFunc(opt->matrix_layout, n, ilo, ihi, a, lda, tau); \
20
+ *info = (int)i; \
21
+ } \
22
+ \
23
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
24
+ VALUE a_vnary = Qnil; \
25
+ VALUE tau_vnary = Qnil; \
26
+ VALUE kw_args = Qnil; \
27
+ rb_scan_args(argc, argv, "2:", &a_vnary, &tau_vnary, &kw_args); \
28
+ ID kw_table[3] = { rb_intern("ilo"), rb_intern("ihi"), rb_intern("order") }; \
29
+ VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
30
+ rb_get_kwargs(kw_args, kw_table, 2, 1, kw_values); \
31
+ const int ilo = NUM2INT(kw_values[0]); \
32
+ const int ihi = NUM2INT(kw_values[1]); \
33
+ const int matrix_layout = \
34
+ kw_values[2] != Qundef ? get_matrix_layout(kw_values[2]) : LAPACK_ROW_MAJOR; \
35
+ \
36
+ if (CLASS_OF(a_vnary) != tNAryClass) { \
37
+ a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
38
+ } \
39
+ if (!RTEST(nary_check_contiguous(a_vnary))) { \
40
+ a_vnary = nary_dup(a_vnary); \
41
+ } \
42
+ if (CLASS_OF(tau_vnary) != tNAryClass) { \
43
+ tau_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, tau_vnary); \
44
+ } \
45
+ if (!RTEST(nary_check_contiguous(tau_vnary))) { \
46
+ tau_vnary = nary_dup(tau_vnary); \
47
+ } \
48
+ \
49
+ narray_t* a_nary = NULL; \
50
+ GetNArray(a_vnary, a_nary); \
51
+ if (NA_NDIM(a_nary) != 2) { \
52
+ rb_raise(rb_eArgError, "input array a must be 2-dimensional"); \
53
+ return Qnil; \
54
+ } \
55
+ narray_t* tau_nary = NULL; \
56
+ GetNArray(tau_vnary, tau_nary); \
57
+ if (NA_NDIM(tau_nary) != 1) { \
58
+ rb_raise(rb_eArgError, "input array tau must be 1-dimensional"); \
59
+ return Qnil; \
60
+ } \
61
+ \
62
+ ndfunc_arg_in_t ain[2] = { { OVERWRITE, 2 }, { tNAryClass, 1 } }; \
63
+ ndfunc_arg_out_t aout[1] = { { numo_cInt32, 0 } }; \
64
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 2, 1, ain, aout }; \
65
+ struct _unghr_option opt = { matrix_layout, ilo, ihi }; \
66
+ VALUE res = na_ndloop3(&ndf, &opt, 2, a_vnary, tau_vnary); \
67
+ VALUE ret = rb_ary_new3(2, a_vnary, res); \
68
+ \
69
+ RB_GC_GUARD(a_vnary); \
70
+ RB_GC_GUARD(tau_vnary); \
71
+ return ret; \
72
+ }
73
+
74
+ DEF_LINALG_FUNC(lapack_complex_double, numo_cDComplex, zunghr)
75
+ DEF_LINALG_FUNC(lapack_complex_float, numo_cSComplex, cunghr)
76
+
77
+ #undef DEF_LINALG_FUNC
78
+
79
+ void define_linalg_lapack_unghr(VALUE mLapack) {
80
+ rb_define_module_function(mLapack, "zunghr", _linalg_lapack_zunghr, -1);
81
+ rb_define_module_function(mLapack, "cunghr", _linalg_lapack_cunghr, -1);
82
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef NUMO_LINALG_ALT_LAPACK_UNGHR_H
2
+ #define NUMO_LINALG_ALT_LAPACK_UNGHR_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 "../util.h"
12
+
13
+ void define_linalg_lapack_unghr(VALUE mLapack);
14
+
15
+ #endif /* NUMO_LINALG_ALT_LAPACK_UNGHR_H */
@@ -296,6 +296,9 @@ void Init_linalg(void) {
296
296
  define_linalg_lapack_sytrf(rb_mLinalgLapack);
297
297
  define_linalg_lapack_hetrf(rb_mLinalgLapack);
298
298
  define_linalg_lapack_gebal(rb_mLinalgLapack);
299
+ define_linalg_lapack_gehrd(rb_mLinalgLapack);
300
+ define_linalg_lapack_orghr(rb_mLinalgLapack);
301
+ define_linalg_lapack_unghr(rb_mLinalgLapack);
299
302
 
300
303
  rb_define_alias(rb_singleton_class(rb_mLinalgBlas), "znrm2", "dznrm2");
301
304
  rb_define_alias(rb_singleton_class(rb_mLinalgBlas), "cnrm2", "scnrm2");
@@ -54,6 +54,7 @@
54
54
  #include "lapack/gebal.h"
55
55
  #include "lapack/gees.h"
56
56
  #include "lapack/geev.h"
57
+ #include "lapack/gehrd.h"
57
58
  #include "lapack/gelsd.h"
58
59
  #include "lapack/geqrf.h"
59
60
  #include "lapack/gerqf.h"
@@ -72,6 +73,7 @@
72
73
  #include "lapack/hegvx.h"
73
74
  #include "lapack/hetrf.h"
74
75
  #include "lapack/lange.h"
76
+ #include "lapack/orghr.h"
75
77
  #include "lapack/orgqr.h"
76
78
  #include "lapack/orgrq.h"
77
79
  #include "lapack/potrf.h"
@@ -85,6 +87,7 @@
85
87
  #include "lapack/sygvx.h"
86
88
  #include "lapack/sytrf.h"
87
89
  #include "lapack/trtrs.h"
90
+ #include "lapack/unghr.h"
88
91
  #include "lapack/ungqr.h"
89
92
  #include "lapack/ungrq.h"
90
93
 
@@ -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.4.1'
8
+ VERSION = '0.5.0'
9
9
  end
10
10
  end
data/lib/numo/linalg.rb CHANGED
@@ -740,6 +740,63 @@ module Numo
740
740
  [b, v, sdim]
741
741
  end
742
742
 
743
+ # Computes the Hessenberg decomposition of a square matrix.
744
+ # The Hessenberg decomposition is given by `A = Q * H * Q^H`,
745
+ # where `A` is the input matrix, `Q` is a unitary matrix,
746
+ # and `H` is an upper Hessenberg matrix.
747
+ #
748
+ # @example
749
+ # require 'numo/linalg'
750
+ #
751
+ # a = Numo::DFloat[[1, 2, 3], [4, 5, 6], [7, 8, 9]] * 0.5
752
+ # h, q = Numo::Linalg.hessenberg(a, calc_q: true)
753
+ #
754
+ # pp h
755
+ # # => Numo::DFloat#shape=[3,3]
756
+ # # [[0.5, -1.7985, -0.124035],
757
+ # # [-4.03113, 7.02308, 1.41538],
758
+ # # [0, 0.415385, -0.0230769]]
759
+ # pp q
760
+ # # => Numo::DFloat#shape=[3,3]
761
+ # # [[1, 0, 0],
762
+ # # [0, -0.496139, -0.868243],
763
+ # # [0, -0.868243, 0.496139]]
764
+ # pp (a - q.dot(h).dot(q.transpose)).abs.max
765
+ # # => 1.7763568394002505e-15
766
+ #
767
+ # @param a [Numo::NArray] The n-by-n square matrix.
768
+ # @param calc_q [Boolean] The flag indicating whether to calculate the unitary matrix `Q`.
769
+ # @return [Numo::NArray] if calc_q=false, the Hessenberg form `H`.
770
+ # @return [Array<Numo::NArray, Numo::NArray>] if calc_q=true,
771
+ # the Hessenberg form `H` and the unitary matrix `Q`.
772
+ def hessenberg(a, calc_q: false)
773
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
774
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
775
+
776
+ bchr = blas_char(a)
777
+ raise ArgumentError, "invalid array type: #{a.class}" if bchr == 'n'
778
+
779
+ func = :"#{bchr}gebal"
780
+ b, ilo, ihi, _, info = Numo::Linalg::Lapack.send(func, a.dup)
781
+
782
+ raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
783
+
784
+ func = :"#{bchr}gehrd"
785
+ hq, tau, info = Numo::Linalg::Lapack.send(func, b, ilo: ilo, ihi: ihi)
786
+
787
+ raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
788
+
789
+ h = hq.triu(-1)
790
+ return h unless calc_q
791
+
792
+ func = %w[d s].include?(bchr) ? :"#{bchr}orghr" : :"#{bchr}unghr"
793
+ q, info = Numo::Linalg::Lapack.send(func, hq, tau, ilo: ilo, ihi: ihi)
794
+
795
+ raise "the #{-info}-th argument of #{func} had illegal value" if info.negative?
796
+
797
+ [h, q]
798
+ end
799
+
743
800
  # Solves linear equation `A * x = b` or `A * X = B` for `x` from square matrix `A`.
744
801
  #
745
802
  # @example
@@ -1613,6 +1670,41 @@ module Numo
1613
1670
  a_sin.dot(Numo::Linalg.inv(a_cos))
1614
1671
  end
1615
1672
 
1673
+ # Computes the matrix hyperbolic sine using the matrix exponential.
1674
+ #
1675
+ # @param a [Numo::NArray] The n-by-n square matrix.
1676
+ # @return [Numo::NArray] The matrix hyperbolic sine of `a`.
1677
+ def sinhm(a)
1678
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1679
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1680
+
1681
+ 0.5 * (expm(a) - expm(-a))
1682
+ end
1683
+
1684
+ # Computes the matrix hyperbolic cosine using the matrix exponential.
1685
+ #
1686
+ # @param a [Numo::NArray] The n-by-n square matrix.
1687
+ # @return [Numo::NArray] The matrix hyperbolic cosine of `a`.
1688
+ def coshm(a)
1689
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1690
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1691
+
1692
+ 0.5 * (expm(a) + expm(-a))
1693
+ end
1694
+
1695
+ # Computes the matrix hyperbolic tangent.
1696
+ #
1697
+ # @param a [Numo::NArray] The n-by-n square matrix.
1698
+ # @return [Numo::NArray] The matrix hyperbolic tangent of `a`.
1699
+ def tanhm(a)
1700
+ raise Numo::NArray::ShapeError, 'input array a must be 2-dimensional' if a.ndim != 2
1701
+ raise Numo::NArray::ShapeError, 'input array a must be square' if a.shape[0] != a.shape[1]
1702
+
1703
+ a_sinh = sinhm(a)
1704
+ a_cosh = coshm(a)
1705
+ a_sinh.dot(Numo::Linalg.inv(a_cosh))
1706
+ end
1707
+
1616
1708
  # Computes the inverse of a matrix using its LU decomposition.
1617
1709
  #
1618
1710
  # @param lu [Numo::NArray] The LU decomposition of the n-by-n matrix `A`.
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.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
@@ -56,6 +56,8 @@ files:
56
56
  - ext/numo/linalg/lapack/gees.h
57
57
  - ext/numo/linalg/lapack/geev.c
58
58
  - ext/numo/linalg/lapack/geev.h
59
+ - ext/numo/linalg/lapack/gehrd.c
60
+ - ext/numo/linalg/lapack/gehrd.h
59
61
  - ext/numo/linalg/lapack/gelsd.c
60
62
  - ext/numo/linalg/lapack/gelsd.h
61
63
  - ext/numo/linalg/lapack/geqrf.c
@@ -92,6 +94,8 @@ files:
92
94
  - ext/numo/linalg/lapack/hetrf.h
93
95
  - ext/numo/linalg/lapack/lange.c
94
96
  - ext/numo/linalg/lapack/lange.h
97
+ - ext/numo/linalg/lapack/orghr.c
98
+ - ext/numo/linalg/lapack/orghr.h
95
99
  - ext/numo/linalg/lapack/orgqr.c
96
100
  - ext/numo/linalg/lapack/orgqr.h
97
101
  - ext/numo/linalg/lapack/orgrq.c
@@ -118,6 +122,8 @@ files:
118
122
  - ext/numo/linalg/lapack/sytrf.h
119
123
  - ext/numo/linalg/lapack/trtrs.c
120
124
  - ext/numo/linalg/lapack/trtrs.h
125
+ - ext/numo/linalg/lapack/unghr.c
126
+ - ext/numo/linalg/lapack/unghr.h
121
127
  - ext/numo/linalg/lapack/ungqr.c
122
128
  - ext/numo/linalg/lapack/ungqr.h
123
129
  - ext/numo/linalg/lapack/ungrq.c
@@ -136,7 +142,7 @@ metadata:
136
142
  homepage_uri: https://github.com/yoshoku/numo-linalg-alt
137
143
  source_code_uri: https://github.com/yoshoku/numo-linalg-alt
138
144
  changelog_uri: https://github.com/yoshoku/numo-linalg-alt/blob/main/CHANGELOG.md
139
- documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.4.1/
145
+ documentation_uri: https://gemdocs.org/gems/numo-linalg-alt/0.5.0/
140
146
  rubygems_mfa_required: 'true'
141
147
  rdoc_options: []
142
148
  require_paths: