nmatrix 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.autotest +23 -0
  2. data/.gemtest +0 -0
  3. data/Gemfile +7 -0
  4. data/History.txt +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/Manifest.txt +51 -0
  7. data/README.rdoc +63 -0
  8. data/Rakefile +154 -0
  9. data/ext/nmatrix/cblas.c +150 -0
  10. data/ext/nmatrix/dense.c +307 -0
  11. data/ext/nmatrix/dense/blas_header.template.c +52 -0
  12. data/ext/nmatrix/dense/elementwise.template.c +107 -0
  13. data/ext/nmatrix/dense/gemm.template.c +159 -0
  14. data/ext/nmatrix/dense/gemv.template.c +130 -0
  15. data/ext/nmatrix/dense/rationalmath.template.c +68 -0
  16. data/ext/nmatrix/depend +18 -0
  17. data/ext/nmatrix/extconf.rb +143 -0
  18. data/ext/nmatrix/generator.rb +594 -0
  19. data/ext/nmatrix/generator/syntax_tree.rb +481 -0
  20. data/ext/nmatrix/list.c +774 -0
  21. data/ext/nmatrix/nmatrix.c +1977 -0
  22. data/ext/nmatrix/nmatrix.h +912 -0
  23. data/ext/nmatrix/rational.c +98 -0
  24. data/ext/nmatrix/yale.c +726 -0
  25. data/ext/nmatrix/yale/complexmath.template.c +71 -0
  26. data/ext/nmatrix/yale/elementwise.template.c +46 -0
  27. data/ext/nmatrix/yale/elementwise_op.template.c +73 -0
  28. data/ext/nmatrix/yale/numbmm.template.c +94 -0
  29. data/ext/nmatrix/yale/smmp1.template.c +21 -0
  30. data/ext/nmatrix/yale/smmp1_header.template.c +38 -0
  31. data/ext/nmatrix/yale/smmp2.template.c +43 -0
  32. data/ext/nmatrix/yale/smmp2_header.template.c +46 -0
  33. data/ext/nmatrix/yale/sort_columns.template.c +56 -0
  34. data/ext/nmatrix/yale/symbmm.template.c +54 -0
  35. data/ext/nmatrix/yale/transp.template.c +68 -0
  36. data/lib/array.rb +67 -0
  37. data/lib/nmatrix.rb +263 -0
  38. data/lib/string.rb +65 -0
  39. data/spec/nmatrix_spec.rb +395 -0
  40. data/spec/nmatrix_yale_spec.rb +239 -0
  41. data/spec/nvector_spec.rb +43 -0
  42. data/spec/syntax_tree_spec.rb +46 -0
  43. metadata +150 -0
