numo-linalg-alt 0.3.0 → 0.4.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/numo/linalg/blas/dot.c +59 -59
  4. data/ext/numo/linalg/blas/dot_sub.c +58 -58
  5. data/ext/numo/linalg/blas/gemm.c +157 -148
  6. data/ext/numo/linalg/blas/gemv.c +131 -127
  7. data/ext/numo/linalg/blas/nrm2.c +50 -50
  8. data/ext/numo/linalg/lapack/gees.c +239 -220
  9. data/ext/numo/linalg/lapack/geev.c +127 -110
  10. data/ext/numo/linalg/lapack/gelsd.c +81 -70
  11. data/ext/numo/linalg/lapack/geqrf.c +52 -51
  12. data/ext/numo/linalg/lapack/gerqf.c +70 -0
  13. data/ext/numo/linalg/lapack/gerqf.h +15 -0
  14. data/ext/numo/linalg/lapack/gesdd.c +96 -86
  15. data/ext/numo/linalg/lapack/gesv.c +80 -78
  16. data/ext/numo/linalg/lapack/gesvd.c +140 -129
  17. data/ext/numo/linalg/lapack/getrf.c +51 -50
  18. data/ext/numo/linalg/lapack/getri.c +64 -63
  19. data/ext/numo/linalg/lapack/getrs.c +92 -88
  20. data/ext/numo/linalg/lapack/gges.c +214 -0
  21. data/ext/numo/linalg/lapack/gges.h +15 -0
  22. data/ext/numo/linalg/lapack/heev.c +54 -52
  23. data/ext/numo/linalg/lapack/heevd.c +54 -52
  24. data/ext/numo/linalg/lapack/heevr.c +109 -98
  25. data/ext/numo/linalg/lapack/hegv.c +77 -74
  26. data/ext/numo/linalg/lapack/hegvd.c +77 -74
  27. data/ext/numo/linalg/lapack/hegvx.c +132 -120
  28. data/ext/numo/linalg/lapack/hetrf.c +54 -50
  29. data/ext/numo/linalg/lapack/lange.c +45 -44
  30. data/ext/numo/linalg/lapack/orgqr.c +63 -62
  31. data/ext/numo/linalg/lapack/orgrq.c +78 -0
  32. data/ext/numo/linalg/lapack/orgrq.h +15 -0
  33. data/ext/numo/linalg/lapack/potrf.c +49 -48
  34. data/ext/numo/linalg/lapack/potri.c +49 -48
  35. data/ext/numo/linalg/lapack/potrs.c +74 -72
  36. data/ext/numo/linalg/lapack/syev.c +54 -52
  37. data/ext/numo/linalg/lapack/syevd.c +54 -52
  38. data/ext/numo/linalg/lapack/syevr.c +107 -98
  39. data/ext/numo/linalg/lapack/sygv.c +77 -73
  40. data/ext/numo/linalg/lapack/sygvd.c +77 -73
  41. data/ext/numo/linalg/lapack/sygvx.c +132 -120
  42. data/ext/numo/linalg/lapack/sytrf.c +54 -50
  43. data/ext/numo/linalg/lapack/trtrs.c +79 -75
  44. data/ext/numo/linalg/lapack/ungqr.c +63 -62
  45. data/ext/numo/linalg/lapack/ungrq.c +78 -0
  46. data/ext/numo/linalg/lapack/ungrq.h +15 -0
  47. data/ext/numo/linalg/linalg.c +20 -10
  48. data/ext/numo/linalg/linalg.h +4 -0
  49. data/ext/numo/linalg/util.c +8 -0
  50. data/ext/numo/linalg/util.h +1 -0
  51. data/lib/numo/linalg/version.rb +1 -1
  52. data/lib/numo/linalg.rb +139 -3
  53. metadata +10 -2
@@ -1,231 +1,246 @@
1
1
  #include "gees.h"
2
2
 
