nmatrix 0.0.1

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 (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
+