@@ -0,0 +1,159 @@
1
+
2
+ int %%TYPE_ABBREV%%gemm(enum CBLAS_TRANSPOSE TransA, enum CBLAS_TRANSPOSE TransB,
3
+ const int M, const int N, const int K, const %%TYPE%% alpha,
4
+ const %%TYPE%%* A, const int lda,
5
+ const %%TYPE%%* B, const int ldb, const %%TYPE%% beta,
6
+ %%TYPE%%* C, const int ldc)
7
+ {
8
+ int num_rows_a, /*num_cols_a,*/ num_rows_b; // nrowa, ncola, nrowb
9
+
10
+ // use longest possible type for intermediate value storage:
11
+ %%TYPE_LONG%% temp;
12
+ %%= if [:rational,:complex,:value].include?(dtype.type); "#{dtype.long_dtype.sizeof} temp1, temp2;"; end%%
13
+ int i, j, l;
14
+
15
+ if (TransA == CblasNoTrans) num_rows_a = M;
16
+ else num_rows_a = K;
17
+
18
+ if (TransB == CblasNoTrans) num_rows_b = K;
19
+ else num_rows_b = N;
20
+
21
+ // Test the input parameters
22
+ if (TransA < 111 || TransA > 113) {
23
+ fprintf(stderr, "GEMM: TransA must be CblasNoTrans, CblasTrans, or CblasConjTrans\n");
24
+ return 0;
25
+ } else if (TransB < 111 || TransB > 113) {
26
+ fprintf(stderr, "GEMM: TransB must be CblasNoTrans, CblasTrans, or CblasConjTrans\n");
27
+ return 0;
28
+ } else if (M < 0) {
29
+ fprintf(stderr, "GEMM: Expected M >= 0\n");
30
+ return 0;
31
+ } else if (N < 0) {
32
+ fprintf(stderr, "GEMM: Expected N >= 0\n");
33
+ return 0;
34
+ } else if (K < 0) {
35
+ fprintf(stderr, "GEMM: Expected K >= 0\n");
36
+ return 0;
37
+ } else if (lda < NM_MAX(1, num_rows_a)) {
38
+ fprintf(stderr, "GEMM: Expected lda >= max(1, num_rows_a), with num_rows_a = %d; got lda=%d\n", num_rows_a, lda);
39
+ return 0;
40
+ } else if (ldb < NM_MAX(1, num_rows_b)) {
41
+ fprintf(stderr, "GEMM: Expected ldb >= max(1, num_rows_b), with num_rows_b = %d; got ldb=%d\n", num_rows_b, ldb);
42
+ return 0;
43
+ } else if (ldc < NM_MAX(1,M)) {
44
+ fprintf(stderr, "GEMM: Expected ldc >= max(1,M) with M=%d; got ldc=%d\n", M, ldc);
45
+ return 0;
46
+ }
47
+
48
+ // Quick return if possible
49
+ if (!M || !N || (%%TYPE alpha == 0%% || !K) && %%TYPE beta == 1%%) return 0;
50
+
51
+ // For alpha = 0
52
+ if (%%TYPE alpha == 0%%) {
53
+ if (%%TYPE beta == 0%%) {
54
+ for (j = 0; j < N; ++j)
55
+ for (i = 0; i < M; ++i) {
56
+ %%TYPE C[i+j*ldc] = 0%%
57
+ }
58
+ } else {
59
+ for (j = 0; j < N; ++j)
60
+ for (i = 0; i < M; ++i) {
61
+ %%TYPE C[i+j*ldc] *= beta%%
62
+ }
63
+ }
64
+ return 0;
65
+ }
66
+
67
+ // Start the operations
68
+ if (TransB == CblasNoTrans) {
69
+ if (TransA == CblasNoTrans) {
70
+ // C = alpha*A*B+beta*C
71
+ for (j = 0; j < N; ++j) {
72
+ if (%%TYPE beta == 0%%) {
73
+ for (i = 0; i < M; ++i) {
74
+ %%TYPE C[i+j*ldc] = 0%%
75
+ }
76
+ } else if (%%TYPE beta != 1%%) {
77
+ for (i = 0; i < M; ++i) {
78
+ %%TYPE C[i+j*ldc] *= beta%%
79
+ }
80
+ }
81
+
82
+ for (l = 0; l < K; ++l) {
83
+ if (%%TYPE B[l+j*ldb] != 0%%) {
84
+ %%TYPE_LONG temp = alpha * B[l+j*ldb]%%
85
+ for (i = 0; i < M; ++i) {
86
+ %%TYPE C[i+j*ldc] += A[i+l*lda] * temp%%
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ } else {
93
+
94
+ // C = alpha*A**T*B + beta*C
95
+ for (j = 0; j < N; ++j) {
96
+ for (i = 0; i < M; ++i) {
97
+ %%TYPE temp = 0%%
98
+ for (l = 0; l < K; ++l) {
99
+ %%TYPE_LONG temp += A[l+i*lda] * B[l+j*ldb]%%
100
+ }
101
+
102
+ if (%%TYPE beta == 0%%) {
103
+ %%TYPE C[i+j*ldc] = alpha*temp%%
104
+ } else {
105
+ %%TYPE C[i+j*ldc] = alpha*temp + beta*C[i+j*ldc]%%
106
+ }
107
+ }
108
+ }
109
+
110
+ }
111
+
112
+ } else if (TransA == CblasNoTrans) {
113
+
114
+ // C = alpha*A*B**T + beta*C
115
+ for (j = 0; j < N; ++j) {
116
+ if (%%TYPE beta == 0%%) {
117
+ for (i = 0; i < M; ++i) {
118
+ %%TYPE C[i+j*ldc] = 0%%
119
+ }
120
+ } else if (%%TYPE beta != 1%%) {
121
+ for (i = 0; i < M; ++i) {
122
+ %%TYPE C[i+j*ldc] *= beta%%
123
+ }
124
+ }
125
+
126
+ for (l = 0; l < K; ++l) {
127
+ if (%%TYPE B[j+l*ldb] != 0%%) {
128
+ %%TYPE_LONG temp = alpha * B[j+l*ldb]%%
129
+ for (i = 0; i < M; ++i) {
130
+ %%TYPE C[i+j*ldc] += A[i+l*lda] * temp%%
131
+ }
132
+ }
133
+ }
134
+
135
+ }
136
+
137
+ } else {
138
+
139
+ // C = alpha*A**T*B**T + beta*C
140
+ for (j = 0; j < N; ++j) {
141
+ for (i = 0; i < M; ++i) {
142
+ %%TYPE temp = 0%%
143
+ for (l = 0; l < K; ++l) {
144
+ %%TYPE_LONG temp += A[l+i*lda] * B[j+l*ldb]%%
145
+ }
146
+
147
+ if (%%TYPE beta == 0%%) {
148
+ %%TYPE C[i+j*ldc] = alpha*temp%%
149
+ } else {
150
+ %%TYPE C[i+j*ldc] = alpha*temp + beta*C[i+j*ldc]%%
151
+ }
152
+ }
153
+ }
154
+
155
+ }
156
+
157
+ return 0;
158
+ }
159
+
@@ -0,0 +1,130 @@
1
+
2
+ int %%TYPE_ABBREV%%gemv(enum CBLAS_TRANSPOSE Trans, const size_t M, const size_t N, const %%TYPE%% alpha,
3
+ const %%TYPE%%* A, const size_t lda, const %%TYPE%%* X, const int incX, const %%TYPE%% beta, %%TYPE%%* Y, const int incY)
4
+ {
5
+ size_t lenX, lenY, i, j;
6
+ int kx, ky, iy, jx, jy, ix;
7
+ %%TYPE_LONG%% temp;
8
+ %%= if [:rational,:complex,:value].include?(dtype.type); "#{dtype.long_dtype.sizeof} temp1;"; end%%
9
+
10
+ // Test the input parameters
11
+ if (Trans < 111 || Trans > 113) {
12
+ fprintf(stderr, "IGEMV: TransA must be CblasNoTrans, CblasTrans, or CblasConjTrans\n");
13
+ return 0;
14
+ } else if (lda < NM_MAX(1, N)) {
15
+ fprintf(stderr, "IGEMV: Expected lda >= max(1, N), with N = %d; got lda=%d\n", N, lda);
16
+ return 0;
17
+ } else if (incX == 0) {
18
+ fprintf(stderr, "IGEMV: Expected incX != 0\n");
19
+ return 0;
20
+ } else if (incY == 0) {
21
+ fprintf(stderr, "IGEMV: Expected incY != 0\n");
22
+ return 0;
23
+ }
24
+
25
+ // Quick return if possible
26
+ if (!M || !N || %%TYPE alpha == 0%% && %%TYPE beta == 1%%) return 0;
27
+
28
+ if (Trans == CblasNoTrans) {
29
+ lenX = N;
30
+ lenY = M;
31
+ } else {
32
+ lenX = M;
33
+ lenY = N;
34
+ }
35
+
36
+ if (incX > 0) kx = 0;
37
+ else kx = (lenX - 1) * -incX;
38
+
39
+ if (incY > 0) ky = 0;
40
+ else ky = (lenY - 1) * -incY;
41
+
42
+ // Start the operations. In this version, the elements of A are accessed sequentially with one pass through A.
43
+ if (%%TYPE beta != 1%%) {
44
+ if (incY == 1) {
45
+ if (%%TYPE beta == 0%%) {
46
+ for (i = 0; i < lenY; ++i) {
47
+ %%TYPE Y[i] = 0%%
48
+ }
49
+ } else {
50
+ for (i = 0; i < lenY; ++i) {
51
+ %%TYPE Y[i] *= beta%%
52
+ }
53
+ }
54
+ } else {
55
+ iy = ky;
56
+ if (%%TYPE beta == 0%%) {
57
+ for (i = 0; i < lenY; ++i) {
58
+ %%TYPE Y[iy] = 0%%
59
+ iy += incY;
60
+ }
61
+ } else {
62
+ for (i = 0; i < lenY; ++i) {
63
+ %%TYPE Y[iy] *= beta%%
64
+ iy += incY;
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ if (%%TYPE alpha == 0%%) return 0;
71
+
72
+ if (Trans == CblasNoTrans) {
73
+
74
+ // Form y := alpha*A*x + y.
75
+ jx = kx;
76
+ if (incY == 1) {
77
+ for (j = 0; j < N; ++j) {
78
+ if (%%TYPE X[jx] != 0%%) {
79
+ %%TYPE_LONG temp = alpha * X[jx]%%
80
+ for (i = 0; i < M; ++i) {
81
+ %%TYPE Y[i] += A[j+i*lda] * temp%%
82
+ }
83
+ }
84
+ jx += incX;
85
+ }
86
+ } else {
87
+ for (j = 0; j < N; ++j) {
88
+ if (%%TYPE X[jx] != 0%%) {
89
+ %%TYPE_LONG temp = alpha * X[jx]%%
90
+ iy = ky;
91
+ for (i = 0; i < M; ++i) {
92
+ %%TYPE Y[iy] += A[j+i*lda] * temp%%
93
+ iy += incY;
94
+ }
95
+ }
96
+ jx += incX;
97
+ }
98
+ }
99
+
100
+ } else { // TODO: Check that indices are correct! They're switched for C.
101
+
102
+ // Form y := alpha*A**T*x + y.
103
+ jy = ky;
104
+
105
+ if (incX == 1) {
106
+ for (j = 0; j < N; ++j) {
107
+ %%TYPE temp = 0%%
108
+ for (i = 0; i < M; ++i) {
109
+ %%TYPE_LONG temp += A[j+i*lda]*X[j]%%
110
+ }
111
+ %%TYPE Y[jy] += alpha * temp%%
112
+ jy += incY;
113
+ }
114
+ } else {
115
+ for (j = 0; j < N; ++j) {
116
+ %%TYPE temp = 0%%
117
+ ix = kx;
118
+ for (i = 0; i < M; ++i) {
119
+ %%TYPE_LONG temp += A[j+i*lda] * X[ix]%%
120
+ ix += incX;
121
+ }
122
+
123
+ %%TYPE Y[jy] += alpha * temp%%
124
+ jy += incY;
125
+ }
126
+ }
127
+ }
128
+
129
+ return 0;
130
+ } // end of GEMV
@@ -0,0 +1,68 @@
1
+
2
+ inline %%TYPE%% BOOL2%%= dtype.id.to_s.upcase%%(bool expr) {
3
+ %%TYPE%% result;
4
+ result.n = expr;
5
+ result.d = 1;
6
+ return result;
7
+ }
8
+
9
+ inline %%TYPE%% %%TYPE_ABBREV%%_bang(%%= dtype.sym == :rational128 ? "int64_t n, int64_t d" : (dtype.sym == :rational64 ? "int32_t n, int32_t d" : "int16_t n, int16_t d")%%)
10
+ {
11
+ %%TYPE%% result = {!n, 1};
12
+ return result;
13
+ }
14
+
15
+ inline %%TYPE%% %%TYPE_ABBREV%%_negate(%%= dtype.sym == :rational128 ? "int64_t n, int64_t d" : (dtype.sym == :rational64 ? "int32_t n, int32_t d" : "int16_t n, int16_t d")%%)
16
+ {
17
+ %%TYPE%% result = {-n, -d};
18
+ return result;
19
+ }
20
+
21
+ inline %%TYPE%% %%TYPE_ABBREV%%_muldiv(int64_t anum, int64_t aden, int64_t bnum, int64_t bden, char k) {
22
+ %%TYPE%% result;
23
+ int64_t t, g1, g2;
24
+
25
+ if (k == '/') { // Switch numerator and denominator for division (and move sign)
26
+ if (bnum < 0) {
27
+ anum = -anum;
28
+ bnum = -bnum;
29
+ }
30
+ t = bnum;
31
+ bnum = bden;
32
+ bden = t;
33
+ }
34
+
35
+ g1 = nmrb_gcd(anum, bden);
36
+ g2 = nmrb_gcd(aden, bnum);
37
+
38
+ result.n = (anum / g1) * (bnum / g2);
39
+ result.d = (aden / g2) * (bden / g1);
40
+
41
+ return result;
42
+ }
43
+
44
+ inline %%TYPE%% %%TYPE_ABBREV%%_addsub(int64_t anum, int64_t aden, int64_t bnum, int64_t bden, char k) {
45
+ %%TYPE%% result;
46
+
47
+ int64_t ig = nmrb_gcd(aden, bden);
48
+ int64_t a = anum * (bden / ig);
49
+ int64_t b = bnum * (aden / ig);
50
+ int64_t c;
51
+
52
+ if (k == '+') c=a+b;
53
+ else c=a-b;
54
+
55
+ b = aden / ig;
56
+ ig = nmrb_gcd(aden, ig);
57
+ result.n = c / ig;
58
+ a = bden / ig;
59
+ result.d = a*b;
60
+
61
+ return result;
62
+ }
63
+
64
+ inline %%TYPE%% %%TYPE_ABBREV%%_mod(%%= dtype.sym == :rational128 ? "int64_t anum, int64_t aden, int64_t bnum, int64_t bden" : (dtype.sym == :rational64 ? "int32_t anum, int32_t aden, int32_t bnum, int32_t bden" : "int16_t anum, int16_t aden, int16_t bnum, int16_t bden")%%)
65
+ {
66
+ // a - (b * int(a/b))
67
+ return %%TYPE_ABBREV%%_addsub(anum, aden, bnum*((int64_t)((anum * bden) / (aden * bnum))), bden, '-');
68
+ }
@@ -0,0 +1,18 @@
1
+ dtypes.h dtypes.c smmp1.c smmp2.c blas.c: generator.rb
2
+ $(RUBY) -I$(srcdir) $(srcdir)/generator.rb
3
+
4
+ blas.o: blas.c
5
+
6
+ smmp2.o: smmp1.c smmp2.c nmatrix.h yale/smmp2_header.template.c yale/symbmm.template.c yale/transp.template.c yale/numbmm.template.c
7
+
8
+ smmp1.o: smmp1.c nmatrix_config.h nmatrix.h yale/smmp1_header.template.c
9
+
10
+ dfuncs.o: dfuncs.c $(hdrdir)/ruby.h
11
+
12
+ $(DLLIB): dtypes.h dtypes.c dfuncs.c $(OBJS) Makefile
13
+ # $(ECHO) linking shared-object $(DLLIB)
14
+ @-$(RM) $(@)
15
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
16
+
17
+ soclean:
18
+ @-$(RM) *.so *.o *.bundle
@@ -0,0 +1,143 @@
1
+ # = NMatrix
2
+ #
3
+ # A linear algebra library for scientific computation in Ruby.
4
+ # NMatrix is part of SciRuby.
5
+ #
6
+ # NMatrix was originally inspired by and derived from NArray, by
7
+ # Masahiro Tanaka: http://narray.rubyforge.org
8
+ #
9
+ # == Copyright Information
10
+ #
11
+ # SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
12
+ # NMatrix is Copyright (c) 2012, Ruby Science Foundation
13
+ #
14
+ # Please see LICENSE.txt for additional copyright notices.
15
+ #
16
+ # == Contributing
17
+ #
18
+ # By contributing source code to SciRuby, you agree to be bound by
19
+ # our Contributor Agreement:
20
+ #
21
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
22
+ #
23
+ # == extconf.rb
24
+ #
25
+ # This file mostly derived from NArray.
26
+
27
+ require "mkmf"
28
+
29
+
30
+ def have_type(type, header=nil)
31
+ printf "checking for %s... ", type
32
+ STDOUT.flush
33
+
34
+ src = <<"SRC"
35
+ #include <ruby.h>
36
+ SRC
37
+
38
+
39
+ src << <<"SRC" unless header.nil?
40
+ #include <#{header}>
41
+ SRC
42
+
43
+ r = try_link(src + <<"SRC")
44
+ int main() { return 0; }
45
+ int t() { #{type} a; return 0; }
46
+ SRC
47
+
48
+ unless r
49
+ print "no\n"
50
+ return false
51
+ end
52
+
53
+ $defs.push(format("-DHAVE_%s", type.upcase))
54
+
55
+ print "yes\n"
56
+
57
+ return true
58
+ end
59
+
60
+ def create_conf_h(file)
61
+ print "creating #{file}\n"
62
+ hfile = open(file, "w")
63
+ for line in $defs
64
+ line =~ /^-D(.*)/
65
+ hfile.printf "#define %s 1\n", $1
66
+ end
67
+ hfile.close
68
+ end
69
+
70
+ if RUBY_VERSION < '1.9'
71
+ raise(NotImplementedError, "Sorry, you need Ruby 1.9!")
72
+ else
73
+ $INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix_config.h', '$(archdir)']]
74
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
75
+ $INSTALLFILES << ['libnmatrix.a', '$(archdir)']
76
+ end
77
+ end
78
+
79
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
80
+ CONFIG["DLDFLAGS"] << " --output-lib libnmatrix.a"
81
+ end
82
+
83
+ $DEBUG = true
84
+ $CFLAGS = ["-Wall ",$CFLAGS].join(" ") #-BENCHMARK for comparing transp
85
+
86
+ srcs = %w(
87
+ nmatrix
88
+ list
89
+ dense
90
+ yale
91
+ dfuncs
92
+ smmp1
93
+ smmp2
94
+ cblas
95
+ blas
96
+ rational
97
+ )
98
+ # add smmp in to get generic transp; remove smmp2 to eliminate funcptr transp
99
+
100
+ header = "stdint.h"
101
+ unless have_header(header)
102
+ header = "sys/types.h"
103
+ unless have_header(header)
104
+ header = nil
105
+ end
106
+ end
107
+
108
+ have_type("u_int8_t", header)
109
+ have_type("uint8_t", header)
110
+ have_type("u_int16_t", header)
111
+ have_type("uint16_t", header)
112
+ have_type("int16_t", header)
113
+ have_type("int32_t", header)
114
+ have_type("u_int32_t", header)
115
+ have_type("uint32_t", header)
116
+ have_type("int64_t", header)
117
+ have_type("u_int64_t", header)
118
+ have_type("uint64_t", header)
119
+
120
+ unless have_type("size_t", header)
121
+ have_type("size_t", "stddef.h")
122
+ end
123
+
124
+ # dir_config("cblas")
125
+ # dir_config("atlas")
126
+
127
+ find_library("cblas", "cblas_dgemm", "/usr/local/lib", "/usr/local/atlas/lib")
128
+ find_library("atlas", "ATL_dgemmNN", "/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib")
129
+ find_header("cblas.h", "/usr/local/include", "/usr/local/atlas/include")
130
+
131
+ have_library("f2c")
132
+ have_header("f2c.h")
133
+
134
+
135
+ $libs += " -lcblas -latlas "
136
+
137
+ $objs = srcs.collect{|i| i+".o" }
138
+
139
+ $CFLAGS += " -O0"
140
+
141
+ create_conf_h("nmatrix_config.h")
142
+ create_makefile("nmatrix")
143
+