3
- char _get_jobvs(VALUE val) {
4
- const char jobvs = NUM2CHR(val);
5
- if (jobvs != 'N' && jobvs != 'V') {
6
- rb_raise(rb_eArgError, "jobvs must be 'N' or 'V'");
7
- }
8
- return jobvs;
9
- }
10
-
11
- #define DEF_GEES_OPTION(fLapackFunc, tSelectFunc) \
12
- struct _gees_option_##fLapackFunc { \
13
- int matrix_layout; \
14
- char jobvs; \
15
- char sort; \
16
- tSelectFunc select; \
3
+ #define DEF_GEES_OPTION(fLapackFunc, tSelectFunc) \
4
+ struct _gees_option_##fLapackFunc { \
5
+ int matrix_layout; \
6
+ char jobvs; \
7
+ char sort; \
8
+ tSelectFunc select; \
17
9
  };
18
10
 
19
- #define DEF_GEES_SORT_FUNC(tDType, fLapackFunc) \
20
- lapack_logical _sort_nil_##fLapackFunc(const tDType* wr, const tDType* wi) { \
21
- return 0; \
22
- } \
23
- lapack_logical _sort_lhp_##fLapackFunc(const tDType* wr, const tDType* wi) { \
24
- if (*wr < (tDType)0) { \
25
- return 1; \
26
- } \
27
- return 0; \
28
- } \
29
- lapack_logical _sort_rhp_##fLapackFunc(const tDType* wr, const tDType* wi) { \
30
- if (*wr >= (tDType)0) { \
31
- return 1; \
32
- } \
33
- return 0; \
34
- } \
35
- lapack_logical _sort_iup_##fLapackFunc(const tDType* wr, const tDType* wi) { \
36
- tDType magnitude = *wr * *wr + *wi * *wi; \
37
- if (magnitude <= (tDType)1) { \
38
- return 1; \
39
- } \
40
- return 0; \
41
- } \
42
- lapack_logical _sort_ouc_##fLapackFunc(const tDType* wr, const tDType* wi) { \
43
- tDType magnitude = *wr * *wr + *wi * *wi; \
44
- if (magnitude > (tDType)1) { \
45
- return 1; \
46
- } \
47
- return 0; \
11
+ #define DEF_GEES_SORT_FUNC(tDType, fLapackFunc) \
12
+ lapack_logical _sort_nil_##fLapackFunc(const tDType* wr, const tDType* wi) { \
13
+ return 0; \
14
+ } \
15
+ lapack_logical _sort_lhp_##fLapackFunc(const tDType* wr, const tDType* wi) { \
16
+ if (*wr < (tDType)0) { \
17
+ return 1; \
18
+ } \
19
+ return 0; \
20
+ } \
21
+ lapack_logical _sort_rhp_##fLapackFunc(const tDType* wr, const tDType* wi) { \
22
+ if (*wr >= (tDType)0) { \
23
+ return 1; \
24
+ } \
25
+ return 0; \
26
+ } \
27
+ lapack_logical _sort_iup_##fLapackFunc(const tDType* wr, const tDType* wi) { \
28
+ tDType magnitude = *wr * *wr + *wi * *wi; \
29
+ if (magnitude <= (tDType)1) { \
30
+ return 1; \
31
+ } \
32
+ return 0; \
33
+ } \
34
+ lapack_logical _sort_ouc_##fLapackFunc(const tDType* wr, const tDType* wi) { \
35
+ tDType magnitude = *wr * *wr + *wi * *wi; \
36
+ if (magnitude > (tDType)1) { \
37
+ return 1; \
38
+ } \
39
+ return 0; \
48
40
  }
49
41
 
