indirect.cc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. void example1()
  17. {
  18. // Indirection using a list of coordinates
  19. ra::Big<int, 2> A({4, 4}, 0), B({4, 4}, 10*ra::_0 + ra::_1);
  20. using coord = ra::Small<int, 2>;
  21. ra::Big<coord, 1> I = { {1, 1}, {2, 2} };
  22. // Blitz++ had A[I] = B.
  23. // 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).
  24. // Also, the selector () is outer product (to index two axes, you need two arguments). The 'coord' selector is at().
  25. // So this is the most direct translation. Note the -> decltype(auto) to construct a reference expr.
  26. map([&A](auto && c) -> decltype(auto) { return A.at(c); }, I)
  27. = map([&B](auto && c) { return B.at(c); }, I);
  28. // More reasonably
  29. for_each([&A, &B](auto && c) { A.at(c) = B.at(c); }, I);
  30. // There is an array op for at(). See also example5 below.
  31. at(A, I) = at(B, I);
  32. cout << "B = " << B << endl << "A = " << A << endl;
  33. // B = 4 x 4
  34. // 0 1 2 3
  35. // 10 11 12 13
  36. // 20 21 22 23
  37. // 30 31 32 33
  38. // A = 4 x 4
  39. // 0 0 0 0
  40. // 0 11 0 0
  41. // 0 0 22 0
  42. // 0 0 0 0
  43. }
  44. void example2()
  45. {
  46. // Cartesian-product indirection
  47. ra::Big<int, 2> A({6, 6}, 0), B({6, 6}, 10*ra::_0 + ra::_1);
  48. ra::Big<int, 1> I { 1, 2, 4 }, J { 2, 0, 5 };
  49. // The normal selector () already has Cartesian-product behavior. As before, both sides must agree in shape.
  50. A(I, J) = B(I, J);
  51. cout << "B = " << B << endl << "A = " << A << endl;
  52. // B = 6 x 6
  53. // 0 1 2 3 4 5
  54. // 10 11 12 13 14 15
  55. // 20 21 22 23 24 25
  56. // 30 31 32 33 34 35
  57. // 40 41 42 43 44 45
  58. // 50 51 52 53 54 55
  59. // A = 6 x 6
  60. // 0 0 0 0 0 0
  61. // 10 0 12 0 0 15
  62. // 20 0 22 0 0 25
  63. // 0 0 0 0 0 0
  64. // 40 0 42 0 0 45
  65. // 0 0 0 0 0 0
  66. }
  67. void example3()
  68. {
  69. // Simple 1-D indirection, using a STL container of int
  70. ra::Big<int, 1> A({5}, 0), B({ 1, 2, 3, 4, 5 });
  71. ra::Big<int, 1> I {2, 4, 1};
  72. // As before, both sides must agree in shape.
  73. A(I) = B(I);
  74. cout << "B = " << B << endl << "A = " << A << endl;
  75. // B = [ 1 2 3 4 5 ]
  76. // A = [ 0 2 3 0 5 ]
  77. }
  78. void example4()
  79. {
  80. // Indirection using a list of rect domains (RectDomain<N> objects in Blitz++).
  81. // ra:: doesn't have those, so we fake it.
  82. int const N = 7;
  83. ra::Big<int, 2> A({N, N}, 0.), B({N, N}, 1.);
  84. double centre_i = (N-1)/2.0;
  85. double centre_j = (N-1)/2.0;
  86. double radius = 0.8 * N/2.0;
  87. // circle will contain a list of strips which represent a circular subdomain.
  88. ra::Big<std::tuple<int, int, int>, 1> circle; // [y x0 x1; ...]
  89. for (int i=0; i < N; ++i) {
  90. double jdist2 = sqr(radius) - sqr(i-centre_i);
  91. if (jdist2 < 0.0)
  92. continue;
  93. int jdist = int(sqrt(jdist2));
  94. int j0 = int(centre_j - jdist);
  95. int j1 = int(centre_j + jdist);
  96. circle.push_back(std::make_tuple(i, j0, j1));
  97. }
  98. // Set only those points in the circle subdomain to 1
  99. map([&A](auto && c) -> decltype(auto) { auto [i, j0, j1] = c; return A(i, ra::iota(j1-j0+1, j0)); }, circle)
  100. = map([&B](auto && c) { auto [i, j0, j1] = c; return B(i, ra::iota(j1-j0+1, j0)); }, circle);
  101. // or more reasonably
  102. 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); },
  103. circle);
  104. // but it would be easier to just do
  105. A = 0.;
  106. B = 1.;
  107. A = where(sqr(ra::_0-centre_i)+sqr(ra::_1-centre_j)<sqr(radius), B, A);
  108. cout << "A = " << A << endl;
  109. // A = 7 x 7
  110. // 0 0 0 0 0 0 0
  111. // 0 0 1 1 1 0 0
  112. // 0 1 1 1 1 1 0
  113. // 0 1 1 1 1 1 0
  114. // 0 1 1 1 1 1 0
  115. // 0 0 1 1 1 0 0
  116. // 0 0 0 0 0 0 0
  117. }
  118. void example5()
  119. {
  120. // suppose you have the x coordinates in one array and the y coordinates in another array.
  121. ra::Big<int, 2> x({4, 4}, {0, 1, 2, 0, /* */ 0, 1, 2, 0, /* */ 0, 1, 2, 0, /* */ 0, 1, 2, 0});
  122. ra::Big<int, 2> y({4, 4}, {1, 2, 0, 1, /* */ 1, 2, 0, 1, /* */ 1, 2, 0, 1, /* */ 1, 2, 0, 1});
  123. cout << "coordinates: " << format_array(ra::pack<ra::Small<int, 2>>(x, y), "|") << endl;
  124. // you can use these for indirect access without creating temporaries.
  125. ra::Big<int, 2> a({3, 3}, {0, 1, 2, 3, 4, 5, 6, 7, 8});
  126. ra::Big<int, 2> b = at(a, ra::pack<ra::Small<int, 2>>(x, y));
  127. cout << "sampling of a using coordinates: " << b << endl;
  128. // cf the default selection operator, which creates an outer product a(x(i, j), y(k, l)) (a 4x4x4x4 array).
  129. cout << "outer product selection: " << a(x, y) << endl;
  130. }
  131. void example6()
  132. {
  133. ra::Big<int, 1> v = { 1, 3, 4, 9, 15, 12, 0, 1, 15, 12, 0, 3, 4, 8 };
  134. constexpr char chmap[] = "0123456789ABCDEF";
  135. cout << format_array(map(ra::Big<char, 1>(chmap), v), "") << endl; // FIXME make ra::start(chmap) work
  136. }
  137. int main()
  138. {
  139. example1();
  140. example2();
  141. example3();
  142. example4();
  143. example5();
  144. example6();
  145. }