Loops: the foreach constructs

foreach and its variants are a compact and efficient way to perform some action of the kind

For all indices of the array, do something

While this kind of construct is equivalent to write documentation/manually the for loops, it has several advantages:

  • it is more compact, less error prone (one does not need to specify the bounds in the loop).
  • The library orders the loops in way specified by the template parameters TraversalOrder (by default, the standard C order), to obtain the most efficient way to traverse the memory.
  • it is easier to write generic code for array of several dimensions.

foreach

The foreach function call a given function f successively on the indices of an array A, in the order specified by the TraversalOrder of the array.

  • Synopsis:

    template <typename ArrayType, typename Function>
    void foreach (ArrayType const & A, Function F);
    
    • A is an array/matrix/vector or the corresponding view.

    • The template is enabled iif ImmutableArray<ArrayType>::value == true

    • F is a function with the following synopsis

      F(size_t ... indices)
      
  • The foreach algorithm is equivalent to

    for (i,j,k...) F(i,j,k...)
    
  • The for loop are automatically organised to optimize the traversal order of A using the TraversalOrder of the array.

  • As a result this is always equally or more optimized than a documentation/manually written loop.

Example:

#include <triqs/arrays.hpp>
using triqs::arrays::array;
int main() {
  array<long, 2> A(2, 3);
  foreach (A, [&A](size_t i, size_t j) { A(i, j) = i + j; })
    ;
  std::cout << " A " << A << std::endl;
}

Note

You can pass a std::function as Function, but it is not recommended in critical parts of the code.

The indirection caused by std::function at each call may lead to big performance penalty.

The call to lambda, or a custom callable object will on the other hand by inlined.

assign_foreach

assign_foreach is a simpler form that assigns the return value of the function to the array elements. Note that using the lazy expression is usually a lot simpler (except when you already have the function ready).

Synopsis:

 template <typename ArrayType, typename Function>
 void assign_foreach (ArrayType const & A, Function F);

* A is an array/matrix/vector or the corresponding view.
* The template is enabled iif ImmutableArray<ArrayType>::value == true
* F is a function with the following synopsis ::

  F(size_t ... indices)
  • The assign_foreach algorithm is equivalent to

    for (i,j,k...) A(i,j,k...) = F(i,j,k...)
    
  • The for loop are automatically organised to optimize the traversal order of A using the TraversalOrder of the array.

#include <triqs/arrays.hpp>
using triqs::arrays::array;
int main() {
  array<long, 2> A(2, 3);
  assign_foreach(A, [](size_t i, size_t j) { return i + j; });
  std::cout << " A " << A << std::endl;
}

Note

Cf the note of the foreach function.