50
- #define DEF_GEES_SORT_FUNC_COMPLEX(tDType, tElType, fLapackRealFunc, fLapackImagFunc, fLapackFunc) \
51
- lapack_logical _sort_nil_##fLapackFunc(const tDType* w) { \
52
- return 0; \
53
- } \
54
- lapack_logical _sort_lhp_##fLapackFunc(const tDType* w) { \
55
- if (fLapackRealFunc(*w) < 0.0) { \
56
- return 1; \
57
- } \
58
- return 0; \
59
- } \
60
- lapack_logical _sort_rhp_##fLapackFunc(const tDType* w) { \
61
- if (fLapackRealFunc(*w) >= 0.0) { \
62
- return 1; \
63
- } \
64
- return 0; \
65
- } \
66
- lapack_logical _sort_iup_##fLapackFunc(const tDType* w) { \
67
- tElType real = fLapackRealFunc(*w); \
68
- tElType imag = fLapackImagFunc(*w); \
69
- tElType magnitude = real * real + imag * imag; \
70
- if (magnitude <= (tElType)1.0) { \
71
- return 1; \
72
- } \
73
- return 0; \
74
- } \
75
- lapack_logical _sort_ouc_##fLapackFunc(const tDType* w) { \
76
- tElType real = fLapackRealFunc(*w); \
77
- tElType imag = fLapackImagFunc(*w); \
78
- tElType magnitude = real * real + imag * imag; \
79
- if (magnitude > (tElType)1.0) { \
80
- return 1; \
81
- } \
82
- return 0; \
42
+ #define DEF_GEES_SORT_FUNC_COMPLEX( \
43
+ tDType, tElType, fLapackRealFunc, fLapackImagFunc, fLapackFunc \
44
+ ) \
45
+ lapack_logical _sort_nil_##fLapackFunc(const tDType* w) { \
46
+ return 0; \
47
+ } \
48
+ lapack_logical _sort_lhp_##fLapackFunc(const tDType* w) { \
49
+ if (fLapackRealFunc(*w) < 0.0) { \
50
+ return 1; \
51
+ } \
52
+ return 0; \
53
+ } \
54
+ lapack_logical _sort_rhp_##fLapackFunc(const tDType* w) { \
55
+ if (fLapackRealFunc(*w) >= 0.0) { \
56
+ return 1; \
57
+ } \
58
+ return 0; \
59
+ } \
60
+ lapack_logical _sort_iup_##fLapackFunc(const tDType* w) { \
61
+ tElType real = fLapackRealFunc(*w); \
62
+ tElType imag = fLapackImagFunc(*w); \
63
+ tElType magnitude = real * real + imag * imag; \
64
+ if (magnitude <= (tElType)1.0) { \
65
+ return 1; \
66
+ } \
67
+ return 0; \
68
+ } \
69
+ lapack_logical _sort_ouc_##fLapackFunc(const tDType* w) { \
70
+ tElType real = fLapackRealFunc(*w); \
71
+ tElType imag = fLapackImagFunc(*w); \
72
+ tElType magnitude = real * real + imag * imag; \
73
+ if (magnitude > (tElType)1.0) { \
74
+ return 1; \
75
+ } \
76
+ return 0; \
83
77
  }
84
78
 
85
- #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
86
- static void _iter_##fLapackFunc(na_loop_t* const lp) { \
87
- tDType* a = (tDType*)(NDL_PTR(lp, 0)); \
88
- tDType* wr = (tDType*)(NDL_PTR(lp, 1)); \
89
- tDType* wi = (tDType*)(NDL_PTR(lp, 2)); \
90
- tDType* vs = (tDType*)(NDL_PTR(lp, 3)); \
91
- int* sdim = (int*)(NDL_PTR(lp, 4)); \
92
- int* info = (int*)(NDL_PTR(lp, 5)); \
93
- struct _gees_option_##fLapackFunc* opt = (struct _gees_option_##fLapackFunc*)(lp->opt_ptr); \
94
- const lapack_int n = (lapack_int)(opt->matrix_layout == LAPACK_ROW_MAJOR ? NDL_SHAPE(lp, 0)[0] : NDL_SHAPE(lp, 0)[1]); \
95
- const lapack_int lda = n; \
96
- const lapack_int ldvs = (opt->jobvs == 'N') ? 1 : n; \
97
- lapack_int s = 0; \
98
- lapack_int i = LAPACKE_##fLapackFunc(opt->matrix_layout, opt->jobvs, opt->sort, opt->select, n, a, lda, &s, wr, wi, vs, ldvs); \
99
- *sdim = (int)s; \
100
- *info = (int)i; \
101
- } \
102
- \
103
- static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
104
- VALUE a_vnary = Qnil; \
105
- VALUE kw_args = Qnil; \
106
- rb_scan_args(argc, argv, "1:", &a_vnary, &kw_args); \
107
- ID kw_table[3] = { rb_intern("order"), rb_intern("jobvs"), rb_intern("sort") }; \
108
- VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
109
- rb_get_kwargs(kw_args, kw_table, 0, 3, kw_values); \
110
- const int matrix_layout = kw_values[0] != Qundef ? get_matrix_layout(kw_values[0]) : LAPACK_ROW_MAJOR; \
111
- const char jobvs = kw_values[1] != Qundef ? _get_jobvs(kw_values[1]) : 'V'; \
112
- VALUE sort_val = kw_values[2] != Qundef ? kw_values[2] : Qnil; \
113
- const char sort_ch = NIL_P(sort_val) ? 'N' : 'S'; \
114
- \
115
- if (CLASS_OF(a_vnary) != tNAryClass) { \
116
- a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
117
- } \
118
- if (!RTEST(nary_check_contiguous(a_vnary))) { \
119
- a_vnary = nary_dup(a_vnary); \
120
- } \
121
- \
122
- narray_t* a_nary = NULL; \
123
- GetNArray(a_vnary, a_nary); \
124
- if (NA_NDIM(a_nary) != 2) { \
125
- rb_raise(rb_eArgError, "input array must be 2-dimensional array"); \
126
- return Qnil; \
127
- } \
128
- \
129
- size_t n = matrix_layout == LAPACK_ROW_MAJOR ? NA_SHAPE(a_nary)[0] : NA_SHAPE(a_nary)[1]; \
130
- size_t shape_wr[1] = { n }; \
131
- size_t shape_wi[1] = { n }; \
132
- size_t shape_vs[2] = { n, jobvs == 'N' ? 1 : n }; \
133
- ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
134
- ndfunc_arg_out_t aout[5] = { { tNAryClass, 1, shape_wr }, { tNAryClass, 1, shape_wi }, { tNAryClass, 2, shape_vs }, { numo_cInt32, 0 }, { numo_cInt32, 0 } }; \
135
- ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 5, ain, aout }; \
136
- struct _gees_option_##fLapackFunc opt = { matrix_layout, jobvs, sort_ch, NULL }; \
137
- const char* sort_str = NIL_P(sort_val) ? "" : StringValueCStr(sort_val); \
138
- if (NIL_P(sort_val)) { \
139
- opt.select = _sort_nil_##fLapackFunc; \
140
- } else if (strcmp(sort_str, "lhp") == 0) { \
141
- opt.select = _sort_lhp_##fLapackFunc; \
142
- } else if (strcmp(sort_str, "rhp") == 0) { \
143
- opt.select = _sort_rhp_##fLapackFunc; \
144
- } else if (strcmp(sort_str, "iup") == 0) { \
145
- opt.select = _sort_iup_##fLapackFunc; \
146
- } else if (strcmp(sort_str, "ouc") == 0) { \
147
- opt.select = _sort_ouc_##fLapackFunc; \
148
- } else { \
149
- rb_raise(rb_eArgError, "invalid value for sort option"); \
150
- return Qnil; \
151
- } \
152
- VALUE ret = na_ndloop3(&ndf, &opt, 1, a_vnary); \
153
- \
154
- RB_GC_GUARD(sort_val); \
155
- RB_GC_GUARD(a_vnary); \
156
- return ret; \
79
+ #define DEF_LINALG_FUNC(tDType, tNAryClass, fLapackFunc) \
80
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
81
+ tDType* a = (tDType*)(NDL_PTR(lp, 0)); \
82
+ tDType* wr = (tDType*)(NDL_PTR(lp, 1)); \
83
+ tDType* wi = (tDType*)(NDL_PTR(lp, 2)); \
84
+ tDType* vs = (tDType*)(NDL_PTR(lp, 3)); \
85
+ int* sdim = (int*)(NDL_PTR(lp, 4)); \
86
+ int* info = (int*)(NDL_PTR(lp, 5)); \
87
+ struct _gees_option_##fLapackFunc* opt = \
88
+ (struct _gees_option_##fLapackFunc*)(lp->opt_ptr); \
89
+ const lapack_int n = \
90
+ (lapack_int)(opt->matrix_layout == LAPACK_ROW_MAJOR ? NDL_SHAPE(lp, 0)[0] \
91
+ : NDL_SHAPE(lp, 0)[1]); \
92
+ const lapack_int lda = n; \
93
+ const lapack_int ldvs = (opt->jobvs == 'N') ? 1 : n; \
94
+ lapack_int s = 0; \
95
+ lapack_int i = LAPACKE_##fLapackFunc( \
96
+ opt->matrix_layout, opt->jobvs, opt->sort, opt->select, n, a, lda, &s, wr, wi, vs, ldvs \
97
+ ); \
98
+ *sdim = (int)s; \
99
+ *info = (int)i; \
100
+ } \
101
+ \
102
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
103
+ VALUE a_vnary = Qnil; \
104
+ VALUE kw_args = Qnil; \
105
+ rb_scan_args(argc, argv, "1:", &a_vnary, &kw_args); \
106
+ ID kw_table[3] = { rb_intern("order"), rb_intern("jobvs"), rb_intern("sort") }; \
107
+ VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
108
+ rb_get_kwargs(kw_args, kw_table, 0, 3, kw_values); \
109
+ const int matrix_layout = \
110
+ kw_values[0] != Qundef ? get_matrix_layout(kw_values[0]) : LAPACK_ROW_MAJOR; \
111
+ const char jobvs = kw_values[1] != Qundef ? get_jobvs(kw_values[1]) : 'V'; \
112
+ VALUE sort_val = kw_values[2] != Qundef ? kw_values[2] : Qnil; \
113
+ const char sort_ch = NIL_P(sort_val) ? 'N' : 'S'; \
114
+ \
115
+ if (CLASS_OF(a_vnary) != tNAryClass) { \
116
+ a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
117
+ } \
118
+ if (!RTEST(nary_check_contiguous(a_vnary))) { \
119
+ a_vnary = nary_dup(a_vnary); \
120
+ } \
121
+ \
122
+ narray_t* a_nary = NULL; \
123
+ GetNArray(a_vnary, a_nary); \
124
+ if (NA_NDIM(a_nary) != 2) { \
125
+ rb_raise(rb_eArgError, "input array must be 2-dimensional array"); \
126
+ return Qnil; \
127
+ } \
128
+ \
129
+ size_t n = matrix_layout == LAPACK_ROW_MAJOR ? NA_SHAPE(a_nary)[0] : NA_SHAPE(a_nary)[1]; \
130
+ size_t shape_wr[1] = { n }; \
131
+ size_t shape_wi[1] = { n }; \
132
+ size_t shape_vs[2] = { n, jobvs == 'N' ? 1 : n }; \
133
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
134
+ ndfunc_arg_out_t aout[5] = { { tNAryClass, 1, shape_wr }, \
135
+ { tNAryClass, 1, shape_wi }, \
136
+ { tNAryClass, 2, shape_vs }, \
137
+ { numo_cInt32, 0 }, \
138
+ { numo_cInt32, 0 } }; \
139
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 5, ain, aout }; \
140
+ struct _gees_option_##fLapackFunc opt = { matrix_layout, jobvs, sort_ch, NULL }; \
141
+ const char* sort_str = NIL_P(sort_val) ? "" : StringValueCStr(sort_val); \
142
+ if (NIL_P(sort_val)) { \
143
+ opt.select = _sort_nil_##fLapackFunc; \
144
+ } else if (strcmp(sort_str, "lhp") == 0) { \
145
+ opt.select = _sort_lhp_##fLapackFunc; \
146
+ } else if (strcmp(sort_str, "rhp") == 0) { \
147
+ opt.select = _sort_rhp_##fLapackFunc; \
148
+ } else if (strcmp(sort_str, "iup") == 0) { \
149
+ opt.select = _sort_iup_##fLapackFunc; \
150
+ } else if (strcmp(sort_str, "ouc") == 0) { \
151
+ opt.select = _sort_ouc_##fLapackFunc; \
152
+ } else { \
153
+ rb_raise(rb_eArgError, "invalid value for sort option"); \
154
+ return Qnil; \
155
+ } \
156
+ VALUE res = na_ndloop3(&ndf, &opt, 1, a_vnary); \
157
+ VALUE ret = rb_ary_concat(rb_ary_new3(1, a_vnary), res); \
158
+ \
159
+ RB_GC_GUARD(sort_val); \
160
+ RB_GC_GUARD(a_vnary); \
161
+ return ret; \
157
162
  }
