numo-linalg-alt 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +3 -1
- data/ext/numo/linalg/blas/dot.c +59 -59
- data/ext/numo/linalg/blas/dot_sub.c +58 -58
- data/ext/numo/linalg/blas/gemm.c +157 -148
- data/ext/numo/linalg/blas/gemv.c +131 -127
- data/ext/numo/linalg/blas/nrm2.c +50 -50
- data/ext/numo/linalg/lapack/gees.c +276 -0
- data/ext/numo/linalg/lapack/gees.h +15 -0
- data/ext/numo/linalg/lapack/geev.c +127 -110
- data/ext/numo/linalg/lapack/gelsd.c +81 -70
- data/ext/numo/linalg/lapack/geqrf.c +52 -51
- data/ext/numo/linalg/lapack/gerqf.c +70 -0
- data/ext/numo/linalg/lapack/gerqf.h +15 -0
- data/ext/numo/linalg/lapack/gesdd.c +96 -86
- data/ext/numo/linalg/lapack/gesv.c +80 -78
- data/ext/numo/linalg/lapack/gesvd.c +140 -129
- data/ext/numo/linalg/lapack/getrf.c +51 -50
- data/ext/numo/linalg/lapack/getri.c +64 -63
- data/ext/numo/linalg/lapack/getrs.c +92 -88
- data/ext/numo/linalg/lapack/gges.c +214 -0
- data/ext/numo/linalg/lapack/gges.h +15 -0
- data/ext/numo/linalg/lapack/heev.c +54 -52
- data/ext/numo/linalg/lapack/heevd.c +54 -52
- data/ext/numo/linalg/lapack/heevr.c +109 -98
- data/ext/numo/linalg/lapack/hegv.c +77 -74
- data/ext/numo/linalg/lapack/hegvd.c +77 -74
- data/ext/numo/linalg/lapack/hegvx.c +132 -120
- data/ext/numo/linalg/lapack/hetrf.c +54 -50
- data/ext/numo/linalg/lapack/lange.c +45 -44
- data/ext/numo/linalg/lapack/orgqr.c +63 -62
- data/ext/numo/linalg/lapack/orgrq.c +78 -0
- data/ext/numo/linalg/lapack/orgrq.h +15 -0
- data/ext/numo/linalg/lapack/potrf.c +49 -48
- data/ext/numo/linalg/lapack/potri.c +49 -48
- data/ext/numo/linalg/lapack/potrs.c +74 -72
- data/ext/numo/linalg/lapack/syev.c +54 -52
- data/ext/numo/linalg/lapack/syevd.c +54 -52
- data/ext/numo/linalg/lapack/syevr.c +107 -98
- data/ext/numo/linalg/lapack/sygv.c +77 -73
- data/ext/numo/linalg/lapack/sygvd.c +77 -73
- data/ext/numo/linalg/lapack/sygvx.c +132 -120
- data/ext/numo/linalg/lapack/sytrf.c +54 -50
- data/ext/numo/linalg/lapack/trtrs.c +79 -75
- data/ext/numo/linalg/lapack/ungqr.c +63 -62
- data/ext/numo/linalg/lapack/ungrq.c +78 -0
- data/ext/numo/linalg/lapack/ungrq.h +15 -0
- data/ext/numo/linalg/linalg.c +21 -10
- data/ext/numo/linalg/linalg.h +5 -0
- data/ext/numo/linalg/util.c +8 -0
- data/ext/numo/linalg/util.h +1 -0
- data/lib/numo/linalg/version.rb +1 -1
- data/lib/numo/linalg.rb +322 -0
- metadata +14 -4
data/ext/numo/linalg/blas/gemv.c
CHANGED
@@ -1,138 +1,142 @@
|
|
1
1
|
#include "gemv.h"
|
2
2
|
|
3
|
-
#define DEF_LINALG_OPTIONS(tDType)
|
4
|
-
struct _gemv_options_##tDType {
|
5
|
-
tDType alpha;
|
6
|
-
tDType beta;
|
7
|
-
enum CBLAS_ORDER order;
|
8
|
-
enum CBLAS_TRANSPOSE trans;
|
9
|
-
blasint m;
|
10
|
-
blasint n;
|
3
|
+
#define DEF_LINALG_OPTIONS(tDType) \
|
4
|
+
struct _gemv_options_##tDType { \
|
5
|
+
tDType alpha; \
|
6
|
+
tDType beta; \
|
7
|
+
enum CBLAS_ORDER order; \
|
8
|
+
enum CBLAS_TRANSPOSE trans; \
|
9
|
+
blasint m; \
|
10
|
+
blasint n; \
|
11
11
|
};
|
12
12
|
|
13
|
-
#define DEF_LINALG_ITER_FUNC(tDType, fBlasFunc)
|
14
|
-
static void _iter_##fBlasFunc(na_loop_t* const lp) {
|
15
|
-
const tDType* a = (tDType*)NDL_PTR(lp, 0);
|
16
|
-
const tDType* x = (tDType*)NDL_PTR(lp, 1);
|
17
|
-
tDType* y = (tDType*)NDL_PTR(lp, 2);
|
18
|
-
const struct _gemv_options_##tDType* opt = (struct _gemv_options_##tDType*)(lp->opt_ptr);
|
19
|
-
const blasint lda = opt->n;
|
20
|
-
cblas_##fBlasFunc(
|
21
|
-
|
13
|
+
#define DEF_LINALG_ITER_FUNC(tDType, fBlasFunc) \
|
14
|
+
static void _iter_##fBlasFunc(na_loop_t* const lp) { \
|
15
|
+
const tDType* a = (tDType*)NDL_PTR(lp, 0); \
|
16
|
+
const tDType* x = (tDType*)NDL_PTR(lp, 1); \
|
17
|
+
tDType* y = (tDType*)NDL_PTR(lp, 2); \
|
18
|
+
const struct _gemv_options_##tDType* opt = (struct _gemv_options_##tDType*)(lp->opt_ptr); \
|
19
|
+
const blasint lda = opt->n; \
|
20
|
+
cblas_##fBlasFunc( \
|
21
|
+
opt->order, opt->trans, opt->m, opt->n, opt->alpha, a, lda, x, 1, opt->beta, y, 1 \
|
22
|
+
); \
|
22
23
|
}
|
23
24
|
|
24
|
-
#define DEF_LINALG_ITER_FUNC_COMPLEX(tDType, fBlasFunc)
|
25
|
-
static void _iter_##fBlasFunc(na_loop_t* const lp) {
|
26
|
-
const tDType* a = (tDType*)NDL_PTR(lp, 0);
|
27
|
-
const tDType* x = (tDType*)NDL_PTR(lp, 1);
|
28
|
-
tDType* y = (tDType*)NDL_PTR(lp, 2);
|
29
|
-
const struct _gemv_options_##tDType* opt = (struct _gemv_options_##tDType*)(lp->opt_ptr);
|
30
|
-
const blasint lda = opt->n;
|
31
|
-
cblas_##fBlasFunc(
|
32
|
-
|
25
|
+
#define DEF_LINALG_ITER_FUNC_COMPLEX(tDType, fBlasFunc) \
|
26
|
+
static void _iter_##fBlasFunc(na_loop_t* const lp) { \
|
27
|
+
const tDType* a = (tDType*)NDL_PTR(lp, 0); \
|
28
|
+
const tDType* x = (tDType*)NDL_PTR(lp, 1); \
|
29
|
+
tDType* y = (tDType*)NDL_PTR(lp, 2); \
|
30
|
+
const struct _gemv_options_##tDType* opt = (struct _gemv_options_##tDType*)(lp->opt_ptr); \
|
31
|
+
const blasint lda = opt->n; \
|
32
|
+
cblas_##fBlasFunc( \
|
33
|
+
opt->order, opt->trans, opt->m, opt->n, &opt->alpha, a, lda, x, 1, &opt->beta, y, 1 \
|
34
|
+
); \
|
33
35
|
}
|
34
36
|
|
35
|
-
#define DEF_LINALG_FUNC(tDType, tNAryClass, fBlasFunc)
|
36
|
-
static VALUE _linalg_blas_##fBlasFunc(int argc, VALUE* argv, VALUE self) {
|
37
|
-
VALUE a = Qnil;
|
38
|
-
VALUE x = Qnil;
|
39
|
-
VALUE y = Qnil;
|
40
|
-
VALUE kw_args = Qnil;
|
41
|
-
rb_scan_args(argc, argv, "21:", &a, &x, &y, &kw_args);
|
42
|
-
|
43
|
-
ID kw_table[4] = { rb_intern("alpha"), rb_intern("beta"),
|
44
|
-
rb_intern("
|
45
|
-
VALUE kw_values[4] = { Qundef, Qundef, Qundef, Qundef };
|
46
|
-
rb_get_kwargs(kw_args, kw_table, 0, 4, kw_values);
|
47
|
-
|
48
|
-
if (CLASS_OF(a) != tNAryClass) {
|
49
|
-
a = rb_funcall(tNAryClass, rb_intern("cast"), 1, a);
|
50
|
-
}
|
51
|
-
if (!RTEST(nary_check_contiguous(a))) {
|
52
|
-
a = nary_dup(a);
|
53
|
-
}
|
54
|
-
if (CLASS_OF(x) != tNAryClass) {
|
55
|
-
x = rb_funcall(tNAryClass, rb_intern("cast"), 1, x);
|
56
|
-
}
|
57
|
-
if (!RTEST(nary_check_contiguous(x))) {
|
58
|
-
x = nary_dup(x);
|
59
|
-
}
|
60
|
-
if (!NIL_P(y)) {
|
61
|
-
if (CLASS_OF(y) != tNAryClass) {
|
62
|
-
y = rb_funcall(tNAryClass, rb_intern("cast"), 1, y);
|
63
|
-
}
|
64
|
-
if (!RTEST(nary_check_contiguous(y))) {
|
65
|
-
y = nary_dup(y);
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
tDType alpha = kw_values[0] != Qundef ? conv_##tDType(kw_values[0]) : one_##tDType();
|
70
|
-
tDType beta = kw_values[1] != Qundef ? conv_##tDType(kw_values[1]) : zero_##tDType();
|
71
|
-
enum CBLAS_ORDER order =
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
narray_t*
|
77
|
-
GetNArray(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
const blasint
|
99
|
-
const blasint
|
100
|
-
const blasint
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
RB_GC_GUARD(
|
134
|
-
|
135
|
-
|
37
|
+
#define DEF_LINALG_FUNC(tDType, tNAryClass, fBlasFunc) \
|
38
|
+
static VALUE _linalg_blas_##fBlasFunc(int argc, VALUE* argv, VALUE self) { \
|
39
|
+
VALUE a = Qnil; \
|
40
|
+
VALUE x = Qnil; \
|
41
|
+
VALUE y = Qnil; \
|
42
|
+
VALUE kw_args = Qnil; \
|
43
|
+
rb_scan_args(argc, argv, "21:", &a, &x, &y, &kw_args); \
|
44
|
+
\
|
45
|
+
ID kw_table[4] = { rb_intern("alpha"), rb_intern("beta"), rb_intern("order"), \
|
46
|
+
rb_intern("trans") }; \
|
47
|
+
VALUE kw_values[4] = { Qundef, Qundef, Qundef, Qundef }; \
|
48
|
+
rb_get_kwargs(kw_args, kw_table, 0, 4, kw_values); \
|
49
|
+
\
|
50
|
+
if (CLASS_OF(a) != tNAryClass) { \
|
51
|
+
a = rb_funcall(tNAryClass, rb_intern("cast"), 1, a); \
|
52
|
+
} \
|
53
|
+
if (!RTEST(nary_check_contiguous(a))) { \
|
54
|
+
a = nary_dup(a); \
|
55
|
+
} \
|
56
|
+
if (CLASS_OF(x) != tNAryClass) { \
|
57
|
+
x = rb_funcall(tNAryClass, rb_intern("cast"), 1, x); \
|
58
|
+
} \
|
59
|
+
if (!RTEST(nary_check_contiguous(x))) { \
|
60
|
+
x = nary_dup(x); \
|
61
|
+
} \
|
62
|
+
if (!NIL_P(y)) { \
|
63
|
+
if (CLASS_OF(y) != tNAryClass) { \
|
64
|
+
y = rb_funcall(tNAryClass, rb_intern("cast"), 1, y); \
|
65
|
+
} \
|
66
|
+
if (!RTEST(nary_check_contiguous(y))) { \
|
67
|
+
y = nary_dup(y); \
|
68
|
+
} \
|
69
|
+
} \
|
70
|
+
\
|
71
|
+
tDType alpha = kw_values[0] != Qundef ? conv_##tDType(kw_values[0]) : one_##tDType(); \
|
72
|
+
tDType beta = kw_values[1] != Qundef ? conv_##tDType(kw_values[1]) : zero_##tDType(); \
|
73
|
+
enum CBLAS_ORDER order = \
|
74
|
+
kw_values[2] != Qundef ? get_cblas_order(kw_values[2]) : CblasRowMajor; \
|
75
|
+
enum CBLAS_TRANSPOSE trans = \
|
76
|
+
kw_values[3] != Qundef ? get_cblas_trans(kw_values[3]) : CblasNoTrans; \
|
77
|
+
\
|
78
|
+
narray_t* a_nary = NULL; \
|
79
|
+
GetNArray(a, a_nary); \
|
80
|
+
narray_t* x_nary = NULL; \
|
81
|
+
GetNArray(x, x_nary); \
|
82
|
+
\
|
83
|
+
if (NA_NDIM(a_nary) != 2) { \
|
84
|
+
rb_raise(rb_eArgError, "a must be 2-dimensional"); \
|
85
|
+
return Qnil; \
|
86
|
+
} \
|
87
|
+
if (NA_NDIM(x_nary) != 1) { \
|
88
|
+
rb_raise(rb_eArgError, "x must be 1-dimensional"); \
|
89
|
+
return Qnil; \
|
90
|
+
} \
|
91
|
+
if (NA_SIZE(a_nary) == 0) { \
|
92
|
+
rb_raise(rb_eArgError, "a must not be empty"); \
|
93
|
+
return Qnil; \
|
94
|
+
} \
|
95
|
+
if (NA_SIZE(x_nary) == 0) { \
|
96
|
+
rb_raise(rb_eArgError, "x must not be empty"); \
|
97
|
+
return Qnil; \
|
98
|
+
} \
|
99
|
+
\
|
100
|
+
const blasint ma = (blasint)NA_SHAPE(a_nary)[0]; \
|
101
|
+
const blasint na = (blasint)NA_SHAPE(a_nary)[1]; \
|
102
|
+
const blasint mx = (blasint)NA_SHAPE(x_nary)[0]; \
|
103
|
+
const blasint m = trans == CblasNoTrans ? ma : na; \
|
104
|
+
const blasint n = trans == CblasNoTrans ? na : ma; \
|
105
|
+
\
|
106
|
+
if (n != mx) { \
|
107
|
+
rb_raise(nary_eShapeError, "shape1[1](=%d) != shape2[0](=%d)", n, mx); \
|
108
|
+
return Qnil; \
|
109
|
+
} \
|
110
|
+
\
|
111
|
+
struct _gemv_options_##tDType opt = { alpha, beta, order, trans, ma, na }; \
|
112
|
+
size_t shape_out[1] = { (size_t)(m) }; \
|
113
|
+
ndfunc_arg_out_t aout[1] = { { tNAryClass, 1, shape_out } }; \
|
114
|
+
VALUE ret = Qnil; \
|
115
|
+
\
|
116
|
+
if (!NIL_P(y)) { \
|
117
|
+
narray_t* y_nary = NULL; \
|
118
|
+
GetNArray(y, y_nary); \
|
119
|
+
blasint my = (blasint)NA_SHAPE(y_nary)[0]; \
|
120
|
+
if (m > my) { \
|
121
|
+
rb_raise(nary_eShapeError, "shape3[0](=%d) >= shape1[0]=%d", my, m); \
|
122
|
+
return Qnil; \
|
123
|
+
} \
|
124
|
+
ndfunc_arg_in_t ain[3] = { { tNAryClass, 2 }, { tNAryClass, 1 }, { OVERWRITE, 1 } }; \
|
125
|
+
ndfunc_t ndf = { _iter_##fBlasFunc, NO_LOOP, 3, 0, ain, aout }; \
|
126
|
+
na_ndloop3(&ndf, &opt, 3, a, x, y); \
|
127
|
+
ret = y; \
|
128
|
+
} else { \
|
129
|
+
y = INT2NUM(0); \
|
130
|
+
ndfunc_arg_in_t ain[3] = { { tNAryClass, 2 }, { tNAryClass, 1 }, { sym_init, 0 } }; \
|
131
|
+
ndfunc_t ndf = { _iter_##fBlasFunc, NO_LOOP, 3, 1, ain, aout }; \
|
132
|
+
ret = na_ndloop3(&ndf, &opt, 3, a, x, y); \
|
133
|
+
} \
|
134
|
+
\
|
135
|
+
RB_GC_GUARD(a); \
|
136
|
+
RB_GC_GUARD(x); \
|
137
|
+
RB_GC_GUARD(y); \
|
138
|
+
\
|
139
|
+
return ret; \
|
136
140
|
}
|
137
141
|
|
138
142
|
DEF_LINALG_OPTIONS(double)
|
data/ext/numo/linalg/blas/nrm2.c
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
#include "nrm2.h"
|
2
2
|
|
3
|
-
#define DEF_LINALG_FUNC(tDType, tRtDType, tNAryClass, tRtNAryClass, fBlasFunc)
|
4
|
-
static void _iter_##fBlasFunc(na_loop_t* const lp) {
|
5
|
-
tDType* x = (tDType*)NDL_PTR(lp, 0);
|
6
|
-
tRtDType* d = (tRtDType*)NDL_PTR(lp, 1);
|
7
|
-
const blasint n = (blasint)NDL_SHAPE(lp, 0)[0];
|
8
|
-
tRtDType ret = cblas_##fBlasFunc(n, x, 1);
|
9
|
-
*d = ret;
|
10
|
-
}
|
11
|
-
|
12
|
-
static VALUE _linalg_blas_##fBlasFunc(int argc, VALUE* argv, VALUE self) {
|
13
|
-
VALUE x = Qnil;
|
14
|
-
VALUE kw_args = Qnil;
|
15
|
-
rb_scan_args(argc, argv, "1:", &x, &kw_args);
|
16
|
-
|
17
|
-
ID kw_table[1] = { rb_intern("keepdims") };
|
18
|
-
VALUE kw_values[1] = { Qundef };
|
19
|
-
rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values);
|
20
|
-
const bool keepdims = kw_values[0] != Qundef ? RTEST(kw_values[0]) : false;
|
21
|
-
|
22
|
-
if (CLASS_OF(x) != tNAryClass) {
|
23
|
-
x = rb_funcall(tNAryClass, rb_intern("cast"), 1, x);
|
24
|
-
}
|
25
|
-
if (!RTEST(nary_check_contiguous(x))) {
|
26
|
-
x = nary_dup(x);
|
27
|
-
}
|
28
|
-
|
29
|
-
narray_t* x_nary = NULL;
|
30
|
-
GetNArray(x, x_nary);
|
31
|
-
|
32
|
-
if (NA_NDIM(x_nary) != 1) {
|
33
|
-
rb_raise(rb_eArgError, "x must be 1-dimensional");
|
34
|
-
return Qnil;
|
35
|
-
}
|
36
|
-
if (NA_SIZE(x_nary) == 0) {
|
37
|
-
rb_raise(rb_eArgError, "x must not be empty");
|
38
|
-
return Qnil;
|
39
|
-
}
|
40
|
-
|
41
|
-
ndfunc_arg_in_t ain[1] = { { tNAryClass, 1 } };
|
42
|
-
size_t shape_out[1] = { 1 };
|
43
|
-
ndfunc_arg_out_t aout[1] = { { tRtNAryClass, 0, shape_out } };
|
44
|
-
ndfunc_t ndf = { _iter_##fBlasFunc, NO_LOOP | NDF_EXTRACT, 1, 1, ain, aout };
|
45
|
-
if (keepdims) {
|
46
|
-
ndf.flag |= NDF_KEEP_DIM;
|
47
|
-
}
|
48
|
-
|
49
|
-
VALUE ret = na_ndloop(&ndf, 1, x);
|
50
|
-
|
51
|
-
RB_GC_GUARD(x);
|
52
|
-
return ret;
|
3
|
+
#define DEF_LINALG_FUNC(tDType, tRtDType, tNAryClass, tRtNAryClass, fBlasFunc) \
|
4
|
+
static void _iter_##fBlasFunc(na_loop_t* const lp) { \
|
5
|
+
tDType* x = (tDType*)NDL_PTR(lp, 0); \
|
6
|
+
tRtDType* d = (tRtDType*)NDL_PTR(lp, 1); \
|
7
|
+
const blasint n = (blasint)NDL_SHAPE(lp, 0)[0]; \
|
8
|
+
tRtDType ret = cblas_##fBlasFunc(n, x, 1); \
|
9
|
+
*d = ret; \
|
10
|
+
} \
|
11
|
+
\
|
12
|
+
static VALUE _linalg_blas_##fBlasFunc(int argc, VALUE* argv, VALUE self) { \
|
13
|
+
VALUE x = Qnil; \
|
14
|
+
VALUE kw_args = Qnil; \
|
15
|
+
rb_scan_args(argc, argv, "1:", &x, &kw_args); \
|
16
|
+
\
|
17
|
+
ID kw_table[1] = { rb_intern("keepdims") }; \
|
18
|
+
VALUE kw_values[1] = { Qundef }; \
|
19
|
+
rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values); \
|
20
|
+
const bool keepdims = kw_values[0] != Qundef ? RTEST(kw_values[0]) : false; \
|
21
|
+
\
|
22
|
+
if (CLASS_OF(x) != tNAryClass) { \
|
23
|
+
x = rb_funcall(tNAryClass, rb_intern("cast"), 1, x); \
|
24
|
+
} \
|
25
|
+
if (!RTEST(nary_check_contiguous(x))) { \
|
26
|
+
x = nary_dup(x); \
|
27
|
+
} \
|
28
|
+
\
|
29
|
+
narray_t* x_nary = NULL; \
|
30
|
+
GetNArray(x, x_nary); \
|
31
|
+
\
|
32
|
+
if (NA_NDIM(x_nary) != 1) { \
|
33
|
+
rb_raise(rb_eArgError, "x must be 1-dimensional"); \
|
34
|
+
return Qnil; \
|
35
|
+
} \
|
36
|
+
if (NA_SIZE(x_nary) == 0) { \
|
37
|
+
rb_raise(rb_eArgError, "x must not be empty"); \
|
38
|
+
return Qnil; \
|
39
|
+
} \
|
40
|
+
\
|
41
|
+
ndfunc_arg_in_t ain[1] = { { tNAryClass, 1 } }; \
|
42
|
+
size_t shape_out[1] = { 1 }; \
|
43
|
+
ndfunc_arg_out_t aout[1] = { { tRtNAryClass, 0, shape_out } }; \
|
44
|
+
ndfunc_t ndf = { _iter_##fBlasFunc, NO_LOOP | NDF_EXTRACT, 1, 1, ain, aout }; \
|
45
|
+
if (keepdims) { \
|
46
|
+
ndf.flag |= NDF_KEEP_DIM; \
|
47
|
+
} \
|
48
|
+
\
|
49
|
+
VALUE ret = na_ndloop(&ndf, 1, x); \
|
50
|
+
\
|
51
|
+
RB_GC_GUARD(x); \
|
52
|
+
return ret; \
|
53
53
|
}
|
54
54
|
|
55
55
|
DEF_LINALG_FUNC(double, double, numo_cDFloat, numo_cDFloat, dnrm2)
|