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,71 @@
1
+
2
+ inline static %%TYPE%% BOOL2%%= dtype.id.to_s.upcase%%(bool expr) {
3
+ %%TYPE%% result;
4
+ result.r = expr;
5
+ result.i = 0;
6
+ return result;
7
+ }
8
+
9
+
10
+
11
+ inline static %%TYPE%% %%TYPE_ABBREV%%_mul(double ar, double ai, double br, double bi) {
12
+ %%TYPE%% result;
13
+
14
+ result.r = ar * br - ai * bi;
15
+ result.i = ar * bi + br * ai;
16
+
17
+ return result;
18
+ }
19
+
20
+
21
+ inline static %%TYPE%% %%TYPE_ABBREV%%_div(double ar, double ai, double br, double bi) {
22
+ %%TYPE%% result;
23
+ double denom = br * br + bi * bi;
24
+
25
+ result.r = (ar * br + ai * bi) / denom;
26
+ result.i = (ai * br - ar * bi) / denom;
27
+
28
+ return result;
29
+ }
30
+
31
+
32
+ inline static %%TYPE%% %%TYPE_ABBREV%%_add(%%= dtype.sym == :complex128 ? "double ar, double ai, double br, double bi" : "float ar, float ai, float br, float bi"%%) {
33
+ %%TYPE%% result;
34
+
35
+ result.r = ar + br;
36
+ result.i = ai + bi;
37
+
38
+ return result;
39
+ }
40
+
41
+
42
+ inline static %%TYPE%% %%TYPE_ABBREV%%_sub(%%= dtype.sym == :complex128 ? "double ar, double ai, double br, double bi" : "float ar, float ai, float br, float bi"%%) {
43
+ %%TYPE%% result;
44
+
45
+ result.r = ar - br;
46
+ result.i = ai - bi;
47
+
48
+ return result;
49
+ }
50
+
51
+
52
+ inline static %%TYPE%% %%TYPE_ABBREV%%_mod(%%= dtype.sym == :complex128 ? "double ar, double ai, double br, double bi" : "float ar, float ai, float br, float bi"%%) {
53
+ %%TYPE%% result;
54
+ rb_raise(rb_eNotImpError, "modulo arithmetic for complex numbers not yet implemented");
55
+
56
+ return result;
57
+ }
58
+
59
+
60
+ inline static %%TYPE%% %%TYPE_ABBREV%%_bang(%%= dtype.sym == :complex128 ? "double ar, double ai" : "float ar, float ai"%%) {
61
+ %%TYPE%% result = {!ar, 0};
62
+ return result;
63
+ }
64
+
65
+ inline static %%TYPE%% %%TYPE_ABBREV%%_negate(%%= dtype.sym == :complex128 ? "double ar, double ai" : "float ar, float ai"%%) {
66
+ %%TYPE%% result;
67
+ result.r = -ar;
68
+ result.i = -ai;
69
+ return result;
70
+ }
71
+
@@ -0,0 +1,46 @@
1
+
2
+ int %%INT_ABBREV%%_%%TYPE_ABBREV%%_ew(y_size_t n, y_size_t m, enum NMatrix_Ops op, const u_%%INT%%* ija, const u_%%INT%%* ijb, const u_%%INT%%* ijc, %%TYPE%%* a, %%TYPE%%* b, %%TYPE%%* c)
3
+ {
4
+ y_size_t i;
5
+ y_size_t c_jj, a_jj, b_jj;
6
+ %%TYPE%% left, right;
7
+
8
+ for (i = 0; i < n; ++i) {
9
+ // do operation on diagonals first:
10
+ if (i < m) {
11
+ if (b) %%TYPE_ABBREV%%_ew_op_binary(op, &(c[i]), a[i], b[i]);
12
+ else %%TYPE_ABBREV%%_ew_op_unary(op, &(c[i]), a[i]);
13
+ }
14
+
15
+ c_jj = ijc[i];
16
+ a_jj = ija[i];
17
+ if (ijb) b_jj = ijb[i];
18
+
19
+ //fprintf(stderr, "i16_f64_ew: n=%d, i=%d, c_jj=%d\n", (int)(n), (int)(i), (int)(c_jj));
20
+ while (c_jj < ijc[i+1]) {
21
+ // one or the other has to be the correct column (j = ijc[c_jj] ==? ija[a_jj])
22
+ if (a_jj < ija[i+1] && ija[a_jj] == ijc[c_jj]) {
23
+ %%TYPE left = a[a_jj]%%
24
+ ++a_jj;
25
+ } else {
26
+ %%TYPE left = 0%%
27
+ }
28
+
29
+ if (b) { // some ops don't have a second vector
30
+ if (b_jj < ijb[i+1] && ijb[b_jj] == ijc[c_jj]) {
31
+ %%TYPE right = b[b_jj]%%
32
+ ++b_jj;
33
+ } else {
34
+ %%TYPE right = 0%%
35
+ }
36
+
37
+ %%TYPE_ABBREV%%_ew_op_binary(op, &(c[c_jj]), left, right);
38
+ } else {
39
+ %%TYPE_ABBREV%%_ew_op_unary(op, &(c[c_jj]), left);
40
+ }
41
+
42
+ ++c_jj;
43
+ }
44
+ }
45
+ return 0;
46
+ }
@@ -0,0 +1,73 @@
1
+
2
+ static inline void %%TYPE_ABBREV%%_ew_op_unary(enum NMatrix_Ops op, %%TYPE%%* result, %%TYPE%% left) {
3
+ switch(op) {
4
+ case '!':
5
+ %%TYPE *result = !left%%
6
+ break;
7
+ case NM_OP_NEG:
8
+ %%TYPE *result = -left%%
9
+ break;
10
+ case '~':
11
+ %%TYPE *result = ~left%%
12
+ break;
13
+ default:
14
+ rb_raise(rb_eNotImpError, "Unrecognized element-wise unary operator");
15
+ }
16
+ }
17
+
18
+
19
+
20
+ static inline void %%TYPE_ABBREV%%_ew_op_binary(enum NMatrix_Ops op, %%TYPE%%* result, %%TYPE%% left, %%TYPE%% right) {
21
+ switch(op) {
22
+ case '+':
23
+ %%TYPE *result = left + right%%
24
+ break;
25
+ case '-':
26
+ %%TYPE *result = left - right%%
27
+ break;
28
+ case '*':
29
+ %%TYPE *result = left * right%%
30
+ break;
31
+ case '/':
32
+ %%TYPE *result = left / right%%
33
+ break;
34
+ case '%':
35
+ %%TYPE *result = left % right%%
36
+ break;
37
+ case NM_OP_EQEQ:
38
+ %%TYPE *result = left == right%%
39
+ break;
40
+ case NM_OP_NEQ:
41
+ %%TYPE *result = left != right%%
42
+ break;
43
+ case '>':
44
+ %%TYPE *result = left > right%%
45
+ break;
46
+ case '<':
47
+ %%TYPE *result = left < right%%
48
+ break;
49
+ case NM_OP_GTE:
50
+ %%TYPE *result = left >= right%%
51
+ break;
52
+ case NM_OP_LTE:
53
+ %%TYPE *result = left <= right%%
54
+ break;
55
+ case '&':
56
+ %%TYPE *result = left & right%%
57
+ break;
58
+ case '|':
59
+ %%TYPE *result = left | right%%
60
+ break;
61
+ case '^':
62
+ %%TYPE *result = left ^ right%%
63
+ break;
64
+ case NM_OP_LSH:
65
+ %%TYPE *result = left << right%%
66
+ break;
67
+ case NM_OP_RSH:
68
+ %%TYPE *result = left >> right%%
69
+ break;
70
+ default:
71
+ rb_raise(rb_eNotImpError, "Unrecognized element-wise binary operator");
72
+ }
73
+ }
@@ -0,0 +1,94 @@
1
+ // numeric matrix multiply c=a*b
2
+ void %%INT_ABBREV%%_%%TYPE_ABBREV%%_numbmm_(y_size_t n, y_size_t m, YALE_PARAM A, YALE_PARAM B, YALE_PARAM C)
3
+ {
4
+ u_%%INT%% next[m];
5
+ %%TYPE%% sums[m];
6
+
7
+ %%TYPE%% v;
8
+ %%= if [:rational,:complex,:value].include?(dtype.type); "#{dtype.long_dtype.sizeof} temp1;"; end%%
9
+
10
+ u_%%INT%% head, length, temp, ndnz = 0;
11
+ u_%%INT%% jj_start, jj_end, kk_start, kk_end;
12
+ u_%%INT%% i, j, k, kk, jj;
13
+ u_%%INT%% minmn = SMMP_MIN(m,n);
14
+
15
+ u_%%INT%% *ia = (u_%%INT%%*)(A.ia),
16
+ *ja = (u_%%INT%%*)(A.ja),
17
+ *ib = (u_%%INT%%*)(B.ia),
18
+ *jb = (u_%%INT%%*)(B.ja),
19
+ *ic = (u_%%INT%%*)(C.ia),
20
+ *jc = (u_%%INT%%*)(C.ja);
21
+ %%TYPE%% *a = A.a,
22
+ *b = B.a,
23
+ *c = C.a;
24
+
25
+ for (i = 0; i < m; ++i) { // initialize scratch arrays
26
+ next[i] = U%%INT_MAX%%;
27
+ %%TYPE sums[i] = 0%%
28
+ }
29
+
30
+ for (i = 0; i < n; ++i) { // walk down the rows
31
+ head = U%%INT_MAX%%-1; // head gets assigned as whichever column of B's row j we last visited
32
+ length = 0;
33
+
34
+ jj_start = ia[i];
35
+ jj_end = ia[i+1];
36
+
37
+ for (jj = jj_start; jj <= jj_end; ++jj) { // walk through entries in each row
38
+
39
+ if (jj == jj_end) { // if we're in the last entry for this row:
40
+ if (!A.diag || i >= minmn) continue;
41
+ j = i; // if it's a new Yale matrix, and last entry, get the diagonal position (j) and entry (ajj)
42
+ %%TYPE v = a[i]%%
43
+ } else {
44
+ j = ja[jj]; // if it's not the last entry for this row, get the column (j) and entry (ajj)
45
+ %%TYPE v = a[jj]%%
46
+ }
47
+
48
+ kk_start = ib[j]; // Find the first entry of row j of matrix B
49
+ kk_end = ib[j+1];
50
+ for (kk = kk_start; kk <= kk_end; ++kk) {
51
+
52
+ if (kk == kk_end) { // Get the column id for that entry
53
+ if (!B.diag || j >= minmn) continue;
54
+ k = j;
55
+ %%TYPE sums[k] += v*b[k]%%
56
+ } else {
57
+ k = jb[kk];
58
+ %%TYPE sums[k] += v*b[kk]%%
59
+ }
60
+
61
+ if (next[k] == U%%INT_MAX%%) {
62
+ next[k] = head;
63
+ head = k;
64
+ ++length;
65
+ }
66
+ }
67
+ }
68
+
69
+ for (jj = 0; jj < length; ++jj) {
70
+ if (%%TYPE sums[head] != 0%%) {
71
+ if (C.diag && head == i) {
72
+ %%TYPE c[head] = sums[head]%%
73
+ } else {
74
+ jc[n+1+ndnz] = head;
75
+ %%TYPE c[n+1+ndnz] = sums[head]%%
76
+ ++ndnz;
77
+ }
78
+ }
79
+
80
+ temp = head;
81
+ head = next[head];
82
+
83
+ next[temp] = U%%INT_MAX%%;
84
+ %%TYPE sums[temp] = 0%%
85
+ }
86
+
87
+ ic[i+1] = n+1+ndnz;
88
+ }
89
+ } /* numbmm_ */
90
+
91
+
92
+
93
+
94
+
@@ -0,0 +1,21 @@
1
+
2
+ void %%TYPE_ABBREV%%_symbmm(y_size_t n, y_size_t m, YALE_PARAM A, YALE_PARAM B, YALE_PARAM C)
3
+ {
4
+ if (A.diag && A.ia != A.ja) {
5
+ fprintf(stderr, "A.diag=true, but ia!=ja. For new yale, ia must equal ja.");
6
+ return;
7
+ }
8
+
9
+ if (B.diag && B.ia != B.ja) {
10
+ fprintf(stderr, "B.diag=true, but ia!=ja. For new yale, ia must equal ja.");
11
+ return;
12
+ }
13
+
14
+ if (C.diag && C.ia != C.ja) {
15
+ fprintf(stderr, "C.diag=true, but ia!=ja. For new yale, ia must equal ja.");
16
+ return;
17
+ }
18
+
19
+
20
+ %%TYPE_ABBREV%%_symbmm_(n, m, A, B, C);
21
+ }
@@ -0,0 +1,38 @@
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
+ // == smmp1.c
25
+ //
26
+ // smmp1.c is automatically generated by generator.rb. Do not modify
27
+ // it directly!
28
+ //
29
+ // This file ensures that all SMMP functions have the same signature,
30
+ // so we can call them using arrays of function pointers.
31
+
32
+ #include "nmatrix.h"
33
+
34
+ #include <stdlib.h>
35
+ #include <stdio.h>
36
+
37
+
38
+
@@ -0,0 +1,43 @@
1
+
2
+ void %%INT_ABBREV%%_%%TYPE_ABBREV%%_numbmm(y_size_t n, y_size_t m, YALE_PARAM A, YALE_PARAM B, YALE_PARAM C)
3
+ {
4
+ if (A.diag && A.ia != A.ja) {
5
+ fprintf(stderr, "A.diag=true, but ia!=ja. For new yale, ia must equal ja.");
6
+ return;
7
+ }
8
+
9
+ if (B.diag && B.ia != B.ja) {
10
+ fprintf(stderr, "B.diag=true, but ia!=ja. For new yale, ia must equal ja.");
11
+ return;
12
+ }
13
+
14
+ if (C.diag && C.ia != C.ja) {
15
+ fprintf(stderr, "C.diag=true, but ia!=ja. For new yale, ia must equal ja.");
16
+ return;
17
+ }
18
+
19
+ %%INT_ABBREV%%_%%TYPE_ABBREV%%_numbmm_(n, m, A, B, C);
20
+ }
21
+
22
+ // Perform both the symbolic and numeric steps together.
23
+ void %%INT_ABBREV%%_%%TYPE_ABBREV%%_smmp(y_size_t n, y_size_t m, YALE_PARAM A, YALE_PARAM B, YALE_PARAM C)
24
+ {
25
+ if (A.diag && A.ia != A.ja) {
26
+ fprintf(stderr, "A.diag=true, but ia!=ja. For new yale, ia must equal ja.");
27
+ return;
28
+ }
29
+
30
+ if (B.diag && B.ia != B.ja) {
31
+ fprintf(stderr, "B.diag=true, but ia!=ja. For new yale, ia must equal ja.");
32
+ return;
33
+ }
34
+
35
+ if (C.diag && C.ia != C.ja) {
36
+ fprintf(stderr, "C.diag=true, but ia!=ja. For new yale, ia must equal ja.");
37
+ return;
38
+ }
39
+
40
+ %%INT_ABBREV%%_symbmm_(n, m, A, B, C);
41
+ %%INT_ABBREV%%_%%TYPE_ABBREV%%_numbmm_(n, m, A, B, C);
42
+ %%INT_ABBREV%%_%%TYPE_ABBREV%%_smmp_sort_columns_(n, C);
43
+ }
@@ -0,0 +1,46 @@
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
+ // == smmp2.c
25
+ //
26
+ /* ======================================================================= *
27
+ * Sparse Matrix Multiplication Package *
28
+ * Randolph E. Bank and Craig C. Douglas *
29
+ * na.bank@na-net.ornl.gov and na.cdouglas@na-net.ornl.gov *
30
+ * ======================================================================= */
31
+ // This was originally derived from the above paper, but the algorithm they
32
+ // give, in Fortran, uses 1-based indexing, and I simply could not make it
33
+ // work. So I went back to where I found the link to that paper -- SciPy's
34
+ // CSR type -- and looked at what they had done:
35
+ //
36
+ // https://github.com/scipy/scipy/blob/master/scipy/sparse/sparsetools/csr.h
37
+ //
38
+ // However, the SciPy version does not use the "new Yale" format, but rather
39
+ // "old Yale." Thus, some modification was necessary -- reincorporating some
40
+ // stuff from the original Bank & Douglas paper.
41
+ //
42
+ //
43
+ // DO NOT MODIFY smmp2.c DIRECTLY, as it is autogenerated by generator.rb.
44
+
45
+ #include <stdio.h>
46
+ #include "nmatrix.h"
@@ -0,0 +1,56 @@
1
+ //TODO: More efficient sorting algorithm than selection sort would be nice, probably.
2
+ // Remember, we're dealing with unique keys, which simplifies things.
3
+ // Doesn't have to be in-place, since we probably just multiplied and that wasn't in-place.
4
+
5
+ void %%INT_ABBREV%%_%%TYPE_ABBREV%%_smmp_sort_columns_(y_size_t n, YALE_PARAM A)
6
+ {
7
+ u_%%INT%% i, jj, jj_start, jj_end, min, min_jj;
8
+ %%TYPE%% temp_val;
9
+
10
+ u_%%INT%% *ia = (u_%%INT%%*)(A.ia),
11
+ *ja = (u_%%INT%%*)(A.ja);
12
+ %%TYPE%% *a = (%%TYPE%%*)(A.a);
13
+
14
+ for (i = 0; i < n; ++i) {
15
+ // No need to sort if there are 0 or 1 entries in the row
16
+ if (ia[i+1] - ia[i] < 2) continue;
17
+
18
+ jj_end = ia[i+1];
19
+ for (jj_start = ia[i]; jj_start < jj_end; ++jj_start) {
20
+
21
+ // If the previous min is just current-1, this key/value pair is already in sorted order.
22
+ // This follows from the unique condition on our column keys.
23
+ if (jj_start > ia[i] && min+1 == ja[jj_start]) {
24
+ min = ja[jj_start];
25
+ continue;
26
+ }
27
+
28
+ // find the minimum key (column index) between jj_start and jj_end
29
+ min = ja[jj_start];
30
+ min_jj = jj_start;
31
+ for (jj = jj_start+1; jj < jj_end; ++jj) {
32
+ if (ja[jj] < min) {
33
+ min_jj = jj;
34
+ min = ja[jj];
35
+ }
36
+ }
37
+
38
+ // if min is already first, skip this iteration
39
+ if (min_jj == jj_start) continue;
40
+
41
+ for (jj = jj_start; jj < jj_end; ++jj) {
42
+ // swap minimum key/value pair with key/value pair in the first position.
43
+ if (min_jj != jj) {
44
+ // min already = ja[min_jj], so use this as temp_key
45
+ %%TYPE temp_val = a[min_jj]%%
46
+
47
+ ja[min_jj] = ja[jj];
48
+ %%TYPE a[min_jj] = a[jj]%%
49
+
50
+ ja[jj] = min;
51
+ %%TYPE a[jj] = temp_val%%
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }