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,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
+ }