indirect.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // -*- mode: c++; coding: utf-8 -*-
  2. // ra-ra/examples - Indirect indexing
  3. // Daniel Llorens - 2015
  4. // Adapted from blitz++/examples/indirect.cpp
  5. // The point of this example in Blitz++ seems to be to show off the compact
  6. // notation. ra:: doesn't support special sparse selectors like Blitz++ does,
  7. // and the alternatves look more verbose, but I don't want to clog every expr
  8. // type with additional variants of operator() or operator[] (which on C++17
  9. // still need to be members). The sparse selectors should be better defined as
  10. // standalone functions with separate names depending on the kind of indexing
  11. // they do.
  12. #include "ra/ra.hh"
  13. #include <vector>
  14. #include <iostream>
  15. using std::cout, std::endl;
  16. using ra::sqr;
  17. void
  18. example1()
  19. {
  20. // Indirection using a list of coordinates
  21. ra::Big<int, 2> A({4, 4}, 0), B({4, 4}, 10*ra::_0 + ra::_1);
  22. using coord = ra::Small<int, 2>;
  23. ra::Big<coord, 1> I = { {1, 1}, {2, 2} };
  24. // Blitz++ had A[I] = B.
  25. // In ra::, both sides of = must agree in shape. E.g. if A has rank 1, then I and B must agree in shape (not A and B).
  26. // Also, the selector () is outer product (to index two axes, you need two arguments). The 'coord' selector is at().
  27. // So this is the most direct translation. Note the -> decltype(auto) to construct a reference expr.
  28. map([&A](auto && c) -> decltype(auto) { return A.at(c); }, I)
  29. = map([&B](auto && c) { return B.at(c); }, I);
  30. // More reasonably
  31. for_each([&A, &B](auto && c) { A.at(c) = B.at(c); }, I);
  32. // There is an array op for at(). See also example5 below.
  33. at(A, I) = at(B, I);
  34. cout << "B = " << B << endl << "A = " << A << endl;
  35. // B = 4 x 4
  36. // 0 1 2 3
  37. // 10 11 12 13
  38. // 20 21 22 23
  39. // 30 31 32 33
  40. // A = 4 x 4
  41. // 0 0 0 0
  42. // 0 11 0 0
  43. // 0 0 22 0
  44. // 0 0 0 0
  45. }
  46. void
  47. example2()
  48. {
  49. // Cartesian-product indirection
  50. ra::Big<int, 2> A({6, 6}, 0), B({6, 6}, 10*ra::_0 + ra::_1);
  51. ra::Big<int, 1> I { 1, 2, 4 }, J { 2, 0, 5 };
  52. // The normal selector () already has Cartesian-product behavior. As before, both sides must agree in shape.
  53. A(I, J) = B(I, J);
  54. cout << "B = " << B << endl << "A = " << A << endl;
  55. // B = 6 x 6
  56. // 0 1 2 3 4 5
  57. // 10 11 12 13 14 15
  58. // 20 21 22 23 24 25
  59. // 30 31 32 33 34 35
  60. // 40 41 42 43 44 45
  61. // 50 51 52 53 54 55
  62. // A = 6 x 6
  63. // 0 0 0 0 0 0
  64. // 10 0 12 0 0 15
  65. // 20 0 22 0 0 25
  66. // 0 0 0 0 0 0
  67. // 40 0 42 0 0 45
  68. // 0 0 0 0 0 0
  69. }
  70. void
  71. example3()
  72. {
  73. // Simple 1-D indirection, using a STL container of int
  74. ra::Big<int, 1> A({5}, 0), B({ 1, 2, 3, 4, 5 });
  75. ra::Big<int, 1> I {2, 4, 1};
  76. // As before, both sides must agree in shape.
  77. A(I) = B(I);
  78. cout << "B = " << B << endl << "A = " << A << endl;
  79. // B = [ 1 2 3 4 5 ]
  80. // A = [ 0 2 3 0 5 ]
  81. }
  82. void
  83. example4()
  84. {
  85. // Indirection using a list of rect domains (RectDomain<N> objects in Blitz++).
  86. // ra:: doesn't have those, so we fake it.
  87. int const N = 7;
  88. ra::Big<int, 2> A({N, N}, 0.), B({N, N}, 1.);
  89. double centre_i = (N-1)/2.0;
  90. double centre_j = (N-1)/2.0;
  91. double radius = 0.8 * N/2.0;
  92. // circle will contain a list of strips which represent a circular subdomain.
  93. ra::Big<std::tuple<int, int, int>, 1> circle; // [y x0 x1; ...]
  94. for (int i=0; i < N; ++i) {
  95. double jdist2 = sqr(radius) - sqr(i-centre_i);
  96. if (jdist2 < 0.0)
  97. continue;
  98. int jdist = int(sqrt(jdist2));
  99. int j0 = int(centre_j - jdist);
  100. int j1 = int(centre_j + jdist);
  101. circle.push_back(std::make_tuple(i, j0, j1));
  102. }
  103. // Set only those points in the circle subdomain to 1
  104. map([&A](auto && c) -> decltype(auto) { auto [i, j0, j1] = c; return A(i, ra::iota(j1-j0+1, j0)); }, circle)
  105. = map([&B](auto && c) { auto [i, j0, j1] = c; return B(i, ra::iota(j1-j0+1, j0)); }, circle);
  106. // or more reasonably
  107. for_each([&A, &B](auto && c) { auto [i, j0, j1] = c; auto j = ra::iota(j1-j0+1, j0); A(i, j) = B(i, j); },
  108. circle);
  109. // but it would be easier to just do
  110. A = 0.;
  111. B = 1.;
  112. A = where(sqr(ra::_0-centre_i)+sqr(ra::_1-centre_j)<sqr(radius), B, A);
  113. cout << "A = " << A << endl;
  114. // A = 7 x 7
  115. // 0 0 0 0 0 0 0
  116. // 0 0 1 1 1 0 0
  117. // 0 1 1 1 1 1 0
  118. // 0 1 1 1 1 1 0
  119. // 0 1 1 1 1 1 0
  120. // 0 0 1 1 1 0 0
  121. // 0 0 0 0 0 0 0
  122. }
  123. void
  124. example5()
  125. {
  126. // suppose you have the x coordinates in one array and the y coordinates in another array.
  127. ra::Big<int, 2> x({4, 4}, {0, 1, 2, 0, /* */ 0, 1, 2, 0, /* */ 0, 1, 2, 0, /* */ 0, 1, 2, 0});
  128. ra::Big<int, 2> y({4, 4}, {1, 2, 0, 1, /* */ 1, 2, 0, 1, /* */ 1, 2, 0, 1, /* */ 1, 2, 0, 1});
  129. cout << "coordinates: " << format_array(ra::pack<ra::Small<int, 2>>(x, y), { .sep0="|" }) << endl;
  130. // you can use these for indirect access without creating temporaries.
  131. ra::Big<int, 2> a({3, 3}, {0, 1, 2, 3, 4, 5, 6, 7, 8});
  132. ra::Big<int, 2> b = at(a, ra::pack<ra::Small<int, 2>>(x, y));
  133. cout << "sampling of a using coordinates: " << b << endl;
  134. // cf the default selection operator, which creates an outer product a(x(i, j), y(k, l)) (a 4x4x4x4 array).
  135. cout << "outer product selection: " << a(x, y) << endl;
  136. }
  137. void
  138. example6()
  139. {
  140. ra::Big<int, 1> v = { 1, 3, 4, 9, 15, 12, 0, 1, 15, 12, 0, 3, 4, 8 };
  141. constexpr char chmap[] = "0123456789ABCDEF";
  142. cout << format_array(map(ra::Big<char, 1>(chmap), v), { .sep0="" }) << endl; // FIXME make ra::start(chmap) work
  143. }
  144. // from the manual on ra::iota()
  145. void
  146. example7()
  147. {
  148. ra::Big<int, 1> a = {1, 2, 3, 4, 5, 6};
  149. ra::Big<int, 1> b = {1, 2, 3};
  150. cout << (b + a(ra::iota())) << endl; // a(iota()) has undefined length
  151. }
  152. int main()
  153. {
  154. example1();
  155. example2();
  156. example3();
  157. example4();
  158. example5();
  159. example6();
  160. example7();
  161. }