158
163
 
159
- #define DEF_LINALG_FUNC_COMPLEX(tDType, tNAryClass, fLapackFunc) \
160
- static void _iter_##fLapackFunc(na_loop_t* const lp) { \
161
- tDType* a = (tDType*)(NDL_PTR(lp, 0)); \
162
- tDType* w = (tDType*)(NDL_PTR(lp, 1)); \
163
- tDType* vs = (tDType*)(NDL_PTR(lp, 2)); \
164
- int* sdim = (int*)(NDL_PTR(lp, 3)); \
165
- int* info = (int*)(NDL_PTR(lp, 4)); \
166
- struct _gees_option_##fLapackFunc* opt = (struct _gees_option_##fLapackFunc*)(lp->opt_ptr); \
167
- const lapack_int n = (lapack_int)(opt->matrix_layout == LAPACK_ROW_MAJOR ? NDL_SHAPE(lp, 0)[0] : NDL_SHAPE(lp, 0)[1]); \
168
- const lapack_int lda = n; \
169
- const lapack_int ldvs = (opt->jobvs == 'N') ? 1 : n; \
170
- lapack_int s = 0; \
171
- lapack_int i = LAPACKE_##fLapackFunc(opt->matrix_layout, opt->jobvs, opt->sort, opt->select, n, a, lda, &s, w, vs, ldvs); \
172
- *sdim = (int)s; \
173
- *info = (int)i; \
174
- } \
175
- \
176
- static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
177
- VALUE a_vnary = Qnil; \
178
- VALUE kw_args = Qnil; \
179
- rb_scan_args(argc, argv, "1:", &a_vnary, &kw_args); \
180
- ID kw_table[3] = { rb_intern("order"), rb_intern("jobvs"), rb_intern("sort") }; \
181
- VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
182
- rb_get_kwargs(kw_args, kw_table, 0, 3, kw_values); \
183
- const int matrix_layout = kw_values[0] != Qundef ? get_matrix_layout(kw_values[0]) : LAPACK_ROW_MAJOR; \
184
- const char jobvs = kw_values[1] != Qundef ? _get_jobvs(kw_values[1]) : 'V'; \
185
- VALUE sort_val = kw_values[2] != Qundef ? kw_values[2] : Qnil; \
186
- const char sort_ch = NIL_P(sort_val) ? 'N' : 'S'; \
187
- \
188
- if (CLASS_OF(a_vnary) != tNAryClass) { \
189
- a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
190
- } \
191
- if (!RTEST(nary_check_contiguous(a_vnary))) { \
192
- a_vnary = nary_dup(a_vnary); \
193
- } \
194
- \
195
- narray_t* a_nary = NULL; \
196
- GetNArray(a_vnary, a_nary); \
197
- if (NA_NDIM(a_nary) != 2) { \
198
- rb_raise(rb_eArgError, "input array must be 2-dimensional array"); \
199
- return Qnil; \
200
- } \
201
- \
202
- size_t n = matrix_layout == LAPACK_ROW_MAJOR ? NA_SHAPE(a_nary)[0] : NA_SHAPE(a_nary)[1]; \
203
- size_t shape_w[1] = { n }; \
204
- size_t shape_vs[2] = { n, jobvs == 'N' ? 1 : n }; \
205
- ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
206
- ndfunc_arg_out_t aout[4] = { { tNAryClass, 1, shape_w }, { tNAryClass, 2, shape_vs }, { numo_cInt32, 0 }, { numo_cInt32, 0 } }; \
207
- ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 4, ain, aout }; \
208
- struct _gees_option_##fLapackFunc opt = { matrix_layout, jobvs, sort_ch, NULL }; \
209
- const char* sort_str = NIL_P(sort_val) ? "" : StringValueCStr(sort_val); \
210
- if (NIL_P(sort_val)) { \
211
- opt.select = _sort_nil_##fLapackFunc; \
212
- } else if (strcmp(sort_str, "lhp") == 0) { \
213
- opt.select = _sort_lhp_##fLapackFunc; \
214
- } else if (strcmp(sort_str, "rhp") == 0) { \
215
- opt.select = _sort_rhp_##fLapackFunc; \
216
- } else if (strcmp(sort_str, "iup") == 0) { \
217
- opt.select = _sort_iup_##fLapackFunc; \
218
- } else if (strcmp(sort_str, "ouc") == 0) { \
219
- opt.select = _sort_ouc_##fLapackFunc; \
220
- } else { \
221
- rb_raise(rb_eArgError, "invalid value for sort option"); \
222
- return Qnil; \
223
- } \
224
- VALUE ret = na_ndloop3(&ndf, &opt, 1, a_vnary); \
225
- \
226
- RB_GC_GUARD(sort_val); \
227
- RB_GC_GUARD(a_vnary); \
228
- return ret; \
164
+ #define DEF_LINALG_FUNC_COMPLEX(tDType, tNAryClass, fLapackFunc) \
165
+ static void _iter_##fLapackFunc(na_loop_t* const lp) { \
166
+ tDType* a = (tDType*)(NDL_PTR(lp, 0)); \
167
+ tDType* w = (tDType*)(NDL_PTR(lp, 1)); \
168
+ tDType* vs = (tDType*)(NDL_PTR(lp, 2)); \
169
+ int* sdim = (int*)(NDL_PTR(lp, 3)); \
170
+ int* info = (int*)(NDL_PTR(lp, 4)); \
171
+ struct _gees_option_##fLapackFunc* opt = \
172
+ (struct _gees_option_##fLapackFunc*)(lp->opt_ptr); \
173
+ const lapack_int n = \
174
+ (lapack_int)(opt->matrix_layout == LAPACK_ROW_MAJOR ? NDL_SHAPE(lp, 0)[0] \
175
+ : NDL_SHAPE(lp, 0)[1]); \
176
+ const lapack_int lda = n; \
177
+ const lapack_int ldvs = (opt->jobvs == 'N') ? 1 : n; \
178
+ lapack_int s = 0; \
179
+ lapack_int i = LAPACKE_##fLapackFunc( \
180
+ opt->matrix_layout, opt->jobvs, opt->sort, opt->select, n, a, lda, &s, w, vs, ldvs \
181
+ ); \
182
+ *sdim = (int)s; \
183
+ *info = (int)i; \
184
+ } \
185
+ \
186
+ static VALUE _linalg_lapack_##fLapackFunc(int argc, VALUE* argv, VALUE self) { \
187
+ VALUE a_vnary = Qnil; \
188
+ VALUE kw_args = Qnil; \
189
+ rb_scan_args(argc, argv, "1:", &a_vnary, &kw_args); \
190
+ ID kw_table[3] = { rb_intern("order"), rb_intern("jobvs"), rb_intern("sort") }; \
191
+ VALUE kw_values[3] = { Qundef, Qundef, Qundef }; \
192
+ rb_get_kwargs(kw_args, kw_table, 0, 3, kw_values); \
193
+ const int matrix_layout = \
194
+ kw_values[0] != Qundef ? get_matrix_layout(kw_values[0]) : LAPACK_ROW_MAJOR; \
195
+ const char jobvs = kw_values[1] != Qundef ? get_jobvs(kw_values[1]) : 'V'; \
196
+ VALUE sort_val = kw_values[2] != Qundef ? kw_values[2] : Qnil; \
197
+ const char sort_ch = NIL_P(sort_val) ? 'N' : 'S'; \
198
+ \
199
+ if (CLASS_OF(a_vnary) != tNAryClass) { \
200
+ a_vnary = rb_funcall(tNAryClass, rb_intern("cast"), 1, a_vnary); \
201
+ } \
202
+ if (!RTEST(nary_check_contiguous(a_vnary))) { \
203
+ a_vnary = nary_dup(a_vnary); \
204
+ } \
205
+ \
206
+ narray_t* a_nary = NULL; \
207
+ GetNArray(a_vnary, a_nary); \
208
+ if (NA_NDIM(a_nary) != 2) { \
209
+ rb_raise(rb_eArgError, "input array must be 2-dimensional array"); \
210
+ return Qnil; \
211
+ } \
212
+ \
213
+ size_t n = matrix_layout == LAPACK_ROW_MAJOR ? NA_SHAPE(a_nary)[0] : NA_SHAPE(a_nary)[1]; \
214
+ size_t shape_w[1] = { n }; \
215
+ size_t shape_vs[2] = { n, jobvs == 'N' ? 1 : n }; \
216
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 2 } }; \
217
+ ndfunc_arg_out_t aout[4] = { { tNAryClass, 1, shape_w }, \
218
+ { tNAryClass, 2, shape_vs }, \
219
+ { numo_cInt32, 0 }, \
220
+ { numo_cInt32, 0 } }; \
221
+ ndfunc_t ndf = { _iter_##fLapackFunc, NO_LOOP | NDF_EXTRACT, 1, 4, ain, aout }; \
222
+ struct _gees_option_##fLapackFunc opt = { matrix_layout, jobvs, sort_ch, NULL }; \
223
+ const char* sort_str = NIL_P(sort_val) ? "" : StringValueCStr(sort_val); \
224
+ if (NIL_P(sort_val)) { \
225
+ opt.select = _sort_nil_##fLapackFunc; \
226
+ } else if (strcmp(sort_str, "lhp") == 0) { \
227
+ opt.select = _sort_lhp_##fLapackFunc; \
228
+ } else if (strcmp(sort_str, "rhp") == 0) { \
229
+ opt.select = _sort_rhp_##fLapackFunc; \
230
+ } else if (strcmp(sort_str, "iup") == 0) { \
231
+ opt.select = _sort_iup_##fLapackFunc; \
232
+ } else if (strcmp(sort_str, "ouc") == 0) { \
233
+ opt.select = _sort_ouc_##fLapackFunc; \
234
+ } else { \
235
+ rb_raise(rb_eArgError, "invalid value for sort option"); \
236
+ return Qnil; \
237
+ } \
238
+ VALUE res = na_ndloop3(&ndf, &opt, 1, a_vnary); \
239
+ VALUE ret = rb_ary_concat(rb_ary_new3(1, a_vnary), res); \
240
+ \
241
+ RB_GC_GUARD(sort_val); \
242
+ RB_GC_GUARD(a_vnary); \
243
+ return ret; \
229
244
  }
