readme.C 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // (c) Daniel Llorens - 2016
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. // @file readme.C
  7. // @brief Examples used in top-level README.md
  8. // TODO Generate README.md and/or these examples.
  9. #include "ra/operators.H"
  10. #include "ra/io.H"
  11. #include "ra/test.H"
  12. #include <iostream>
  13. using std::cout; using std::endl;
  14. int main()
  15. {
  16. TestRecorder tr(std::cout);
  17. tr.section("dynamic/static shape");
  18. // Dynamic or static array rank. Dynamic or static array shape (all dimensions or none).
  19. {
  20. ra::Big<char> A({2, 3}, 'a'); // dynamic rank = 2, dynamic shape = {2, 3}
  21. ra::Big<char, 2> B({2, 3}, 'b'); // static rank = 2, dynamic shape = {2, 3}
  22. ra::Small<char, 2, 3> C('c'); // static rank = 2, static shape = {2, 3}
  23. cout << "A: " << A << "\n\n";
  24. cout << "B: " << B << "\n\n";
  25. cout << "C: " << C << "\n\n";
  26. }
  27. tr.section("storage");
  28. // Memory-owning types and views. You can make array views over any piece of memory.
  29. {
  30. // memory-owning types
  31. ra::Big<char, 2> A({2, 3}, 'a'); // storage is std::vector inside A
  32. ra::Unique<char, 2> B({2, 3}, 'b'); // storage is owned by std::unique_ptr inside B
  33. ra::Small<char, 2, 3> C('c'); // storage is owned by C itself, on the stack
  34. cout << "A: " << A << "\n\n";
  35. cout << "B: " << B << "\n\n";
  36. cout << "C: " << C << "\n\n";
  37. // view types
  38. char cs[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
  39. ra::View<char, 2> D1({2, 3}, cs); // dynamic sizes and strides, C order
  40. ra::View<char, 2> D2({{2, 1}, {3, 2}}, cs); // dynamic sizes and strides, Fortran order.
  41. ra::SmallView<char, mp::int_list<2, 3>, mp::int_list<3, 1>> D3(cs); // static sizes & strides, C order.
  42. ra::SmallView<char, mp::int_list<2, 3>, mp::int_list<1, 2>> D4(cs); // static sizes & strides, Fortran order.
  43. cout << "D1: " << D1 << "\n\n";
  44. cout << "D2: " << D2 << "\n\n";
  45. cout << "D3: " << D3 << "\n\n";
  46. cout << "D4: " << D4 << "\n\n";
  47. }
  48. tr.section("shape agreement");
  49. // Shape agreement rules and rank extension (broadcasting) for rank-0 operations of any arity
  50. // and operands of any rank, any of which can a reference (so you can write on them). These
  51. // rules are taken from the array language, J.
  52. // (See examples/agreement.C for more examples.)
  53. {
  54. ra::Big<float, 2> A({2, 3}, { 1, 2, 3, 1, 2, 3 });
  55. ra::Big<float, 1> B({-1, +1});
  56. ra::Big<float, 2> C({2, 3}, 99.);
  57. C = A * B; // C(i, j) = A(i, j) * C(i)
  58. cout << "C: " << C << "\n\n";
  59. ra::Big<float, 1> D({2}, 0.);
  60. D += A * B; // D(i) += A(i, j) * C(i)
  61. cout << "D: " << D << "\n\n";
  62. }
  63. tr.section("rank iterators");
  64. // Iterators over cells of arbitrary rank.
  65. {
  66. ra::TensorIndex<0> i;
  67. ra::TensorIndex<1> j;
  68. ra::TensorIndex<2> k;
  69. ra::Big<float, 3> A({2, 3, 4}, i+j+k);
  70. ra::Big<float, 2> B({2, 3}, 0);
  71. cout << "A: " << A << "\n\n";
  72. // store the sum of A(i, j, ...) in B(i, j). All these are equivalent.
  73. B = 0; B += A; // default agreement matches prefixes
  74. for_each([](auto && b, auto && a) { b = ra::sum(a); }, B, A); // default agreement matches prefixes
  75. for_each([](auto && b, auto && a) { b = ra::sum(a); }, B, A.iter<1>()); // give cell rank
  76. for_each([](auto && b, auto && a) { b = ra::sum(a); }, B, A.iter<-2>()); // give frame rank
  77. cout << "B: " << B << "\n\n";
  78. // store the sum of A(i, ...) in B(i, j). The op is re-executed for each j, so don't do it this way.
  79. for_each([](auto && b, auto && a) { b = ra::sum(a); }, B, A.iter<2>()); // give cell rank
  80. cout << "B: " << B << "\n\n";
  81. }
  82. // A rank conjunction (only for static rank and somewhat fragile).
  83. tr.section("rank conjuction");
  84. {
  85. // This is a translation of J: A = (i.3) -"(0 1) i.4, that is: A(i, j) = b(i)-c(j).
  86. ra::Big<float, 2> A = map(ra::wrank<0, 1>(std::minus<float>()), ra::iota(3), ra::iota(4));
  87. cout << "A: " << A << "\n\n";
  88. }
  89. // A proper selection operator with 'beating' of range or scalar subscripts.
  90. // See examples/slicing.C for more examples.
  91. tr.section("selector");
  92. {
  93. // TODO do implicit reshape in constructors?? so I can accept any 1-array and not only an initializer_list.
  94. ra::Big<char, 3> A({2, 2, 2}, {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'});
  95. cout << "A: " << A << "\n\n";
  96. // these are all equivalent to e.g. A(:, 0, :) in Octave.
  97. cout << "A1: " << A(ra::all, 0) << "\n\n";
  98. cout << "A2: " << A(ra::all, 0, ra::all) << "\n\n";
  99. cout << "A3: " << A(ra::all, 0, ra::dots<1>) << "\n\n";
  100. // an inverted range.
  101. cout << "A4: " << A(ra::iota(2, 1, -1)) << "\n\n";
  102. // indices can be arrays of any rank.
  103. ra::Big<int, 2> I({2, 2}, {0, 3, 1, 2});
  104. ra::Big<char, 1> B({4}, {'a', 'b', 'c', 'd'});
  105. cout << "B(I): " << B(I) << "\n\n";
  106. // multiple indexing performs an implicit outer product. this results in a rank
  107. // 4 array X = A(J, 1, J) -> X(i, j, k, l) = A(J(i, j), 1, J(k, l))
  108. ra::Big<int, 2> J({2, 2}, {1, 0, 0, 1});
  109. cout << "A(J, 1, J): " << A(J, 1, J) << "\n\n";
  110. // explicit indices do not result in a View view (= pointer + strides), but the
  111. // resulting expression can still be written on.
  112. B(I) = ra::Big<char, 2>({2, 2}, {'x', 'y', 'z', 'w'});
  113. cout << "B: " << B << endl;
  114. }
  115. // A TensorIndex object as in Blitz++ (with some differences).
  116. tr.section("tensorindex");
  117. {
  118. // as shown above.
  119. }
  120. tr.section("STL compat");
  121. {
  122. ra::Big<char, 1> A = {'x', 'z', 'y'};
  123. std::sort(A.begin(), A.end());
  124. cout << "A: " << A << "\n\n";
  125. ra::Big<float, 2> B({2, 2}, {1, 2, 3, 4});
  126. B += std::vector<float>({10, 20});
  127. cout << "B: " << B << "\n\n";
  128. }
  129. // example from the manual [ma100].
  130. {
  131. ra::Small<int, 3> s {2, 1, 0};
  132. ra::Small<double, 3> z = pick(s, s*s, s+s, sqrt(s));
  133. cout << "z: " << z << endl;
  134. }
  135. // example from the manual [ma101].
  136. {
  137. ra::Big<char, 2> A({2, 5}, "helloworld");
  138. std::cout << format_array(transpose<1, 0>(A), false, "|") << std::endl;
  139. }
  140. {
  141. ra::Big<char const *, 1> A = {"hello", "array", "world"};
  142. std::cout << format_array(A, false, "|") << std::endl;
  143. }
  144. // example from the manual [ma102].
  145. {
  146. // ra::Big<char const *, 1> A({3}, "hello"); // ERROR b/c of pointer constructor
  147. ra::Big<char const *, 1> A({3}, ra::scalar("hello"));
  148. std::cout << format_array(A, false, "|") << std::endl;
  149. }
  150. // example from the manual [ma103].
  151. {
  152. ra::Big<int, 2> A({3, 2}, {1, 2, 3, 4, 5, 6});
  153. ra::Big<int, 2> B({2, 3}, {7, 8, 9, 10, 11, 12});
  154. ra::Big<int, 2> C({3, 3}, 0.);
  155. for_each(ra::wrank<1, 1, 2>(ra::wrank<1, 0, 1>([](auto && c, auto && a, auto && b) { c += a*b; })), C, A, B);
  156. /* 3 3
  157. 27 30 33
  158. 61 68 75
  159. 95 106 117 */
  160. cout << C << endl;
  161. }
  162. // example from the manual [ma104]
  163. {
  164. ra::Big<int, 3> c({3, 2, 2}, ra::_0 - ra::_1 - 2*ra::_2);
  165. cout << c << endl;
  166. cout << map([](auto && a) { return sum(diag(a)); }, iter<-1>(c)) << endl;
  167. }
  168. // example from the manual [ma105]
  169. {
  170. ra::Big<double, 2> a({2, 3}, {1, 2, 3, 4, 5, 6});
  171. ra::Big<double, 1> b({3}, {10, 20, 30});
  172. ra::Big<double, 2> c({2, 3}, 0);
  173. iter<1>(c) = iter<1>(a) * iter<1>(b); // multiply each item of a by b
  174. cout << c << endl;
  175. }
  176. // example from the manual [ma109]. This is a rare case where I need explicit ply.
  177. {
  178. ra::Big<int, 1> o = {};
  179. ra::Big<int, 1> e = {};
  180. ra::Big<int, 1> n = {1, 2, 7, 9, 12};
  181. ply(where(odd(n), map([&o](auto && x) { o.push_back(x); }, n), map([&e](auto && x) { e.push_back(x); }, n)));
  182. cout << "o: " << format_array(o, false) << ", e: " << format_array(e, false) << endl;
  183. }
  184. return 0;
  185. }