Automatic assignment of containers

Another use of expression is the automatic assignment of containers.

Synopsis:

If C is a container,

C(x_)        << some_expression_of_x_
C[i_]        << some_expression_of_i_
C(x_)(i_,j_) << some_expression_of_x_i_j
C[x_](i_,j_) << some_expression_of_x_i_j

depending of course of the operator that the container support. The Right Hand Side (RHS) of the << statement can be any expression, while Left Hand Side (LHS) of the << sign is a container supporting the operation (see below).

This statement simply will be rewritten by the CLEF library as

triqs_clef_auto_assign (C, x_ -> some_expression_of_x_);                  // pseudo code
triqs_clef_auto_assign (C, [](auto x_) {return some_expression_of_x_;});  // or in C++ lambda syntax

The function triqs_clef_auto_assign has to be overloaded for the container and the correct functional form, and it is expected to fill C by evaluating this function.

Such a function is provided for TRIQS objects (arrays, matrix, Green function), and also for some STL container like std::vector.

Example :

#include <nda/clef.hpp>
#include <iostream>
#include <vector>
using namespace nda::clef;

int main() {
  int N     = 5;
  double pi = std::acos(-1);

  // automatic assignment of vector
  placeholder<0> k_;
  std::vector<double> V(N);
  make_expr(V)[k_] << cos((2 * pi * k_) / N);

  // chaining them ...
  placeholder<1> i_;
  std::vector<std::vector<double>> W(3, std::vector<double>(N));
  make_expr(W)[i_][k_] << i_ + cos((2 * pi * k_) / N);

  // check result...
  for (size_t u = 0; u < V.size(); ++u)
    if (std::abs(V[u] - cos((2 * pi * u) / N)) > 1.e-10) throw "error!";
  for (size_t w = 0; w < W.size(); ++w)
    for (size_t u = 0; u < W[w].size(); ++u)
      if (std::abs(W[w][u] - (w + cos((2 * pi * u) / N))) > 1.e-10) throw "error!";
}
2
 called triqs_clef_auto_assign 16
3

Details

The synopsis of the triqs_clef_auto_assign functions is

template<typename Fnt> void triqs_clef_auto_assign (Obj & x, Fnt f);

The compiler will then rewrite

obj(x_,y_, ...) = expression

into

triqs_clef_auto_assign (obj, make_function( expression, x_, y_, ....))

The function must be found by ADL. It is therefore useful to implement it e.g. as a friend function.

Similarly, for [ ], adding a function

template<typename Fnt> void triqs_clef_auto_assign_subscript (Obj & x, Fnt f);

The compiler will rewrite

obj[i_] = expression

into

triqs_clef_auto_assign_subscript (obj, make_function( expression, i_))

A complete example:

#include <nda/clef.hpp>
#include <iostream>
using namespace nda::clef;

struct Obj {
  double v;
  CLEF_IMPLEMENT_LAZY_CALL();
  //
  template <typename Fnt> friend void clef_auto_assign(Obj &x, Fnt f) {
    std::cout << " called triqs_clef_auto_assign " << f(x.v++) << std::endl;
  }
};

int main() {
  Obj f{2};
  placeholder<3> x_;
  std::cout << f.v << std::endl;
  f(x_) << 8 * x_;
  std::cout << f.v << std::endl;
}
2
 called triqs_clef_auto_assign 16
3