230
245
 
231
246
  DEF_GEES_OPTION(dgees, LAPACK_D_SELECT2)
@@ -235,8 +250,12 @@ DEF_GEES_OPTION(cgees, LAPACK_C_SELECT1)
235
250
 
236
251
  DEF_GEES_SORT_FUNC(double, dgees)
237
252
  DEF_GEES_SORT_FUNC(float, sgees)
238
- DEF_GEES_SORT_FUNC_COMPLEX(lapack_complex_double, double, lapack_complex_double_real, lapack_complex_double_imag, zgees)
239
- DEF_GEES_SORT_FUNC_COMPLEX(lapack_complex_float, float, lapack_complex_float_real, lapack_complex_float_imag, cgees)
253
+ DEF_GEES_SORT_FUNC_COMPLEX(
254
+ lapack_complex_double, double, lapack_complex_double_real, lapack_complex_double_imag, zgees
255
+ )
256
+ DEF_GEES_SORT_FUNC_COMPLEX(
257
+ lapack_complex_float, float, lapack_complex_float_real, lapack_complex_float_imag, cgees
258
+ )
240
259
 
241
260
  DEF_LINALG_FUNC(double, numo_cDFloat, dgees)
242
261
  DEF_LINALG_FUNC(float, numo_cSFloat, sgees)