nmatrix 0.0.1 → 0.0.2
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.
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +3 -5
- data/Guardfile +6 -0
- data/History.txt +33 -0
- data/Manifest.txt +41 -38
- data/README.rdoc +88 -11
- data/Rakefile +35 -53
- data/ext/nmatrix/data/complex.h +372 -0
- data/ext/nmatrix/data/data.cpp +275 -0
- data/ext/nmatrix/data/data.h +707 -0
- data/ext/nmatrix/data/rational.h +421 -0
- data/ext/nmatrix/data/ruby_object.h +446 -0
- data/ext/nmatrix/extconf.rb +101 -51
- data/ext/nmatrix/new_extconf.rb +56 -0
- data/ext/nmatrix/nmatrix.cpp +1609 -0
- data/ext/nmatrix/nmatrix.h +265 -849
- data/ext/nmatrix/ruby_constants.cpp +134 -0
- data/ext/nmatrix/ruby_constants.h +103 -0
- data/ext/nmatrix/storage/common.cpp +70 -0
- data/ext/nmatrix/storage/common.h +170 -0
- data/ext/nmatrix/storage/dense.cpp +665 -0
- data/ext/nmatrix/storage/dense.h +116 -0
- data/ext/nmatrix/storage/list.cpp +1088 -0
- data/ext/nmatrix/storage/list.h +129 -0
- data/ext/nmatrix/storage/storage.cpp +658 -0
- data/ext/nmatrix/storage/storage.h +99 -0
- data/ext/nmatrix/storage/yale.cpp +1601 -0
- data/ext/nmatrix/storage/yale.h +208 -0
- data/ext/nmatrix/ttable_helper.rb +126 -0
- data/ext/nmatrix/{yale/smmp1_header.template.c → types.h} +36 -9
- data/ext/nmatrix/util/io.cpp +295 -0
- data/ext/nmatrix/util/io.h +117 -0
- data/ext/nmatrix/util/lapack.h +1175 -0
- data/ext/nmatrix/util/math.cpp +557 -0
- data/ext/nmatrix/util/math.h +1363 -0
- data/ext/nmatrix/util/sl_list.cpp +475 -0
- data/ext/nmatrix/util/sl_list.h +255 -0
- data/ext/nmatrix/util/util.h +78 -0
- data/lib/nmatrix/blas.rb +70 -0
- data/lib/nmatrix/io/mat5_reader.rb +567 -0
- data/lib/nmatrix/io/mat_reader.rb +162 -0
- data/lib/{string.rb → nmatrix/monkeys.rb} +49 -2
- data/lib/nmatrix/nmatrix.rb +199 -0
- data/lib/nmatrix/nvector.rb +103 -0
- data/lib/nmatrix/version.rb +27 -0
- data/lib/nmatrix.rb +22 -230
- data/nmatrix.gemspec +59 -0
- data/scripts/mac-brew-gcc.sh +47 -0
- data/spec/4x4_sparse.mat +0 -0
- data/spec/4x5_dense.mat +0 -0
- data/spec/blas_spec.rb +47 -0
- data/spec/elementwise_spec.rb +164 -0
- data/spec/io_spec.rb +60 -0
- data/spec/lapack_spec.rb +52 -0
- data/spec/math_spec.rb +96 -0
- data/spec/nmatrix_spec.rb +93 -89
- data/spec/nmatrix_yale_spec.rb +52 -36
- data/spec/nvector_spec.rb +1 -1
- data/spec/slice_spec.rb +257 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/utm5940.mtx +83844 -0
- metadata +113 -71
- data/.autotest +0 -23
- data/.gemtest +0 -0
- data/ext/nmatrix/cblas.c +0 -150
- data/ext/nmatrix/dense/blas_header.template.c +0 -52
- data/ext/nmatrix/dense/elementwise.template.c +0 -107
- data/ext/nmatrix/dense/gemm.template.c +0 -159
- data/ext/nmatrix/dense/gemv.template.c +0 -130
- data/ext/nmatrix/dense/rationalmath.template.c +0 -68
- data/ext/nmatrix/dense.c +0 -307
- data/ext/nmatrix/depend +0 -18
- data/ext/nmatrix/generator/syntax_tree.rb +0 -481
- data/ext/nmatrix/generator.rb +0 -594
- data/ext/nmatrix/list.c +0 -774
- data/ext/nmatrix/nmatrix.c +0 -1977
- data/ext/nmatrix/rational.c +0 -98
- data/ext/nmatrix/yale/complexmath.template.c +0 -71
- data/ext/nmatrix/yale/elementwise.template.c +0 -46
- data/ext/nmatrix/yale/elementwise_op.template.c +0 -73
- data/ext/nmatrix/yale/numbmm.template.c +0 -94
- data/ext/nmatrix/yale/smmp1.template.c +0 -21
- data/ext/nmatrix/yale/smmp2.template.c +0 -43
- data/ext/nmatrix/yale/smmp2_header.template.c +0 -46
- data/ext/nmatrix/yale/sort_columns.template.c +0 -56
- data/ext/nmatrix/yale/symbmm.template.c +0 -54
- data/ext/nmatrix/yale/transp.template.c +0 -68
- data/ext/nmatrix/yale.c +0 -726
- data/lib/array.rb +0 -67
- data/spec/syntax_tree_spec.rb +0 -46
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
|
2
|
+
// = NMatrix
|
|
3
|
+
//
|
|
4
|
+
// A linear algebra library for scientific computation in Ruby.
|
|
5
|
+
// NMatrix is part of SciRuby.
|
|
6
|
+
//
|
|
7
|
+
// NMatrix was originally inspired by and derived from NArray, by
|
|
8
|
+
// Masahiro Tanaka: http://narray.rubyforge.org
|
|
9
|
+
//
|
|
10
|
+
// == Copyright Information
|
|
11
|
+
//
|
|
12
|
+
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
|
|
13
|
+
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
|
|
14
|
+
//
|
|
15
|
+
// Please see LICENSE.txt for additional copyright notices.
|
|
16
|
+
//
|
|
17
|
+
// == Contributing
|
|
18
|
+
//
|
|
19
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
|
20
|
+
// our Contributor Agreement:
|
|
21
|
+
//
|
|
22
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
|
23
|
+
//
|
|
24
|
+
// == sl_list.h
|
|
25
|
+
//
|
|
26
|
+
// Singly-linked list implementation used for List Storage.
|
|
27
|
+
|
|
28
|
+
#ifndef SL_LIST_H
|
|
29
|
+
#define SL_LIST_H
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Standard Includes
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
#include <type_traits>
|
|
37
|
+
#include <cstdlib>
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
* Project Includes
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
#include "types.h"
|
|
44
|
+
|
|
45
|
+
#include "data/data.h"
|
|
46
|
+
|
|
47
|
+
#include "nmatrix.h"
|
|
48
|
+
|
|
49
|
+
namespace nm { namespace list {
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* Macros
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
* Types
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* Data
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/*
|
|
65
|
+
* Functions
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
////////////////
|
|
69
|
+
// Lifecycle //
|
|
70
|
+
///////////////
|
|
71
|
+
|
|
72
|
+
LIST* create(void);
|
|
73
|
+
void del(LIST* list, size_t recursions);
|
|
74
|
+
void mark(LIST* list, size_t recursions);
|
|
75
|
+
|
|
76
|
+
///////////////
|
|
77
|
+
// Accessors //
|
|
78
|
+
///////////////
|
|
79
|
+
|
|
80
|
+
NODE* insert(LIST* list, bool replace, size_t key, void* val);
|
|
81
|
+
NODE* insert_with_copy(LIST *list, size_t key, void *val, size_t size);
|
|
82
|
+
NODE* insert_after(NODE* node, size_t key, void* val);
|
|
83
|
+
void* remove(LIST* list, size_t key);
|
|
84
|
+
bool remove_recursive(LIST* list, const size_t* coords, const size_t* offset, size_t r, const size_t& dim, void* rm);
|
|
85
|
+
|
|
86
|
+
template <typename Type>
|
|
87
|
+
inline NODE* insert_helper(LIST* list, NODE* node, size_t key, Type val) {
|
|
88
|
+
Type* val_mem = ALLOC(Type);
|
|
89
|
+
*val_mem = val;
|
|
90
|
+
|
|
91
|
+
if (node == NULL) {
|
|
92
|
+
return insert(list, false, key, val_mem);
|
|
93
|
+
|
|
94
|
+
} else {
|
|
95
|
+
return insert_after(node, key, val_mem);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
template <typename Type>
|
|
100
|
+
inline NODE* insert_helper(LIST* list, NODE* node, size_t key, Type* ptr) {
|
|
101
|
+
if (node == NULL) {
|
|
102
|
+
return insert(list, false, key, ptr);
|
|
103
|
+
|
|
104
|
+
} else {
|
|
105
|
+
return insert_after(node, key, ptr);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
///////////
|
|
110
|
+
// Tests //
|
|
111
|
+
///////////
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* Do all values in a list == some value?
|
|
115
|
+
*
|
|
116
|
+
* Note that the template parameters should line up with the first two function parameters. This differs from most
|
|
117
|
+
* other eqeq functions, which use left and right dtypes.
|
|
118
|
+
*/
|
|
119
|
+
template <typename ListDType, typename ValueDType>
|
|
120
|
+
bool eqeq_value(const LIST* l, const ValueDType* v, size_t recursions, size_t& checked) {
|
|
121
|
+
NODE *next, *curr = l->first;
|
|
122
|
+
|
|
123
|
+
while (curr) {
|
|
124
|
+
next = curr->next;
|
|
125
|
+
|
|
126
|
+
if (recursions == 0) {
|
|
127
|
+
++checked;
|
|
128
|
+
|
|
129
|
+
if (*reinterpret_cast<ListDType*>(curr->val) != *v) return false;
|
|
130
|
+
|
|
131
|
+
} else if (!eqeq_value<ListDType,ValueDType>((LIST*)curr->val, v, recursions - 1, checked)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
curr = next;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
* Are all values in the two lists equal? If one is missing a value, but the
|
|
144
|
+
* other isn't, does the value in the list match the default value?
|
|
145
|
+
*/
|
|
146
|
+
template <typename LDType, typename RDType>
|
|
147
|
+
bool eqeq(const LIST* left, const LIST* right, const LDType* left_val, const RDType* right_val, size_t recursions, size_t& checked) {
|
|
148
|
+
NODE *lnext = NULL, *lcurr = left->first, *rnext = NULL, *rcurr = right->first;
|
|
149
|
+
|
|
150
|
+
if (lcurr) lnext = lcurr->next;
|
|
151
|
+
if (rcurr) rnext = rcurr->next;
|
|
152
|
+
|
|
153
|
+
while (lcurr && rcurr) {
|
|
154
|
+
|
|
155
|
+
if (lcurr->key == rcurr->key) {
|
|
156
|
+
// MATCHING KEYS
|
|
157
|
+
|
|
158
|
+
if (recursions == 0) {
|
|
159
|
+
++checked;
|
|
160
|
+
|
|
161
|
+
if (*reinterpret_cast<LDType*>(lcurr->val) != *reinterpret_cast<RDType*>(rcurr->val)) return false;
|
|
162
|
+
|
|
163
|
+
} else if (!eqeq<LDType,RDType>(reinterpret_cast<LIST*>(lcurr->val), (LIST*)rcurr->val, left_val, right_val, recursions - 1, checked)) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// increment both iterators
|
|
168
|
+
rcurr = rnext;
|
|
169
|
+
if (rcurr) rnext = rcurr->next;
|
|
170
|
+
lcurr = lnext;
|
|
171
|
+
if (lcurr) lnext = lcurr->next;
|
|
172
|
+
|
|
173
|
+
} else if (lcurr->key < rcurr->key) {
|
|
174
|
+
// NON-MATCHING KEYS
|
|
175
|
+
|
|
176
|
+
if (recursions == 0) {
|
|
177
|
+
// compare left entry to right default value
|
|
178
|
+
++checked;
|
|
179
|
+
|
|
180
|
+
if (*reinterpret_cast<LDType*>(lcurr->val) != *right_val) return false;
|
|
181
|
+
|
|
182
|
+
} else if (!eqeq_value<LDType,RDType>(reinterpret_cast<LIST*>(lcurr->val), right_val, recursions - 1, checked)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// increment left iterator
|
|
187
|
+
lcurr = lnext;
|
|
188
|
+
if (lcurr) lnext = lcurr->next;
|
|
189
|
+
|
|
190
|
+
} else {
|
|
191
|
+
// if (rcurr->key < lcurr->key)
|
|
192
|
+
|
|
193
|
+
if (recursions == 0) {
|
|
194
|
+
// compare right entry to left default value
|
|
195
|
+
++checked;
|
|
196
|
+
|
|
197
|
+
if (*reinterpret_cast<RDType*>(rcurr->val) != *left_val) return false;
|
|
198
|
+
|
|
199
|
+
} else if (!eqeq_value<RDType,LDType>(reinterpret_cast<LIST*>(rcurr->val), left_val, recursions - 1, checked)) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// increment right iterator
|
|
204
|
+
rcurr = rnext;
|
|
205
|
+
if (rcurr) rnext = rcurr->next;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/*
|
|
211
|
+
* One final check, in case we get to the end of one list but not the other
|
|
212
|
+
* one.
|
|
213
|
+
*/
|
|
214
|
+
if (lcurr) {
|
|
215
|
+
// nothing left in right-hand list
|
|
216
|
+
if (*reinterpret_cast<LDType*>(lcurr->val) != *right_val) return false;
|
|
217
|
+
|
|
218
|
+
} else if (rcurr) {
|
|
219
|
+
// nothing left in left-hand list
|
|
220
|
+
if (*reinterpret_cast<RDType*>(rcurr->val) != *left_val) return false;
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/*
|
|
225
|
+
* Nothing different between the two lists -- but make sure after this return
|
|
226
|
+
* that you compare the default values themselves, if we haven't visited
|
|
227
|
+
* every value in the two matrices.
|
|
228
|
+
*/
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/////////////
|
|
233
|
+
// Utility //
|
|
234
|
+
/////////////
|
|
235
|
+
|
|
236
|
+
NODE* find(LIST* list, size_t key);
|
|
237
|
+
NODE* find_preceding_from(NODE* prev, size_t key);
|
|
238
|
+
NODE* find_nearest(LIST* list, size_t key);
|
|
239
|
+
NODE* find_nearest_from(NODE* prev, size_t key);
|
|
240
|
+
|
|
241
|
+
/////////////////////////
|
|
242
|
+
// Copying and Casting //
|
|
243
|
+
/////////////////////////
|
|
244
|
+
|
|
245
|
+
template <typename LDType, typename RDType>
|
|
246
|
+
void cast_copy_contents(LIST* lhs, const LIST* rhs, size_t recursions);
|
|
247
|
+
|
|
248
|
+
}} // end of namespace nm::list
|
|
249
|
+
|
|
250
|
+
extern "C" {
|
|
251
|
+
void nm_list_cast_copy_contents(LIST* lhs, const LIST* rhs, dtype_t lhs_dtype, dtype_t rhs_dtype, size_t recursions);
|
|
252
|
+
VALUE nm_list_copy_to_hash(const LIST* l, const dtype_t dtype, size_t recursions, VALUE default_value);
|
|
253
|
+
} // end of extern "C" block
|
|
254
|
+
|
|
255
|
+
#endif // SL_LIST_H
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
|
2
|
+
// = NMatrix
|
|
3
|
+
//
|
|
4
|
+
// A linear algebra library for scientific computation in Ruby.
|
|
5
|
+
// NMatrix is part of SciRuby.
|
|
6
|
+
//
|
|
7
|
+
// NMatrix was originally inspired by and derived from NArray, by
|
|
8
|
+
// Masahiro Tanaka: http://narray.rubyforge.org
|
|
9
|
+
//
|
|
10
|
+
// == Copyright Information
|
|
11
|
+
//
|
|
12
|
+
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
|
|
13
|
+
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
|
|
14
|
+
//
|
|
15
|
+
// Please see LICENSE.txt for additional copyright notices.
|
|
16
|
+
//
|
|
17
|
+
// == Contributing
|
|
18
|
+
//
|
|
19
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
|
20
|
+
// our Contributor Agreement:
|
|
21
|
+
//
|
|
22
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
|
23
|
+
//
|
|
24
|
+
// == util.h
|
|
25
|
+
//
|
|
26
|
+
// Header file for utility functions and data.
|
|
27
|
+
|
|
28
|
+
#ifndef UTIL_H
|
|
29
|
+
#define UTIL_H
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* Standard Includes
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Project Includes
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
#include "types.h"
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* Macros
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* Types
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Data
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Functions
|
|
55
|
+
*/
|
|
56
|
+
namespace nm {
|
|
57
|
+
template <typename Type>
|
|
58
|
+
inline Type gcf(Type x, Type y) {
|
|
59
|
+
Type t;
|
|
60
|
+
|
|
61
|
+
if (x < 0) x = -x;
|
|
62
|
+
if (y < 0) y = -y;
|
|
63
|
+
|
|
64
|
+
if (x == 0) return y;
|
|
65
|
+
if (y == 0) return x;
|
|
66
|
+
|
|
67
|
+
while (x > 0) {
|
|
68
|
+
t = x;
|
|
69
|
+
x = y % x;
|
|
70
|
+
y = t;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return y;
|
|
74
|
+
}
|
|
75
|
+
} // end of namespace nm
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
#endif // UTIL_H
|
data/lib/nmatrix/blas.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module NMatrix::BLAS
|
|
2
|
+
|
|
3
|
+
class << self
|
|
4
|
+
|
|
5
|
+
def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, transpose_a = false, transpose_b = false, m = nil, n = nil, k = nil, lda = nil, ldb = nil, ldc = nil)
|
|
6
|
+
raise ArgumentError, 'Expected dense NMatrices as first two arguments.' unless a.is_a?(NMatrix) and b.is_a?(NMatrix) and a.stype == :dense and b.stype == :dense
|
|
7
|
+
raise ArgumentError, 'Expected nil or dense NMatrix as third argument.' unless c.nil? or (c.is_a?(NMatrix) and c.stype == :dense)
|
|
8
|
+
raise ArgumentError, 'NMatrix dtype mismatch.' unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true)
|
|
9
|
+
|
|
10
|
+
# First, set m, n, and k, which depend on whether we're taking the
|
|
11
|
+
# transpose of a and b.
|
|
12
|
+
if c
|
|
13
|
+
m ||= c.shape[0]
|
|
14
|
+
n ||= c.shape[1]
|
|
15
|
+
k ||= transpose_a ? a.shape[0] : a.shape[1]
|
|
16
|
+
|
|
17
|
+
else
|
|
18
|
+
if transpose_a
|
|
19
|
+
# Either :transpose or :complex_conjugate.
|
|
20
|
+
m ||= a.shape[1]
|
|
21
|
+
k ||= a.shape[0]
|
|
22
|
+
|
|
23
|
+
else
|
|
24
|
+
# No transpose.
|
|
25
|
+
m ||= a.shape[0]
|
|
26
|
+
k ||= a.shape[1]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
n ||= transpose_b ? b.shape[0] : b.shape[1]
|
|
30
|
+
c = NMatrix.new([m, n], a.dtype)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# I think these are independent of whether or not a transpose occurs.
|
|
34
|
+
lda ||= a.shape[1]
|
|
35
|
+
ldb ||= b.shape[1]
|
|
36
|
+
ldc ||= c.shape[1]
|
|
37
|
+
|
|
38
|
+
# NM_COMPLEX64 and NM_COMPLEX128 both require complex alpha and beta.
|
|
39
|
+
if a.dtype == :complex64 or a.dtype == :complex128
|
|
40
|
+
alpha = Complex.new(1.0, 0.0) if alpha == 1.0
|
|
41
|
+
beta = Complex.new(0.0, 0.0) if beta == 0.0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# For argument descriptions, see: http://www.netlib.org/blas/dgemm.f
|
|
45
|
+
::NMatrix::BLAS.cblas_gemm(:row, transpose_a, transpose_b, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
|
|
46
|
+
|
|
47
|
+
return c
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, transpose_a = false, m = nil, n = nil, lda = nil, incx = nil, incy = nil)
|
|
51
|
+
m ||= transpose_a ? a.shape[1] : a.shape[0]
|
|
52
|
+
n ||= transpose_a ? a.shape[0] : a.shape[1]
|
|
53
|
+
|
|
54
|
+
lda ||= a.shape[1]
|
|
55
|
+
incx ||= 1
|
|
56
|
+
incy ||= 1
|
|
57
|
+
|
|
58
|
+
# NM_COMPLEX64 and NM_COMPLEX128 both require complex alpha and beta.
|
|
59
|
+
if a.dtype == :complex64 or a.dtype == :complex128
|
|
60
|
+
alpha = Complex.new(1.0, 0.0) if alpha == 1.0
|
|
61
|
+
beta = Complex.new(0.0, 0.0) if beta == 0.0
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
::NMatrix::BLAS.cblas_gemv(transpose_a, m, n, alpha, a, lda, x, incx, beta, y, incy)
|
|
65
|
+
|
|
66
|
+
return y
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|