mirror of
https://github.com/triqs/dft_tools
synced 2024-12-25 05:43:40 +01:00
clef : new version using lvalues and moving rvalues
- change : all objects are by default stored now by reference, not by copy any more. Unless the trait force_copy_in_expr is true. - rvalue refs are moved into the tree - simplifies a lot the writing of lazy method, objects. - added a macro for methods - tests ok. Further check needed to control absence of copies... - improved documentation
This commit is contained in:
parent
27be5cbd5b
commit
2c542647fd
@ -1,58 +1,70 @@
|
||||
.. highlight:: c
|
||||
|
||||
Automatic assignment
|
||||
=======================
|
||||
Automatic assignment of containers
|
||||
===================================
|
||||
|
||||
Principle
|
||||
----------------
|
||||
Another use of expression is the automatic assignment of containers.
|
||||
|
||||
It is possible to use a subset of possible expressions as Left Hand Side (LHS) in an assignment statement, e.g. ::
|
||||
**Synopsis** :
|
||||
|
||||
A(x_) = some_expression_of_x_
|
||||
A[i_] = some_expression_of_i_
|
||||
A(x_)(i_,j_) = some_expression_of_x_i_j
|
||||
A[x_](i_,j_) = some_expression_of_x_i_j
|
||||
If C is a container, ::
|
||||
|
||||
* Right Hand Side (RHS) of the = statement can be any expression.
|
||||
* Left Hand Side (LHS) of the = sign. A must be a `lazy-assignable`, called by [] or (), one or several time.
|
||||
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
|
||||
|
||||
This writing means that a regular function ::
|
||||
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).
|
||||
|
||||
x_ -> some_expression_of_x_
|
||||
This statement simply will be rewritten by the CLEF library as ::
|
||||
|
||||
will be given to A so that it can fill itself by evaluating this function.
|
||||
A determines the range of value of x on which the function is called.
|
||||
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
|
||||
|
||||
Example
|
||||
---------
|
||||
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 :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include "triqs/clef.hpp"
|
||||
#include "triqs/clef/adapters/vector.hpp"
|
||||
#include <iostream>
|
||||
using namespace triqs::clef;
|
||||
|
||||
int main() {
|
||||
int N = 10;
|
||||
int N = 5;
|
||||
double pi = std::acos(-1);
|
||||
std::vector<double> V(N);
|
||||
|
||||
// automatic assignment of vector and use of lazy math function
|
||||
triqs::clef::placeholder <0> k_;
|
||||
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N );
|
||||
// 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) std::cout<< u << " "<<V[u]<< " "<< cos((2*pi*u)/N)<<std::endl;
|
||||
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!";
|
||||
}
|
||||
|
||||
Implementing automatic assign for an object
|
||||
------------------------------------------------------------
|
||||
**Details**
|
||||
|
||||
It is sufficient to add a function ::
|
||||
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 rewrite ::
|
||||
The compiler will then rewrite ::
|
||||
|
||||
obj(x_,y_, ...) = expression
|
||||
|
||||
@ -60,7 +72,7 @@ into ::
|
||||
|
||||
triqs_clef_auto_assign (obj, make_function( expression, x_, y_, ....))
|
||||
|
||||
The function is found by ADL. It is therefore useful to implement it e.g. as a friend function.
|
||||
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 ::
|
||||
|
||||
@ -82,33 +94,22 @@ A complete example :
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
using namespace triqs::clef;
|
||||
|
||||
struct Obj{
|
||||
double v;
|
||||
Obj(double v_): v(v_){}
|
||||
|
||||
// lazy call : cf ...
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
|
||||
|
||||
// The non const version (which then stores a non-const reference ....)
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
|
||||
x.v++; std::cout<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;
|
||||
}
|
||||
friend std::ostream & triqs_clef_formal_print(std::ostream & out, Obj const & x) {return out<<"Obj";}
|
||||
double v;
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
|
||||
//
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
|
||||
std::cout<< " called triqs_clef_auto_assign "<< f(x.v++)<<std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Obj f(2);
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout<< f.v << std::endl;
|
||||
f(x_ ) << 8*x_ ;
|
||||
//f(x_ + y_) = 8*x_; // leads to a compile error as expected
|
||||
std::cout<< f.v << std::endl;
|
||||
Obj f{2};
|
||||
placeholder<3> x_;
|
||||
std::cout<< f.v << std::endl;
|
||||
f(x_ ) << 8*x_ ;
|
||||
std::cout<< f.v << std::endl;
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,27 @@
|
||||
Clef expressions library
|
||||
Clef
|
||||
*************************************
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
.. warning::
|
||||
|
||||
This library is still a prototype, of alpha quality.
|
||||
This library is still a prototype. Its basic features are used in our codes, but
|
||||
there are probably still some dark corners ...
|
||||
|
||||
Documentation is not fully up to date : work in progress.
|
||||
Documentation in progress.
|
||||
|
||||
The CLEF library (**C**\ompile time **L**\azy **E**\xpressions and **F**\unctions) is a little
|
||||
library to manipulate simple expressions at compile-time and use them e.g.
|
||||
to automatically fill containers.
|
||||
|
||||
The little CLEF library (Compile time Lazy Expression and Function)
|
||||
is a simple lambda library for C++11, to store and code formal expressions
|
||||
using placeholders.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:maxdepth: 2
|
||||
|
||||
introduction
|
||||
expressions_form
|
||||
expressions_eval
|
||||
function
|
||||
lazy_call
|
||||
assign
|
||||
lazy_function_cls
|
||||
overload
|
||||
function
|
||||
examples/contents
|
||||
|
@ -1,40 +0,0 @@
|
||||
|
||||
Copy policy in building expressions [Advanced]
|
||||
====================================================
|
||||
|
||||
When building expressions, a problem can appear for the object at the leaves of the expressions tree
|
||||
(scalar, placeholders, various callable objects, etc...).
|
||||
|
||||
The question is whether they should be captured by value or by reference.
|
||||
|
||||
In the lazy library, the choice has been made to capture them **by value**.
|
||||
|
||||
This means that, by default, *all objects appearing in a lazy expression are copied, rather than captured by reference*.
|
||||
|
||||
This is necessary to store expressions (with auto like above) for future reuse, transform them into new expressions
|
||||
(e.g. make partial evaluation). Expressions are objects.
|
||||
Capturing the leaves by reference easily produces dangling references.
|
||||
[Basically, an expression is a function of its placeholder. The leaves are the parameters of the function,
|
||||
they must leave as long as the expression live. In other words, we need to have a closure of the function].
|
||||
|
||||
The drawback of this approach is that it can generate unless copies of large objects.
|
||||
There are several solutions to this issue :
|
||||
|
||||
* The object is very small (like a double), hence making a copy in not a problem.
|
||||
* You *know* that the object `A` will survive the expression, so using a reference is not a problem.
|
||||
You can use the `lazy(A)` expression that will wrap the reference to the object.
|
||||
* The object has a compagnon view object (like array, array_view). In this case,
|
||||
one wishes to put a view of the object rather than a copy in the expression.
|
||||
There are two cases.
|
||||
|
||||
* TRIQS objects like array, matrix, vector will do it automatically.
|
||||
|
||||
* For another object, if the object defines the tag `has_view_type_tag` as ::
|
||||
|
||||
typedef void has_view_type_tag;
|
||||
typedef MY_VIEW_TYPE view_type;
|
||||
|
||||
the instance of the object will be replaced by an instance of its view_type in building the expression.
|
||||
|
||||
For an illustration, Cf....
|
||||
|
@ -1,12 +1,14 @@
|
||||
.. highlight:: c
|
||||
|
||||
Examples
|
||||
More complex examples
|
||||
=======================
|
||||
|
||||
.. warning::
|
||||
|
||||
To be written.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
vector_and_math
|
||||
lazy_sum
|
||||
lazy_function
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
.. _lazy_function_ex:
|
||||
|
||||
Using clef::function
|
||||
-----------------------------
|
||||
|
||||
The following code :
|
||||
|
||||
.. literalinclude:: src/lazyfunction.cpp
|
||||
|
||||
will print :
|
||||
|
||||
.. literalinclude:: src/lazyfunction2.output
|
||||
|
@ -3,18 +3,13 @@
|
||||
A lazy sum
|
||||
--------------
|
||||
|
||||
Problem : we want
|
||||
|
||||
* a functional `sum` that sums a function f over various domains, with various methods.
|
||||
|
||||
* that this functionnal accepts lazy expressions as arguments.
|
||||
|
||||
This is done by the little code:
|
||||
Here is a little functional `sum` that sums a function f over various domains
|
||||
and accepts lazy expressions as arguments.
|
||||
|
||||
.. literalinclude:: src/sum_functional.cpp
|
||||
|
||||
which will print :
|
||||
Compiling and running this code reads :
|
||||
|
||||
.. literalinclude:: src/sum_functional2.output
|
||||
.. literalinclude:: src/sum_functional.output
|
||||
|
||||
|
||||
|
1
doc/reference/c++/clef/examples/src
Symbolic link
1
doc/reference/c++/clef/examples/src
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../../test/triqs/clef_examples/
|
@ -1,25 +0,0 @@
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
std::vector and math
|
||||
---------------------------------
|
||||
|
||||
A simple example using std::vector.
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include "triqs/clef.hpp"
|
||||
|
||||
int main() {
|
||||
// init some variables
|
||||
int N = 10; double pi = std::acos(-1); std::vector<double> V(N);
|
||||
|
||||
// Filling the vector automatically from an expression of k_
|
||||
triqs::clef::placeholder<0> k_;
|
||||
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N );
|
||||
|
||||
// check result...
|
||||
for (size_t u=0; u<V.size(); ++u)
|
||||
std::cout<< u << " "<<V[u]<< " "<< cos((2*pi*u)/N)<<std::endl;
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
.. highlight:: c
|
||||
|
||||
Forming lazy expressions
|
||||
===========================
|
||||
|
||||
Expressions are composed from :
|
||||
|
||||
* Placeholders
|
||||
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
|
||||
* Callable objects (see below) called on expressions
|
||||
* Conditional if_else expressions
|
||||
|
||||
Placeholders
|
||||
----------------
|
||||
|
||||
Placeholders are only defined by their type, they contain no data ::
|
||||
|
||||
triqs::lazy_expressions::placeholder <DOM,1> x_;
|
||||
triqs::lazy_expressions::placeholder <DOM,2> y_;
|
||||
|
||||
.. warning::
|
||||
As a consequence, if you define::
|
||||
|
||||
triqs::clef::placeholder <DOM,2> y_;
|
||||
|
||||
then `x_` is the same as `y_` : `x_` == `y_` will be always true.
|
||||
|
||||
|
||||
Callable objects
|
||||
--------------------
|
||||
|
||||
* The header `math.hpp` contains the declaration to make
|
||||
the basic function of std `math.h` accept lazy_expressions.
|
||||
Example ::
|
||||
|
||||
#include <triqs/clef/math.hpp>
|
||||
cos(2*x_+1) (x_=2) ;
|
||||
abs(2*x_-1) (x_=2) ;
|
||||
floor(2*x_-1) (x_=2.3) ;
|
||||
pow(2*x_+1,2) (x_=2) ;
|
||||
|
||||
|
||||
* To make your object callable, or to overload a function to accept lazy argument, see :ref:`callable_object`.
|
||||
|
||||
|
||||
Copy policy
|
||||
--------------------
|
||||
|
||||
.. warning:: All objects appearing in a lazy expressions are copied, rather than captured by reference.
|
||||
|
||||
This is necessary to store expressions, make partial evaluation.
|
||||
In order to avoid unncessary copies for large objects, it is necessary to use view type objects ( or shared_ptr).
|
||||
|
||||
**NB** : for array, matrix, vector of the triqs::arrays library, this is automatic : triqs::clef
|
||||
takes a *view* of the objects when building the expression tree.
|
||||
|
||||
Evaluating lazy expressions
|
||||
===============================
|
||||
|
||||
Complete evaluation
|
||||
--------------------
|
||||
|
||||
Expressions are evaluated used named arguments, following the pattern ::
|
||||
|
||||
expression ( placeholder_1 = value_1, placeholder_2 = value_2, ...)
|
||||
|
||||
Example ::
|
||||
|
||||
(x_ + 2*y_) ( x_=1, y_ = 2)
|
||||
|
||||
// or (in C++11)
|
||||
auto e = x_ + 2*y_;
|
||||
auto r = e ( x_=1, y_ = 2);
|
||||
|
||||
Note that :
|
||||
|
||||
* The order of placeholder does not matter
|
||||
* It is an error to put the same placeholder twice.
|
||||
|
||||
Partial evaluation
|
||||
--------------------
|
||||
|
||||
The evaluation can also be partial, in which case the compiler replaces the placeholder whose value is provided
|
||||
and rebuild a new expression tree.
|
||||
|
||||
Example ::
|
||||
|
||||
auto expr = x_ + 2*y_;
|
||||
expr (x_ =1); // ---> 1 + (2 * y_)
|
||||
expr (x_ =x_ + y_); // ---> ((x_ + y_) + (2 * y_))
|
||||
expr(x_ =x_ + y_)( x_ = 1, y_ = 2)); //---> 7
|
||||
|
||||
During the partial evaluation, all subtrees that can evaluated are evaluated.
|
||||
For example ::
|
||||
|
||||
(x_ + f(y_)) (y_=1); // --> x + f(1)
|
||||
|
||||
Assignment
|
||||
------------
|
||||
|
||||
Some objects are `lazy-assignable`, which means that calling them on placeholders is a possible LHS.
|
||||
Expressions like ::
|
||||
|
||||
F(x_,y_) = an_expression_of(x_,y_);
|
||||
|
||||
are rewritten by the compiler into ::
|
||||
|
||||
F.set_from( make_function( an_expression_of(x_,y_), x_, y_) );
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
Evaluating clef expressions
|
||||
Evaluating CLEF expressions
|
||||
===============================
|
||||
|
||||
Forming expressions is nice, but completely useless unless one can *evaluate* them
|
||||
@ -22,19 +22,21 @@ The evaluation can be :
|
||||
Complete evaluation
|
||||
--------------------
|
||||
|
||||
Example ::
|
||||
.. compileblock::
|
||||
|
||||
eval (x_ + 2*y_ , x_=1, y_ = 2)
|
||||
|
||||
auto e = x_ + 2*y_;
|
||||
auto r = eval( e , x_=1, y_ = 2);
|
||||
#include <triqs/clef.hpp>
|
||||
using namespace triqs::clef;
|
||||
int main () {
|
||||
placeholder<1> x_; placeholder<2> y_;
|
||||
std::cout << eval (x_ + 2*y_ , x_=1, y_ =2) << std::endl;
|
||||
std::cout << eval (x_ + 2*y_ , y_=2, x_ =1) << std::endl;
|
||||
}
|
||||
|
||||
Note that :
|
||||
|
||||
* The order of placeholder does not matter in calling eval.
|
||||
* It is an error to put the same placeholder twice.
|
||||
* The correct version of eval is found by ADL (Argument Dependent Lookup).
|
||||
(It if the clef::eval since arguments are defined in the clef namespace)
|
||||
* The correct version of eval is found by ADL (Argument Dependent Lookup) in the triqs::clef namespace.
|
||||
|
||||
Partial evaluation
|
||||
--------------------
|
||||
|
@ -1,28 +1,25 @@
|
||||
.. highlight:: c
|
||||
|
||||
Introduction
|
||||
Forming CLEF expressions
|
||||
===========================
|
||||
|
||||
The first step consists in forming lazy expressions, before evaluating them.
|
||||
In this section, we describe how to form CLEF expressions.
|
||||
|
||||
Placeholders
|
||||
----------------
|
||||
-------------------
|
||||
|
||||
Loosely speaking, a placeholder is a "variable name" used to build an expression.
|
||||
Technically, it is a trivial object, with a type but containing no data.
|
||||
Placeholders are declared as ::
|
||||
|
||||
placeholder<Number> Name;
|
||||
|
||||
This declares a placeholder called Name (an empty object for C++).
|
||||
|
||||
Example ::
|
||||
|
||||
placeholder <1> x_;
|
||||
placeholder <2> y_;
|
||||
|
||||
Note that the only thing of significance in a placeholder is its type, since it contains no data.
|
||||
In other words, a placeholder is **empty**. It contains **no value** at runtime.
|
||||
Note that the only thing of significance in a placeholder is its type (i.e. Number).
|
||||
A placeholder is **empty** : it contains **no value** at runtime.
|
||||
|
||||
.. warning::
|
||||
|
||||
@ -33,18 +30,62 @@ In other words, a placeholder is **empty**. It contains **no value** at runtime.
|
||||
would imply that `x_` is the same as `y_` : `x_` == `y_` will be always true.
|
||||
|
||||
Forming an expression
|
||||
-------------------------
|
||||
------------------------
|
||||
|
||||
Using simple operators, one can form a more complex expression, e.g.::
|
||||
CLEF expressions are made of :
|
||||
|
||||
* Placeholders
|
||||
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
|
||||
* Ternary conditional if_else expressions
|
||||
* Callable objects which overload the operator () for CLEF expressions, See :ref:`callable_object`.
|
||||
* Functions overloaded for CLEF expressions. For example, the header `math.hpp` contains the declaration to make
|
||||
the basic function of std `math.h` accept CLEF_expressions.
|
||||
* In fact, almost anything : the *make_expr* function can be called on any object to make it lazy.
|
||||
|
||||
Examples :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <vector>
|
||||
using namespace triqs::clef;
|
||||
int main () {
|
||||
placeholder<0> i_; placeholder<1> x_; placeholder<2> y_;
|
||||
std::vector<int> V;
|
||||
|
||||
// arithmetic
|
||||
auto e = x_ + 2* y_;
|
||||
|
||||
// simple math function
|
||||
auto e1 = cos(2*x_+1);
|
||||
auto e2 = abs(2*x_-1);
|
||||
|
||||
// making V lazy
|
||||
auto e0 = make_expr(V)[i_];
|
||||
}
|
||||
|
||||
Note that :
|
||||
|
||||
* Expressions do not compute anything, they just store the expression tree.
|
||||
* There is no check of correctness here in general : an expression can be well formed,
|
||||
but meaningless, e.g. ::
|
||||
|
||||
auto e = cos(2*x_, 8); // !
|
||||
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
Storage of expressions [advanced]
|
||||
-----------------------------------
|
||||
|
||||
CLEF expressions have a complicated (expression template) type encoding the structure of the expression
|
||||
at compile time::
|
||||
|
||||
auto e = x_ + 2* y_;
|
||||
|
||||
e has a complicated type (it is an expression template), which encodes the structure of the expression.
|
||||
Typically here something like ::
|
||||
|
||||
// the type of e is something like
|
||||
expr<tags::plus, placeholder<1>, expr<tags::multiplies, int, placeholder<2> >
|
||||
|
||||
It is worth noting that :
|
||||
Note that :
|
||||
|
||||
* As a user, one *never* has to write such a type
|
||||
One always use expression "on the fly", or use auto.
|
||||
@ -52,81 +93,27 @@ It is worth noting that :
|
||||
* Having the whole structure of the expression at compile time allows
|
||||
efficient evaluation (it is the principle of expression template : add a ref here).
|
||||
|
||||
* Declaring an expression does not do any computation, hence the name of the library (lazy ...).
|
||||
* Declaring an expression does not do any computation.
|
||||
It just stores the expression tree (its structure in the type, and the leaves of the tree).
|
||||
|
||||
What is allowed in clef expressions ?
|
||||
==========================================
|
||||
* Every object in the expression tree is captured by :
|
||||
|
||||
Expressions are composed of :
|
||||
* reference it is an lvalue.
|
||||
|
||||
* Placeholders
|
||||
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
|
||||
* Conditional if_else expressions
|
||||
* Callable objects (see below) called on expressions
|
||||
* value it is an rvalue : an rvalue (i.e. a temporary) is *moved* into the tree, using
|
||||
move semantics.
|
||||
|
||||
Callable objects
|
||||
--------------------
|
||||
Exceptions : the following objects are always copied : placeholders, expression themselves.
|
||||
|
||||
* Objects can overload the operator () for lazy expressions in order to build more complex
|
||||
expressions.
|
||||
Example ::
|
||||
|
||||
* For example, the header `math.hpp` contains the declaration to make
|
||||
the basic function of std `math.h` accept lazy_expressions.
|
||||
double a = 3;
|
||||
auto e = a + 2* x_ ; // a is stored by reference (double &), but 2 is stored by value
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
int main () {
|
||||
triqs::clef::placeholder <1> x_;
|
||||
|
||||
auto e1 = cos(2*x_+1);
|
||||
auto e2 = abs(2*x_-1);
|
||||
auto e3 = floor(2*x_-1);
|
||||
auto e4 = pow(2*x_+1,2);
|
||||
}
|
||||
|
||||
* To make your object callable, or to overload a function to accept lazy argument, see :ref:`callable_object`.
|
||||
|
||||
*lazy* function
|
||||
-------------------
|
||||
|
||||
The *lazy* function can be called on any object to make it lazy, e.g.
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <vector>
|
||||
namespace tql = triqs::clef;
|
||||
int main () {
|
||||
std::vector<int> V;
|
||||
tql::placeholder<1> i_;
|
||||
auto e1 = tql::lazy(V)[i_];
|
||||
}
|
||||
|
||||
Copy policy in building expressions
|
||||
---------------------------------------------------
|
||||
|
||||
A central question when forming expressions is whether the object at the leaves of the expressions tree
|
||||
(scalar, placeholders, various callable objects, etc...) should be captured by value or by reference.
|
||||
|
||||
In the clef library, the choice has been made to capture them **by value**, i.e. :
|
||||
|
||||
*By default, all objects appearing in a clef expression are* **copied**, *rather than captured by reference*.
|
||||
|
||||
This is necessary to store expressions (with auto like above) for future reuse, transform them into new expressions
|
||||
(e.g. make partial evaluation). Expressions are ordinary objects.
|
||||
If the leaves of the expression tree were captured by reference, a guarantee would have to be made that
|
||||
they will live at least as long as the expression itself, or one gets dangling references.
|
||||
|
||||
The drawback of this approach is that it can generate useless copies of large objects.
|
||||
There are two simple solutions to this issue :
|
||||
|
||||
* If you *know* that the object `A` will survive the expression, so using a reference is not a problem
|
||||
and use std::reference_wrapper<A> instead of A in the tree.
|
||||
|
||||
* If the object has a compagnon view object (like array, array_view). In this case,
|
||||
one wishes to put a view of the object rather than a copy in the expression.
|
||||
The rational is as follows :
|
||||
|
||||
* rvalue must be moved, otherwise we would keep (dangling) reference to temporaries.
|
||||
* for lvalue, keeping a reference is quicker. Of course, in the previous example,
|
||||
it is mandatory that a live longer than e ...
|
||||
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
Clef expressions vs functions
|
||||
=====================================================================
|
||||
Transform CLEF expressions into functions
|
||||
===============================================
|
||||
|
||||
Clef expressions are **NOT** functions. In short,
|
||||
|
||||
@ -14,22 +14,12 @@ Clef expressions are **NOT** functions. In short,
|
||||
|
||||
f(1,2)
|
||||
|
||||
It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*,
|
||||
and back.
|
||||
It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*.
|
||||
(the opposite is true, if the function accept lazy arguments, cf :ref:`overload_function`).
|
||||
|
||||
Function to clef expressions
|
||||
-------------------------------------
|
||||
|
||||
This is immediate, if the function accept lazy arguments, cf :ref:`callable_object`::
|
||||
|
||||
auto e1 = f(x_);
|
||||
|
||||
|
||||
Transforming clef expressions into functions
|
||||
----------------------------------------------------
|
||||
|
||||
make_function
|
||||
.....................
|
||||
---------------
|
||||
|
||||
Given any expression with placeholder `x_`, `y_`, `z_`, ..., `make_function`
|
||||
transform them into a regular function. If we say ::
|
||||
@ -38,41 +28,13 @@ transform them into a regular function. If we say ::
|
||||
|
||||
then f is ::
|
||||
|
||||
a function (placeholder_1, placeholder_2, placeholder_3, ...) --> RESULT
|
||||
a function (x1,x2,x3) --> RESULT
|
||||
|
||||
where RESULT is :
|
||||
|
||||
* the result of the complete evaluation of the expression if the list of placeholder exhausts the placeholders of the expression.
|
||||
* otherwise a clef_expression of the remaining placeholders, returning a **function**.
|
||||
|
||||
Examples :
|
||||
|
||||
* With one variable::
|
||||
|
||||
auto e1 = 2*x_ + 1;
|
||||
auto f = make_function( e1, x_);
|
||||
f(3) == 7; // ok
|
||||
std::function<double(double)> F(f); // ok
|
||||
|
||||
* With two variables ::
|
||||
|
||||
auto e2 = 2*x_ + y_ + 1;
|
||||
auto f = make_function( e2, x_, y_);
|
||||
f(3,4) == 11; // ok
|
||||
std::function<double(double,double)> F(f); // ok
|
||||
|
||||
* Make a function partially ::
|
||||
|
||||
auto f = make_function( 2*x_ + y_ + 1, x_);
|
||||
// f is a lazy expression expression with placeholder y_, returning a function...
|
||||
auto f1 = eval (f, y_=1); // f1 is a function x-> 2*x + 2
|
||||
f1 (10) == 22;
|
||||
|
||||
* Currifying a function ::
|
||||
auto f = make_function ( make_function( 2*x\_ + y\_ + 1, x\_), y\_);
|
||||
// f a function y-> x-> 2x+y+1
|
||||
// f(y) returns a function x-> 2x+y+1
|
||||
|
||||
|
||||
Short notation with >> operator
|
||||
.....................................
|
||||
@ -95,4 +57,67 @@ For function of *one* variable, the make_function notation can be simplified int
|
||||
is banned because it conflicts with the standard priority of >>.
|
||||
Use parenthesis.
|
||||
|
||||
clef::function
|
||||
--------------------------
|
||||
|
||||
The class triqs::clef::function stored a function of a given signature
|
||||
It is similar to std::function but
|
||||
it can be constructed from an expression and an ordered list of placeholders.
|
||||
|
||||
clef::function can be assigned with the = operator, Cf example below.
|
||||
|
||||
.. note::
|
||||
Like std::function, it stores the expression polymorphically, by erasing its type.
|
||||
This might lead to some performance penalty in some case, even though tests do not show that at present...
|
||||
|
||||
|
||||
Examples
|
||||
---------
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
using namespace triqs::clef;
|
||||
|
||||
int main() {
|
||||
placeholder<0> x_; placeholder<1> y_;
|
||||
{ // with one variable
|
||||
auto f = make_function(2*x_ + 1, x_);
|
||||
std::cout << f(3) << std::endl;
|
||||
std::function<double(double)> F(f);
|
||||
}
|
||||
{ //with two variables
|
||||
auto f = make_function(2*x_ + y_ + 1, x_, y_);
|
||||
std::cout << f(3,4) << std::endl;
|
||||
std::function<double(double,double)> F(f);
|
||||
}
|
||||
{ // Make a function partially
|
||||
auto f = make_function( 2*x_ + y_ + 1, x_);
|
||||
// f is a lazy expression expression with placeholder y_, returning a function...
|
||||
auto f1 = eval (f, y_=1); // f1 is a function x-> 2*x + 2
|
||||
std::cout << f1 (10) << std::endl;
|
||||
}
|
||||
{ // Currying a function
|
||||
//auto f = make_function ( make_function( 2*x_ + y_ + 1, x_), y_);
|
||||
auto f = y_ >> ( x_ >> 2*x_ + y_ + 1);
|
||||
// f a function y-> x-> 2x+y+1
|
||||
// f(y) returns a function x-> 2x+y+1
|
||||
auto g = f(3);
|
||||
std::cout << g (10) << std::endl;
|
||||
}
|
||||
{ // playing with clef::function and std::function
|
||||
triqs::clef::function<double(double,double)> f2,g2;
|
||||
f2(x_,y_) = x_ + y_;
|
||||
std::cout << f2(2,3) << std::endl;
|
||||
|
||||
std::function<double(double,double)> sf2 = f2;
|
||||
std::cout << sf2(2,3) << std::endl;
|
||||
|
||||
g2(x_,y_) = x_ - y_ + f2(x_,2*y_);
|
||||
|
||||
std::function<double(double)> sf = x_>> 2*x_ + 1;
|
||||
std::cout << sf(3) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,72 @@
|
||||
.. highlight:: c
|
||||
|
||||
|
||||
Motivation
|
||||
=======================
|
||||
Motivation : a little tour of CLEF
|
||||
=====================================
|
||||
|
||||
A usual, the best is to start with a few examples, to show the library in action.
|
||||
|
||||
|
||||
The purpose of the Named Parameter Lambda (nplambda) library is to help
|
||||
the manipulation of formal expressions.
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <triqs/arrays.hpp>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
int main() {
|
||||
// Declaring some placeholders (i.e. dummy variables).
|
||||
triqs::clef::placeholder <0> i_;
|
||||
triqs::clef::placeholder <1> j_;
|
||||
|
||||
// Declaring a 3x3 matrix
|
||||
triqs::arrays::matrix<double> A (3,3);
|
||||
|
||||
// Automatically filling the matrix
|
||||
// -> forget about the bounds, it is automatic
|
||||
// -> forget about the best order to order the for loops for performance, it is also automatic
|
||||
A(i_,j_) << i_ + 2*j_;
|
||||
|
||||
// Cheking the result
|
||||
std::cout<< A<< std::endl;
|
||||
|
||||
// It also works for std container: we just have to add a call clef::make_expr function
|
||||
std::vector<double> V(10);
|
||||
double pi = std::acos(-1);
|
||||
|
||||
// Automatically filling the vector with the evaluation of the expression in i_
|
||||
triqs::clef::make_expr(V) [i_] << cos( 2* pi / 5.0 * i_ );
|
||||
|
||||
// -> by the way, the constant calculation is precomputed
|
||||
// (expressions are partially evaluated as soon as possible)
|
||||
// illustration :
|
||||
// the time_consuming_function will be called only once in the loop, while cos is called 10 times
|
||||
auto time_consuming_function=[](double x){std::cout<<"call time_consuming_function"<<std::endl;return 2*x;};
|
||||
triqs::clef::make_expr(V) [i_] << cos( time_consuming_function(10) * i_ );
|
||||
|
||||
// If you insist using on more complex container ....
|
||||
std::vector<std::vector<double>> W(3, std::vector<double>(5));
|
||||
triqs::clef::make_expr(W)[i_] [j_] << i_ + cos( time_consuming_function(10) * j_ + i_);
|
||||
|
||||
// You can also put a CLEF expression in a std::function
|
||||
// a function i -> 2*i +1
|
||||
std::function<int(int)> f = i_ >> 2*i_ +1;
|
||||
// a function (i,j) -> 2*i +j
|
||||
std::function<double(int,int)> g = var(i_,j_) >> 2*i_ +j_;
|
||||
// checking ...
|
||||
std::cout<< "f(10) =" << f(10)<< " g(1,2) =" << g(1,2)<< std::endl;
|
||||
|
||||
// You can also use a Curry form : h is a function i-> j -> 2*i+ j
|
||||
auto h = i_ >> (j_ >> 2*i_ +j_);
|
||||
std::cout<< "h(1)(2) = " << h(1)(2) << std::endl;
|
||||
|
||||
// You an also use this to quickly write some lambda, as an alternative syntax to the C++ lambda
|
||||
// with e.g. STL algorithms (with the advantage that the function is polymorphic !).
|
||||
std::vector<int> v = {0,-1,2,-3,4,5,-6};
|
||||
// replace all negative elements (i.e. those for which i -> (i<0) return true), by 0
|
||||
std::replace_if(begin(v), end(v), i_ >> (i_<0), 0);
|
||||
// for non believer, it really worked ...
|
||||
for (auto const & x : v) std::cout <<x <<" "; std::cout << std::endl;
|
||||
}
|
||||
|
||||
Functional programming techniques are now widely used. For example, boost::phoenix library
|
||||
provides simple lambda techniques.
|
||||
|
||||
NPL is
|
||||
|
||||
|
@ -1,226 +0,0 @@
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
.. _callable_object:
|
||||
|
||||
Overloading functions and callable objects for clef expression arguments
|
||||
=============================================================================
|
||||
|
||||
Given a callable object or a function, it is possible to overload it for clef expression arguments, returning a clef expression.
|
||||
In all cases:
|
||||
|
||||
*Overloads that are activated iif at least one argument is a clef expression*.
|
||||
|
||||
Functions
|
||||
------------
|
||||
|
||||
std math functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The overload is defined by clef automatically for usual functions :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
int main() {
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout << 2.0 + std::cos(2.0) << std::endl;
|
||||
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
|
||||
}
|
||||
|
||||
Overloading a function for clef expressions arguments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The `TRIQS_CLEF_MAKE_FNT_LAZY` macro defines the overload for clef expressions arguments of a function. Synopsis is ::
|
||||
|
||||
namespace triqs { namespace clef {
|
||||
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
|
||||
}}
|
||||
|
||||
For example:
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
|
||||
double foo(double x) { return x/2;}
|
||||
int foo(int x) { return x*2;}
|
||||
|
||||
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
|
||||
|
||||
int main() {
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout << foo(2.0) << std::endl;
|
||||
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
|
||||
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
|
||||
}
|
||||
|
||||
Note that :
|
||||
|
||||
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
|
||||
* The function `foo` can have many overloads.
|
||||
* The function foo can be a template, BUT then the template must be disabled for lazy expressions, as in ::
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value,T>::type
|
||||
foo (T const & x) { return x+1;}
|
||||
|
||||
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
|
||||
|
||||
int main() {
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout << foo(2.0) << std::endl;
|
||||
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
|
||||
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
|
||||
}
|
||||
|
||||
Callable objects
|
||||
--------------------
|
||||
|
||||
Similarly to functions, classes can define an `operator()` for lazy expressions arguments.
|
||||
It is an ordinary operator() that must :
|
||||
|
||||
* Be enabled only when one argument is a clef expression
|
||||
|
||||
* Return a clef expression.
|
||||
|
||||
The function make_expr_call helps.
|
||||
|
||||
Object stored by copy (default)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The default behaviour is to store the object by copy in the expression tree...
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
|
||||
struct Obj {
|
||||
double v; // put something in it
|
||||
Obj(double v_): v(v_){} // constructor
|
||||
|
||||
// The "normal", non lazy call operator ....
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
// Call operator for const object
|
||||
// make_expr_call creates a clef expression with a "call" node at the top
|
||||
// calling this object on the arguments.
|
||||
// Obj is stored by making a copy in the expression tree.
|
||||
// NB : the make_expr_call trait enabled only if one of the arguments is lazy
|
||||
// hence if none of the Args are clef expression, the template is disabled by SFINAE.
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
|
||||
|
||||
// Just to print itself nicely in the expressions
|
||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Obj f(7);
|
||||
triqs::clef::placeholder<3> x_;
|
||||
triqs::clef::placeholder<4> y_;
|
||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
||||
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
||||
}
|
||||
|
||||
Object stored by reference
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes, one want to escape the copy of the object in the tree.
|
||||
In that case, just use a std::reference_wrapper in place of the object.
|
||||
You have then to guarantee that the object will live longer that the expression
|
||||
that you form.
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
|
||||
struct Obj {
|
||||
double v; // put something in it
|
||||
Obj(double v_): v(v_){} // constructor
|
||||
Obj(Obj const &) = delete; // a non copyable object
|
||||
|
||||
// The "normal", non lazy call operator ....
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
// Same as above, but now we stored a ref to the object and not a copy of the object.
|
||||
// Reference are encapsulated in std::reference_wrapper (Cf C++ documentation).
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
|
||||
|
||||
// The non const version (which then stores a non-const reference ....)
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
|
||||
|
||||
// Just to print itself nicely in the expressions
|
||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Obj f(7);
|
||||
triqs::clef::placeholder<3> x_;
|
||||
triqs::clef::placeholder<4> y_;
|
||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
||||
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
||||
}
|
||||
|
||||
.. note : one can of course replace the reference_wrapper by a view of the object, e.g....
|
||||
|
||||
|
||||
NB: When non lazy operator() is already a template ?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Then it must be disabled for clef expression argument, using the trait ::
|
||||
|
||||
clef::is_any_lazy<T...> :: value // true iif one of the T is a clef expression
|
||||
|
||||
Example, derived from the previous one :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct Obj {
|
||||
double v; // put something in it
|
||||
Obj(double v_): v(v_){} // constructor
|
||||
|
||||
// The "normal", non lazy call operator is now a template
|
||||
template <typename T>
|
||||
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value, T>::type // correct
|
||||
// T operator() (T const & x) const { return 10*x;} would be ambiguous !
|
||||
operator() (T const & x) const { return 10*x;}
|
||||
|
||||
// lazy expression
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
|
||||
|
||||
// Just to print itself nicely in the expressions
|
||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Obj f(7);
|
||||
triqs::clef::placeholder<3> x_;
|
||||
triqs::clef::placeholder<4> y_;
|
||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
.. highlight:: c
|
||||
|
||||
clef::function class
|
||||
==========================
|
||||
|
||||
The class triqs::clef::function is similar to boost::function (std::function),
|
||||
except that :
|
||||
|
||||
* it can be constructed from an expression and an ordered list of placeholders.
|
||||
* it is `lazy-callable` and `lazy-assignable`
|
||||
|
||||
.. note::
|
||||
It stores the expression polymorphically, by erasing its type. (You can put various expressions into it, cf below).
|
||||
This might lead to some performance penalty in some case, even though tests do not show that at present...
|
||||
|
||||
Example of usage is given in :ref:`lazy_function_ex`.
|
129
doc/reference/c++/clef/overload.rst
Normal file
129
doc/reference/c++/clef/overload.rst
Normal file
@ -0,0 +1,129 @@
|
||||
.. highlight:: c
|
||||
|
||||
Overloading functions and methods for CLEF arguments
|
||||
=====================================================
|
||||
|
||||
.. _overload_function:
|
||||
|
||||
Overloading functions
|
||||
----------------------------
|
||||
|
||||
Given a function, it is possible to overload it for CLEF expression arguments, returning a CLEF expression
|
||||
using the `TRIQS_CLEF_MAKE_FNT_LAZY` macro.
|
||||
|
||||
**Synopsis** ::
|
||||
|
||||
namespace triqs { namespace clef {
|
||||
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
|
||||
}}
|
||||
|
||||
For example:
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
|
||||
// a simple foo function
|
||||
double foo(double x) { return x/2;}
|
||||
int foo(int x) { return x*2;}
|
||||
|
||||
// a more complex case : bar is already a template
|
||||
// we have to disable it for CLEF expression to avoid ambiguity
|
||||
|
||||
// C++14 clean syntax will be (using concepts)
|
||||
// template<NotClefExpression T>
|
||||
// T bar (T const & x) { return x+1;}
|
||||
|
||||
// C++11 workaround
|
||||
template<typename T>
|
||||
typename std::enable_if<!triqs::clef::is_clef_expression<T>::value,T>::type
|
||||
bar (T const & x) { return x+1;}
|
||||
|
||||
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; TRIQS_CLEF_MAKE_FNT_LAZY (bar) ; }}
|
||||
|
||||
int main() {
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout << foo(2.0)<<" "<<eval(x_ + foo(x_), x_ = 3)<<" "<<eval(x_ + foo(x_), x_ = 3.5) << std::endl;
|
||||
std::cout << bar(2.0)<<" "<<eval(x_ + bar(x_), x_ = 3)<<" "<<eval(x_ + bar(x_), x_ = 3.5) << std::endl;
|
||||
}
|
||||
|
||||
Note that :
|
||||
|
||||
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
|
||||
* The function `foo` can have many overloads.
|
||||
* The function `bar` can be a template, BUT then the template must be disabled for lazy expressions.
|
||||
* The overload is already defined by clef for usual functions :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
#include <iostream>
|
||||
int main() {
|
||||
triqs::clef::placeholder<3> x_;
|
||||
std::cout << 2.0 + std::cos(2.0) << std::endl;
|
||||
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
|
||||
}
|
||||
|
||||
.. _callable_object:
|
||||
|
||||
Overloading operator() and other methods
|
||||
---------------------------------------------------
|
||||
|
||||
|
||||
Similarly to functions, classes can define an `operator()` for CLEF expressions arguments (or any other method).
|
||||
It is an ordinary operator() that must :
|
||||
|
||||
* Be enabled only when one argument is a CLEF expression
|
||||
* Return a CLEF expression.
|
||||
|
||||
Example :
|
||||
|
||||
.. compileblock::
|
||||
|
||||
#include <triqs/clef.hpp>
|
||||
|
||||
struct Obj {
|
||||
double v; // put something in it
|
||||
Obj(double v_): v(v_){} // constructor
|
||||
Obj(Obj const &) = delete; // a non copyable object, to illustrate that we do NOT copy...
|
||||
|
||||
// The "normal", non CLEF call operator ....
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
// This macro implements properly an overload of the operator ()
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
|
||||
|
||||
// a method
|
||||
double my_method(double x) { return 2*x;}
|
||||
|
||||
// CLEF overload
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(Obj,my_method);
|
||||
|
||||
// Just to print itself nicely in the expressions
|
||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Obj f(7);
|
||||
triqs::clef::placeholder<1> x_; triqs::clef::placeholder<2> y_;
|
||||
|
||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
||||
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl<<std::endl ;
|
||||
|
||||
std::cout << "Clef expression : "<< f.my_method(y_) + 2*x_ << std::endl ;
|
||||
std::cout << "Complete evaluation : "<< eval(f.my_method(x_) + 2*x_, x_=1) << std::endl ;
|
||||
std::cout << "Partial evaluation : "<< eval(f.my_method(y_) + 2*x_, y_=1) << std::endl ;
|
||||
std::cout << "Complete evalution : "<< eval(f.my_method(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
||||
}
|
||||
|
||||
**NB** When the method or the non CLEF operator() is already a template,
|
||||
it must be disabled for clef expression argument, using the trait ::
|
||||
|
||||
clef::is_clef_expression<T...> // true iif one of the T is a clef expression
|
||||
|
||||
as the `bar` function above.
|
||||
|
||||
|
@ -1,67 +0,0 @@
|
||||
#include <triqs/clef/clef.hpp>
|
||||
#include <triqs/clef/io.hpp>
|
||||
#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) <<std::endl;
|
||||
|
||||
struct F1{
|
||||
double v;
|
||||
F1(double v_): v(v_){}
|
||||
F1(F1 const &) = delete; // non copyable
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
|
||||
};
|
||||
|
||||
struct F1b {
|
||||
double v; std::shared_ptr<double> v_ptr;
|
||||
|
||||
F1b(double v_): v_ptr (new double(v_)) {v=v_;} // on purpose, I avoid adding a default constructor !
|
||||
F1b (F1b const & x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
||||
//F1b (F1b && x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
||||
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<F1b,Args...>::type
|
||||
operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F1b const & x) { return out<<"F1b";}
|
||||
|
||||
};
|
||||
|
||||
struct F2 {
|
||||
|
||||
double v;
|
||||
F2() {v=0;}
|
||||
|
||||
double operator()(double x, double y) const { return 10*x + y;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F2>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F2>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
|
||||
};
|
||||
|
||||
|
||||
using namespace triqs::clef;
|
||||
|
||||
triqs::clef::placeholder <1> x_;
|
||||
triqs::clef::placeholder <2> y_;
|
||||
triqs::clef::placeholder <3> z_;
|
||||
namespace tql= triqs::clef;
|
||||
|
1
test/speed/clef_common.hpp
Symbolic link
1
test/speed/clef_common.hpp
Symbolic link
@ -0,0 +1 @@
|
||||
../triqs/clef/common.hpp
|
@ -5,13 +5,7 @@ struct F7 {
|
||||
F7(double v_): v(v_){}
|
||||
double operator() (int i1, int i2, int i3, int i4, int i5, int i6, int i7 ) const { return 10*i1;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F7>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F7>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F7);
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F7 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(1,2,3,4,5,6,7)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F7 const & x) { return out<<"F7";}
|
||||
|
@ -9,13 +9,12 @@ struct F2_vec {
|
||||
|
||||
F2 const & operator()(size_t i) const { return vec[i];}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<F2_vec,Args...>::type
|
||||
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2_vec);
|
||||
|
||||
template<typename Fnt>
|
||||
friend void triqs_clef_auto_assign (F2_vec const & x, Fnt f) {
|
||||
for (size_t i=0; i< x.vec.size(); ++i) triqs_clef_auto_assign(x.vec[i], f(i)); }
|
||||
for (size_t i=0; i< x.vec.size(); ++i) triqs_clef_auto_assign(x.vec[i], f(i));
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & out, F2_vec const & x) { return out<<"F2_vec";}
|
||||
};
|
||||
|
@ -6,37 +6,17 @@ struct F1{
|
||||
double v;
|
||||
F1(double v_): v(v_){}
|
||||
F1(F1 const &) = delete; // non copyable
|
||||
F1(F1 &&x) : v(x.v) { std::cerr << "Moving F1 "<< v<<std::endl;}
|
||||
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
|
||||
};
|
||||
|
||||
struct F1b {
|
||||
double v; std::shared_ptr<double> v_ptr;
|
||||
|
||||
F1b(double v_): v_ptr (new double(v_)) {v=v_;} // on purpose, I avoid adding a default constructor !
|
||||
F1b (F1b const & x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
||||
//F1b (F1b && x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
||||
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<F1b,Args...>::type
|
||||
operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);}
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
friend std::ostream & operator<<(std::ostream & out, F1b const & x) { return out<<"F1b";}
|
||||
|
||||
};
|
||||
|
||||
struct F2 {
|
||||
|
||||
@ -45,15 +25,10 @@ struct F2 {
|
||||
|
||||
double operator()(double x, double y) const { return 10*x + y;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F2>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F2>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2);
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<<std::endl;}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
|
||||
};
|
||||
|
||||
|
@ -34,5 +34,8 @@ int main() {
|
||||
TEST(tql::eval( h, y_=1) (10));
|
||||
TEST(h);
|
||||
|
||||
auto hh = var(x_, y_) >> 2*x_ + y_;
|
||||
std::cout << hh (3,1) << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,3 +9,4 @@
|
||||
lazy function : (_1) --> (((2 * _1) + 1) + 1)
|
||||
(tql::eval( h, y_=1) (10)) ---> 22
|
||||
(h) ---> lazy function : (_1) --> (((2 * _1) + _2) + 1)
|
||||
7
|
||||
|
@ -59,30 +59,24 @@ int main() {
|
||||
{
|
||||
// testing the LHS wrting on an object caught by ref
|
||||
F1 f(7);
|
||||
std::cerr << " operator(double) still ok "<< f(2) << std::endl;
|
||||
std::cout<< " f.v before assign "<<f.v<<" "<< std::endl;
|
||||
f(x_ ) << 8*x_ ;
|
||||
//f(x_ + y_) = 8*x_ ;// leads to a compile error as expected
|
||||
//f(x_ + y_) << 8*x_ ;// leads to a compile error as expected
|
||||
// test.cpp:129:14: error: no viable overloaded '='
|
||||
// f(x_ + y_) = 8*x_ ;
|
||||
// f(x_ + y_) << 8*x_ ;
|
||||
// ~~~~~~~~~~ ^ ~~~~
|
||||
std::cout<< " f.v after assign "<<f.v<<" "<< std::endl;
|
||||
std::cout<<"-------------"<<std::endl;
|
||||
std::cerr <<F1{9}(2,x_, F1{2})<<std::endl;
|
||||
auto expr = F1{9}(x_);
|
||||
expr << 7*x_;
|
||||
std::cerr << expr << std::endl ;
|
||||
F1{9}(x_ ) << 8*x_ ;
|
||||
std::cerr<<"-------------"<<std::endl;
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// testing the LHS wrting on object caught by copy
|
||||
F1b fb(7);
|
||||
std::cout<< " fb.v before assign "<<fb.v<<" "<< *fb.v_ptr<< std::endl;
|
||||
fb(x_ ) << 8*x_ ;
|
||||
//f(x_ + y_) = 8*x_ ;// leads to a compile error as expected
|
||||
// test.cpp:129:14: error: no viable overloaded '='
|
||||
// f(x_ + y_) = 8*x_ ;
|
||||
// ~~~~~~~~~~ ^ ~~~~
|
||||
std::cout<< " fb.v after assign "<<fb.v<<" "<< *fb.v_ptr<< std::endl;
|
||||
std::cout<<"-------------"<<std::endl;
|
||||
|
||||
}
|
||||
{
|
||||
// testing fnt of 2 variables
|
||||
F2 ff;
|
||||
|
@ -45,9 +45,6 @@
|
||||
-------------
|
||||
f.v before assign 7
|
||||
f.v after assign 8
|
||||
-------------
|
||||
fb.v before assign 7 7
|
||||
fb.v after assign 7 8
|
||||
-------------
|
||||
expr = (F2(_1, _2) + (2 * _2))
|
||||
eval(expr,x_ =1, y_ =2) = 16 and it should be 16
|
||||
|
@ -12,19 +12,19 @@ int main() {
|
||||
V[0]=14; V[1]=2; V[2]=3;
|
||||
std::cout<< "V = "<< V[0]<<" "<<V[1]<<" "<<V[2]<<std::endl;
|
||||
|
||||
TEST( tql::eval(lazy(V) [i_], i_=0));
|
||||
TEST( tql::eval(make_expr(V) [i_], i_=0));
|
||||
|
||||
lazy(V) [i_] << i_ + 2;
|
||||
make_expr(V) [i_] << i_ + 2;
|
||||
|
||||
std::cout<< "V = "<< V[0]<<" "<<V[1]<<" "<<V[2]<<std::endl;
|
||||
|
||||
lazy(W) [i_] << i_ + lazy(V)[i_];
|
||||
make_expr(W) [i_] << i_ + make_expr(V)[i_];
|
||||
|
||||
std::cout<< "W = "<< W[0]<<" "<<W[1]<<" "<<W[2]<<std::endl;
|
||||
|
||||
std::vector< std::vector< int> > v2 (3, std::vector<int>(2));
|
||||
|
||||
lazy(v2)[i_][j_] << (i_ + j_ + 1);
|
||||
make_expr(v2)[i_][j_] << (i_ + j_ + 1);
|
||||
|
||||
for (size_t u=0; u<v2.size(); ++u)
|
||||
for (size_t up=0; up<v2[0].size(); ++up)
|
||||
|
@ -1,5 +1,5 @@
|
||||
V = 14 2 3
|
||||
(tql::eval(lazy(V) [i_], i_=0)) ---> 14
|
||||
(tql::eval(make_expr(V) [i_], i_=0)) ---> 14
|
||||
V = 2 3 4
|
||||
W = 2 4 6
|
||||
11
|
||||
|
37
test/triqs/clef/lazy_method.cpp
Normal file
37
test/triqs/clef/lazy_method.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "./common.hpp"
|
||||
|
||||
struct AA{
|
||||
double v;
|
||||
AA(double v_): v(v_){}
|
||||
AA(AA const &) = delete; // non copyable
|
||||
AA(AA &&x) : v(x.v) { std::cerr << "Moving AA "<< std::endl;}
|
||||
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(AA);
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (AA & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & out, AA const & x) { return out<<"AA";}
|
||||
|
||||
double my_method(double x) { return 2*x;}
|
||||
|
||||
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method);
|
||||
#else
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method,double);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
AA f{8};
|
||||
|
||||
TEST(eval( f.my_method(x_), x_ = 10));
|
||||
|
||||
|
||||
};
|
||||
|
1
test/triqs/clef/lazy_method.output
Normal file
1
test/triqs/clef/lazy_method.output
Normal file
@ -0,0 +1 @@
|
||||
(eval( f.my_method(x_), x_ = 10)) ---> 20
|
@ -13,15 +13,10 @@ struct F1{
|
||||
F1(F1 const &) = delete; // non copyable
|
||||
double operator() (double x) const { return 10*x;}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
||||
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
|
||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
|
||||
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
|
||||
};
|
||||
|
||||
|
@ -1,56 +1,39 @@
|
||||
#include <triqs/clef.hpp>
|
||||
#include <triqs/clef/io.hpp>
|
||||
// a general implementation type for all domain and summation methods
|
||||
template<typename Domain, typename Options> struct sum_impl;
|
||||
struct Riemann{}; // one sum method
|
||||
|
||||
template<typename Domain> struct sum_impl<Domain, Riemann> {
|
||||
template<typename Domain> struct sum_impl {
|
||||
Domain d;
|
||||
sum_impl(Domain const &d_):d(d_) {}
|
||||
|
||||
// Disabled when F is a lazy_expression
|
||||
// C++14
|
||||
// double operator() (NotClefExpression const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;}
|
||||
|
||||
// C++11 form
|
||||
template <typename F>
|
||||
typename std::enable_if< !triqs::clef::is_any_lazy <F>::value, double >::type
|
||||
typename std::enable_if< !triqs::clef::is_clef_expression <F>::value, double >::type
|
||||
operator() (F const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;}
|
||||
|
||||
// Defines operator(). Enabled iff one argument is a clef expression.
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<sum_impl,Args...>::type
|
||||
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
|
||||
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(sum_impl);
|
||||
|
||||
// How to print this object in the printing of clef expression
|
||||
friend std::ostream & operator<<(std::ostream & out, sum_impl const & x) { return out<<"sum";}
|
||||
};
|
||||
|
||||
template<typename Domain, typename Option>
|
||||
sum_impl<Domain,Option> sum_functional (Domain && d, Option) {return d;}
|
||||
|
||||
//--------- MAIN ---------------------------------------
|
||||
// a little factory ...
|
||||
template<typename Domain> sum_impl<Domain> sum_functional (Domain d) {return {d};}
|
||||
|
||||
struct DOM{};
|
||||
|
||||
int main() {
|
||||
// two placeholders
|
||||
triqs::clef::placeholder <1> x_;
|
||||
triqs::clef::placeholder <2> y_;
|
||||
triqs::clef::placeholder <1> x_; triqs::clef::placeholder <2> y_;
|
||||
DOM d;
|
||||
|
||||
DOM d; // a domain
|
||||
|
||||
// integrate_on_d is the integration (!) over d with Riemann method
|
||||
auto integrate_on_d = sum_functional( d, Riemann());
|
||||
// integrate_on_d is the integration functional
|
||||
auto integrate_on_d = sum_functional(d);
|
||||
|
||||
// This is a simple application of the sum to a function
|
||||
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 ) << std::endl;
|
||||
|
||||
// This creates a clef expression of placeholder y_, waiting to make the sum
|
||||
// Indeed the argument is a clef expression of y_ returning a function
|
||||
// composed by integrate_on_d, it is a clef expression of y_ returning a double
|
||||
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl;
|
||||
|
||||
// Of course this expression can be mixed with others...
|
||||
std::cout<< y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl;
|
||||
|
||||
// and it can be evaluated
|
||||
std::cout<< eval (y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) ,y_ =0) << std::endl;
|
||||
// A function y -> y_ + integrate (x -> 2*x + y)
|
||||
auto e1 = y_ + integrate_on_d( x_ >> 2*x_ + y_ );
|
||||
std::cout<< e1 << std::endl;
|
||||
std::cout<< eval (e1 ,y_ =0) << std::endl;
|
||||
}
|
||||
|
||||
|
3
test/triqs/clef_examples/sum_functional.output
Normal file
3
test/triqs/clef_examples/sum_functional.output
Normal file
@ -0,0 +1,3 @@
|
||||
19
|
||||
(_2 + sum(lazy function : (_1) --> ((2 * _1) + _2)))
|
||||
9
|
@ -1,4 +0,0 @@
|
||||
19
|
||||
sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))
|
||||
(_2 + (2 * sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))))
|
||||
38
|
@ -10,9 +10,9 @@ int main() {
|
||||
double pi = std::acos(-1);
|
||||
std::vector<double> V(N);
|
||||
|
||||
// automatic assignment of vector and use of lazy math function
|
||||
// automatic assignment of vector and use of make_expr math function
|
||||
tql::placeholder <0> k_;
|
||||
tql::lazy(V) [k_] << cos( (2* pi* k_)/ N );
|
||||
tql::make_expr(V) [k_] << cos( (2* pi* k_)/ N );
|
||||
|
||||
// check result...
|
||||
for (size_t u=0; u<V.size(); ++u)
|
||||
|
@ -232,6 +232,31 @@ namespace triqs { namespace arrays {
|
||||
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, StorageType::is_weak >::type
|
||||
operator()() && { return *this; }
|
||||
|
||||
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
|
||||
// NB : this is ok because indexmap_storage_pair has a shallow copy constructor ...
|
||||
// Correction : no copy, just a ref...
|
||||
// so A(i_) if A is an array will NOT copy the data....
|
||||
template< typename... Args>
|
||||
typename clef::_result_of::make_expr_call<indexmap_storage_pair const &,Args...>::type
|
||||
operator()( Args&&... args ) const & {
|
||||
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
|
||||
return make_expr_call(*this,args...);
|
||||
}
|
||||
|
||||
template< typename... Args>
|
||||
typename clef::_result_of::make_expr_call<indexmap_storage_pair &,Args...>::type
|
||||
operator()( Args&&... args ) & {
|
||||
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
|
||||
return make_expr_call(*this,args...);
|
||||
}
|
||||
|
||||
template< typename... Args>
|
||||
typename clef::_result_of::make_expr_call<indexmap_storage_pair,Args...>::type
|
||||
operator()( Args&&... args ) && {
|
||||
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
|
||||
return make_expr_call(std::move(*this),args...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<typename... Args> // non const version
|
||||
@ -258,18 +283,25 @@ namespace triqs { namespace arrays {
|
||||
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, false >::type
|
||||
operator()() { return *this; }
|
||||
|
||||
#endif
|
||||
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
|
||||
// NB : this is ok because indexmap_storage_pair has a shallow copy constructor ...
|
||||
// Correction : no copy, just a ref...
|
||||
// so A(i_) if A is an array will NOT copy the data....
|
||||
template< typename... Args>
|
||||
typename clef::result_of::make_expr_call<indexmap_storage_pair,Args...>::type
|
||||
typename clef::_result_of::make_expr_call<indexmap_storage_pair const &,Args...>::type
|
||||
operator()( Args&&... args ) const {
|
||||
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
|
||||
return make_expr_call(*this,args...);
|
||||
//return make_expr_call( view_type(*this),args...);
|
||||
}
|
||||
|
||||
template< typename... Args>
|
||||
typename clef::_result_of::make_expr_call<indexmap_storage_pair &,Args...>::type
|
||||
operator()( Args&&... args ) {
|
||||
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
|
||||
return make_expr_call(*this,args...);
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename Fnt> friend void triqs_clef_auto_assign (indexmap_storage_pair & x, Fnt f) { assign_foreach(x,f);}
|
||||
|
||||
// ------------------------------- Iterators --------------------------------------------
|
||||
|
@ -30,7 +30,7 @@ namespace triqs { namespace arrays {
|
||||
template<int I> struct _si { typedef size_t type;};
|
||||
public :
|
||||
immutable_array_expr_impl(Expr e_, clef::pair<ph,range> ... p):
|
||||
f(clef::make_function(e_, clef::placeholder<ph>()...)), dom_(make_shape(p.rhs().size()...)) {};
|
||||
f(clef::make_function(e_, clef::placeholder<ph>()...)), dom_(make_shape(p.rhs.size()...)) {};
|
||||
typedef typename triqs::clef::result_of::make_function<Expr,clef::placeholder<ph>... >::type function_type;
|
||||
typedef typename std::result_of<function_type(typename _si<ph>::type...)>::type value_type;
|
||||
typedef indexmaps::cuboid::domain_t<sizeof...(ph)> domain_type;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../clef.hpp"
|
||||
#include <math.h>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <complex>
|
||||
|
||||
#define TRIQS_CLEF_STD_MATH_FNT_TO_MAKE_LAZY (cos)(sin)(tan)(cosh)(sinh)(tanh)(acos)(asin)(atan)(exp)(log)(sqrt)(abs)(floor)(pow)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
*
|
||||
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
|
||||
*
|
||||
* Copyright (C) 2012 by O. Parcollet
|
||||
* Copyright (C) 2012-2013 by O. Parcollet
|
||||
*
|
||||
* TRIQS is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU General Public License as published by the Free Software
|
||||
@ -21,12 +21,13 @@
|
||||
#ifndef TRIQS_CLEF_CORE_H
|
||||
#define TRIQS_CLEF_CORE_H
|
||||
#include <triqs/utility/first_include.hpp>
|
||||
#include <triqs/utility/macros.hpp>
|
||||
#include <triqs/utility/compiler_details.hpp>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <complex>
|
||||
#include <assert.h>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
@ -36,109 +37,130 @@
|
||||
|
||||
namespace triqs { namespace clef {
|
||||
typedef unsigned long long ull_t;
|
||||
template<typename T> struct remove_cv_ref : std::remove_cv< typename std::remove_reference<T>::type> {};
|
||||
namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; }
|
||||
|
||||
// Compute the type to put in the expression tree.
|
||||
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
|
||||
// If T is an rvalue reference, we store it as the type (using move semantics).
|
||||
template<typename T> struct force_copy_in_expr : std::false_type{};
|
||||
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
|
||||
|
||||
template< class T > struct expr_storage_t {typedef T type;};
|
||||
template< class T > struct expr_storage_t<T&> : std::conditional<force_copy_in_expr<T>::value, T ,std::reference_wrapper<T>>{};
|
||||
template< class T > struct expr_storage_t<T&&> {typedef T type;};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Placeholder and corresponding traits
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<int i, typename T> struct pair {
|
||||
static constexpr int p = i;
|
||||
typedef typename remove_cv_ref <T>::type value_type;
|
||||
value_type const & r;
|
||||
value_type const & rhs() const { return r;}
|
||||
pair (T const & t) : r(t){}
|
||||
};
|
||||
template<int i, typename T> class pair; // forward
|
||||
|
||||
// a placeholder is an empty struct, labelled by an int.
|
||||
template<int N> struct placeholder {
|
||||
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
|
||||
static constexpr int index = N;
|
||||
template <typename RHS> pair<N,RHS> operator = (RHS const & rhs) { return pair<N,RHS>(rhs);}
|
||||
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
|
||||
};
|
||||
|
||||
template<typename T> struct is_placeholder : std::false_type {};
|
||||
template<int N> struct is_placeholder <placeholder <N> > : std::true_type {};
|
||||
// placeholder will always be copied (they are empty anyway).
|
||||
template< int N > struct force_copy_in_expr<placeholder<N>> : std::true_type{};
|
||||
|
||||
// represent a couple (placeholder, value).
|
||||
template<int N, typename U> struct pair {
|
||||
U rhs;
|
||||
static constexpr int p = N;
|
||||
typedef typename remove_cv_ref <U>::type value_type;
|
||||
};
|
||||
|
||||
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
||||
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
|
||||
template<typename... T> struct ph_set;
|
||||
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
|
||||
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
|
||||
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
|
||||
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Detect if an object is a lazy expression
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||
// in_any_lazy : trait to detect if any of Args is a lazy expression
|
||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
||||
|
||||
// a trait that checks the type are value i.e. no &, &&
|
||||
template<typename... T> struct has_no_ref : std::true_type {};
|
||||
template<typename T0, typename... T> struct has_no_ref<T0,T...> : std::integral_constant<bool, !(std::is_reference<T0>::value)&& has_no_ref<T...>::value> {};
|
||||
template<typename T>
|
||||
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Node of the expression tree
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag, typename... T> struct expr {
|
||||
static_assert( has_no_ref<T...>::value , "Internal error : expr childs can not be reference ");
|
||||
typedef std::tuple< T ...> childs_t;
|
||||
// T can be U, U & (a reference or a value).
|
||||
typedef std::tuple<T...> childs_t;
|
||||
childs_t childs;
|
||||
expr(expr const & x) = default;
|
||||
expr(expr && x) : childs(std::move(x.childs)) {}
|
||||
template<typename... Args> explicit expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||
template< typename Args >
|
||||
expr<tags::subscript, expr, typename remove_cv_ref<Args>::type > operator[](Args && args) const
|
||||
{ return expr<tags::subscript, expr, typename remove_cv_ref<Args>::type> (tags::subscript(), *this,std::forward<Args>(args));}
|
||||
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
|
||||
// a constructor with the Tag make it unambiguous with other constructors...
|
||||
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||
// [] returns a new lazy expression, with one more layer
|
||||
template<typename Args>
|
||||
expr<tags::subscript, expr, typename expr_storage_t<Args>::type > operator[](Args && args) const
|
||||
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
||||
// () also ...
|
||||
template< typename... Args >
|
||||
expr<tags::function, expr, typename remove_cv_ref<Args>::type...> operator()(Args && ... args) const
|
||||
{ return expr<tags::function, expr, typename remove_cv_ref<Args>::type...>(tags::function(), *this,std::forward<Args>(args)...);}
|
||||
// only f(i,j) = expr is allowed, in case where f is a clef::function
|
||||
// otherwise use the << operator
|
||||
expr<tags::function, expr, typename expr_storage_t<Args>::type...> operator()(Args && ... args) const
|
||||
{ return {tags::function(), *this,std::forward<Args>(args)...};}
|
||||
// assignement is in general deleted
|
||||
expr & operator= (expr const &) = delete; // no ordinary assignment
|
||||
expr & operator= (expr &&) = default; // move assign ok
|
||||
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
typename std::enable_if<std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>::value>::type
|
||||
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) { *this << rhs;}
|
||||
template<typename RHS, typename CH = childs_t>
|
||||
typename std::enable_if<!std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>::value>::type
|
||||
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
|
||||
operator= (RHS const & rhs) = delete;
|
||||
expr & operator= (expr const & ) = delete; // no ordinary copy
|
||||
};
|
||||
// set some traits
|
||||
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
|
||||
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
|
||||
// if we want that subexpression are copied ?
|
||||
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* The basic operations put in a template....
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
template<typename Tag> struct operation;
|
||||
|
||||
// a little function to clean the reference_wrapper
|
||||
template<typename U> U & _cl(U & x) { return x;}
|
||||
template<typename U> U & _cl(std::reference_wrapper<U> x) { return x.get();}
|
||||
|
||||
/// Terminal
|
||||
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
|
||||
|
||||
/// Function call
|
||||
template<> struct operation<tags::function> {
|
||||
template<typename F, typename... Args> auto operator()(F const & f, Args const & ... args) const -> decltype(f(args...)) { return f(args...);}
|
||||
template<typename F, typename... Args> auto operator()(std::reference_wrapper<F> const &f, Args const & ... args) const -> decltype(f.get()(args...)) { return f.get()(args...);}
|
||||
template<typename F, typename... Args> auto operator()(F const & f, Args const & ... args) const DECL_AND_RETURN(_cl(f)(_cl(args)...));
|
||||
};
|
||||
|
||||
/// [ ] Call
|
||||
template<> struct operation<tags::subscript> {
|
||||
template<typename F, typename Args> auto operator()(F const & f, Args const & args) const -> decltype(f[args]) { return f[args];}
|
||||
template<typename F, typename Args> auto operator()(std::reference_wrapper<F> const &f, Args const & args) const -> decltype(f.get()[args]) { return f.get()[args];}
|
||||
template<typename F, typename Args> auto operator()(F const & f, Args const & args) const DECL_AND_RETURN(_cl(f)[_cl(args)]);
|
||||
};
|
||||
|
||||
// all binary operators....
|
||||
#define TRIQS_CLEF_OPERATION(TAG,OP)\
|
||||
namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
|
||||
template<> struct operation<tags::TAG> {\
|
||||
template<typename L, typename R> auto operator()(L const & l, R const & r) const -> decltype(l OP r) { return l OP r;}\
|
||||
template<typename L, typename R> auto operator()(L const & l, R const & r) const DECL_AND_RETURN ( _cl(l) OP _cl(r));\
|
||||
};\
|
||||
template<typename L, typename R>\
|
||||
typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename remove_cv_ref<L>::type,typename remove_cv_ref<R>::type> >::type \
|
||||
operator OP (L && l, R && r) { return expr<tags::TAG,typename remove_cv_ref<L>::type,typename remove_cv_ref<R>::type> (tags::TAG(),std::forward<L>(l),std::forward<R>(r));}\
|
||||
typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename expr_storage_t<L>::type,typename expr_storage_t<R>::type> >::type \
|
||||
operator OP (L && l, R && r) { return {tags::TAG(),std::forward<L>(l),std::forward<R>(r)};}\
|
||||
|
||||
TRIQS_CLEF_OPERATION(plus, +);
|
||||
TRIQS_CLEF_OPERATION(minus, -);
|
||||
@ -155,11 +177,11 @@ namespace triqs { namespace clef {
|
||||
#define TRIQS_CLEF_OPERATION(TAG,OP)\
|
||||
namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
|
||||
template<> struct operation<tags::TAG> {\
|
||||
template<typename L> auto operator()(L const & l) const -> decltype(OP l) { return OP l;}\
|
||||
template<typename L> auto operator()(L const & l) const DECL_AND_RETURN (OP _cl(l));\
|
||||
};\
|
||||
template<typename L>\
|
||||
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename remove_cv_ref<L>::type> >::type \
|
||||
operator OP (L && l) { return expr<tags::TAG,typename remove_cv_ref<L>::type> (tags::TAG(),std::forward<L>(l));}\
|
||||
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename expr_storage_t<L>::type> >::type \
|
||||
operator OP (L && l) { return {tags::TAG(),std::forward<L>(l)};}\
|
||||
|
||||
TRIQS_CLEF_OPERATION(negate, -);
|
||||
TRIQS_CLEF_OPERATION(loginot, !);
|
||||
@ -167,17 +189,12 @@ namespace triqs { namespace clef {
|
||||
|
||||
/// the only ternary node : expression if
|
||||
template<> struct operation<tags::if_else> {
|
||||
template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const -> decltype((c?a:b)) {
|
||||
//static_assert(std::is_same<typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>::value, "Expression if : evaluation type must be the same");
|
||||
return (c ? a: b);
|
||||
}
|
||||
template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b));
|
||||
};
|
||||
// operator is : if_else( Condition, A, B)
|
||||
template<typename C, typename A, typename B>
|
||||
expr<tags::if_else,typename remove_cv_ref<C>::type,typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>
|
||||
if_else(C && c, A && a, B && b) {
|
||||
return expr<tags::if_else,typename remove_cv_ref<C>::type,typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>
|
||||
(tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b));}
|
||||
expr<tags::if_else,typename expr_storage_t<C>::type,typename expr_storage_t<A>::type,typename expr_storage_t<B>::type>
|
||||
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Evaluation of the expression tree.
|
||||
@ -186,18 +203,18 @@ namespace triqs { namespace clef {
|
||||
template<typename Tag, bool IsLazy, typename... Args> struct operation2;
|
||||
template<typename Tag, typename... Args> struct operation2<Tag, true, Args...> {
|
||||
typedef expr<Tag,typename remove_cv_ref<Args>::type ...> rtype;
|
||||
rtype operator()(Args && ... args) const {return rtype (Tag(), std::forward<Args>(args)...);}
|
||||
rtype operator()(Args const & ... args) const {return rtype {Tag(), args...};}
|
||||
};
|
||||
template<typename Tag, typename... Args> struct operation2<Tag, false, Args...> {
|
||||
typedef typename std::remove_reference<typename std::result_of<operation<Tag>(Args...)>::type>::type rtype;
|
||||
// remove the reference because of ternary if_else in which decltype returns a ref...
|
||||
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
|
||||
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
|
||||
};
|
||||
|
||||
// Generic case : do nothing (for the leaf of the tree except placeholder)
|
||||
template<typename T, typename ... Pairs> struct evaluator{
|
||||
typedef T rtype;
|
||||
rtype operator()( T const & k, Pairs const &... pairs) {return k;}
|
||||
rtype operator()(T const & k, Pairs const &... pairs) {return k;}
|
||||
};
|
||||
|
||||
// placeholder
|
||||
@ -207,40 +224,53 @@ namespace triqs { namespace clef {
|
||||
rtype operator()(placeholder<N>, pair<i,T> const &, Pairs const& ... pairs) { return eval_t()(placeholder<N>(), pairs...);}
|
||||
};
|
||||
template<int N, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<N,T>, Pairs... > {
|
||||
typedef typename pair<N,T>::value_type const & rtype;
|
||||
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.r;}
|
||||
typedef T const & rtype;
|
||||
//typedef typename pair<N,T>::value_type const & rtype;
|
||||
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.rhs;}
|
||||
};
|
||||
|
||||
// general expr node
|
||||
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> {
|
||||
typedef operation2<Tag, is_any_lazy<typename evaluator<Childs, Pairs...>::rtype... >::value, typename evaluator<Childs, Pairs...>::rtype... > OPTYPE;
|
||||
typedef typename OPTYPE::rtype rtype;
|
||||
|
||||
// first done manually for clearer error messages ...
|
||||
template< int arity = sizeof...(Childs)>
|
||||
typename std::enable_if< arity==1, rtype>::type
|
||||
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
|
||||
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...) );}
|
||||
|
||||
template< int arity = sizeof...(Childs)>
|
||||
typename std::enable_if< arity==2, rtype>::type
|
||||
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
|
||||
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...) );}
|
||||
|
||||
#define AUX(z,p,unused) eval(std::get<p>(ex.childs),pairs...)
|
||||
#define IMPL(z, NN, unused) \
|
||||
template< int arity = sizeof...(Childs)>\
|
||||
typename std::enable_if< arity==NN, rtype>::type\
|
||||
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\
|
||||
{ return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));}
|
||||
BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
|
||||
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
|
||||
#undef AUX
|
||||
#undef IMPL
|
||||
};
|
||||
|
||||
#ifdef TRIQS_CLEF_EVAL_SHORT_CIRCUIT
|
||||
// A short circuit if intersection of ph and is 0, no need to evaluate the whole tree......
|
||||
// Seems useless, && the second eval is not correct if hte expression is a terminal.
|
||||
template<typename T, typename... Pairs>
|
||||
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) !=0, typename evaluator<T,Pairs...>::rtype > ::type
|
||||
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
|
||||
|
||||
template<typename T, typename... Pairs>
|
||||
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) ==0, T const &> ::type
|
||||
eval (T const & ex, Pairs const &... pairs) { return ex;}
|
||||
#else
|
||||
// The general eval function for expressions
|
||||
template<typename T, typename... Pairs>
|
||||
typename evaluator<T,Pairs...>::rtype
|
||||
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
|
||||
|
||||
#ifdef TRIQS_SHORT_CIRCUIT_NOT_IMPLEMENTED
|
||||
// A short circuit if intersection of ph and is 0, no need to evaluate the whole tree......
|
||||
template<typename T, typename... Pairs>
|
||||
template<typename Tag, typename... Childs, typename... Pairs>
|
||||
typename std::enable_if< (ph_set<Childs...>::value & ph_set<Pairs...>::value) !=0, typename evaluator<expr<Tag,Childs...>,Pairs...>::rtype > ::type
|
||||
eval (expr<Tag,Childs...> const & ex, Pairs const &... pairs) { return evaluator<expr<Tag,Childs...>, Pairs...>()(ex, pairs...); }
|
||||
|
||||
template<typename Tag, typename... Childs, typename... Pairs>
|
||||
typename std::enable_if< (ph_set<Childs...>::value & ph_set<Pairs...>::value) ==0, expr<Tag,Childs...> > ::type
|
||||
eval (expr<Tag,Childs...> const & ex, Pairs const &... pairs) { return ex; }
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
@ -252,29 +282,30 @@ namespace triqs { namespace clef {
|
||||
make_fun_impl(Expr const & ex_) : ex(ex_) {}
|
||||
|
||||
// gcc 4.6 crashes (!!!) on the first variant
|
||||
#define TRIQS_WORKAROUND_GCC46BUG
|
||||
#ifndef TRIQS_WORKAROUND_GCC46BUG
|
||||
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||
template<typename... Args>
|
||||
typename evaluator<Expr,pair<Is,Args>...>::rtype
|
||||
operator()(Args const &... args) const
|
||||
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>(args)...); }
|
||||
operator()(Args &&... args) const
|
||||
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
|
||||
#else
|
||||
template<typename... Args> struct __eval {
|
||||
typedef evaluator<Expr,pair<Is,Args>...> eval_t;
|
||||
typedef typename eval_t::rtype rtype;
|
||||
rtype operator()(Expr const &ex , Args const &... args) const { return eval_t() ( ex, pair<Is,Args>(args)...); }
|
||||
rtype operator()(Expr const &ex , Args &&... args) const { return eval_t() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
|
||||
};
|
||||
template<typename... Args>
|
||||
typename __eval<Args...>::rtype operator()(Args const &... args) const { return __eval<Args...>() ( ex, args...); }
|
||||
typename __eval<Args...>::rtype operator()(Args &&... args) const { return __eval<Args...>() ( ex, std::forward<Args>(args)...); }
|
||||
#endif
|
||||
};
|
||||
|
||||
// values of the ph, excluding the Is ...
|
||||
template<ull_t x, int... Is> struct ph_filter;
|
||||
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
|
||||
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
|
||||
|
||||
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
|
||||
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
|
||||
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
|
||||
|
||||
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
|
||||
typedef evaluator<Expr,Pairs...> e_t;
|
||||
@ -283,22 +314,28 @@ namespace triqs { namespace clef {
|
||||
};
|
||||
|
||||
template< typename Expr, typename ... Phs>
|
||||
make_fun_impl<typename std::remove_cv<typename std::remove_reference<Expr>::type>::type,Phs::index...>
|
||||
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
|
||||
make_function(Expr && ex, Phs...) { return {ex}; }
|
||||
|
||||
namespace result_of {
|
||||
template< typename Expr, typename ... Phs> struct make_function {
|
||||
typedef make_fun_impl<typename std::remove_cv<typename std::remove_reference<Expr>::type>::type,Phs::index...> type;
|
||||
typedef make_fun_impl<typename remove_cv_ref<Expr>::type,Phs::index...> type;
|
||||
};
|
||||
}
|
||||
|
||||
template<int ... N>
|
||||
std::tuple<placeholder<N>...> var( placeholder<N> ...) { return std::make_tuple(placeholder<N>()...);}
|
||||
|
||||
template<typename Expr, int ... N>
|
||||
auto operator >> (std::tuple<placeholder<N>...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* make_function
|
||||
* x_ >> expression is the same as make_function(expression,x)
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template <int N, typename Expr>
|
||||
make_fun_impl<Expr,N > operator >> ( placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------
|
||||
* Auto assign for ()
|
||||
@ -315,7 +352,7 @@ namespace triqs { namespace clef {
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
||||
@ -327,6 +364,10 @@ namespace triqs { namespace clef {
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::function, F, placeholder<Is>...> & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
|
||||
template<typename F, typename RHS, typename... T>
|
||||
@ -348,6 +389,9 @@ namespace triqs { namespace clef {
|
||||
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
|
||||
|
||||
// auto assign of an expr ? (for chain calls) : just reuse the same operator
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
template<typename Tag, typename... Childs, typename RHS>
|
||||
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||
|
||||
@ -356,45 +400,58 @@ namespace triqs { namespace clef {
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
template<typename F, typename RHS, typename... T>
|
||||
template<typename F, typename RHS, int... Is>
|
||||
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||
}
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
|
||||
|
||||
template<typename F, typename RHS, typename... T>
|
||||
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a terminal node of an object. The reference is wrapped in a reference_wrapper...
|
||||
* Create a terminal node of an object. the from clone version force copying the object
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
||||
make_expr(T && x){ return expr<tags::terminal,typename remove_cv_ref<T>::type >(tags::terminal(), std::forward<T>(x));}
|
||||
// make a node with the ref, unless it is an rvalue (which is moved).
|
||||
template<typename T> expr<tags::terminal,typename expr_storage_t<T>::type >
|
||||
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
template<typename T> auto lazy (T && x) -> decltype (make_expr(std::ref(x))) { return make_expr(std::ref(x)); }
|
||||
// make a node from a copy of the object
|
||||
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
|
||||
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a call node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
namespace result_of {
|
||||
template<typename T> struct arity { static constexpr int value =-1;};
|
||||
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename... Args > struct make_expr_call :
|
||||
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename remove_cv_ref<Obj>::type, typename remove_cv_ref<Args>::type ...> > {};
|
||||
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename expr_storage_t<Obj>::type, typename expr_storage_t<Args>::type ...> > {
|
||||
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
|
||||
};
|
||||
}
|
||||
template< typename Obj, typename... Args >
|
||||
typename result_of::make_expr_call<Obj,Args...>::type
|
||||
make_expr_call(Obj&& obj, Args &&... args)
|
||||
{ return typename result_of::make_expr_call<Obj,Args...>::type (tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...);}
|
||||
typename _result_of::make_expr_call<Obj,Args...>::type
|
||||
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* Create a [] call (subscript) node of an object
|
||||
* The object can be kept as a : a ref, a copy, a view
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
|
||||
namespace result_of {
|
||||
namespace _result_of {
|
||||
template< typename Obj, typename Arg> struct make_expr_subscript :
|
||||
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,typename remove_cv_ref<Obj>::type, typename remove_cv_ref<Arg>::type> > {};
|
||||
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,typename expr_storage_t<Obj>::type, typename expr_storage_t<Arg>::type> > {};
|
||||
}
|
||||
template< typename Obj, typename Arg>
|
||||
typename result_of::make_expr_subscript<Obj,Arg>::type
|
||||
make_expr_subscript(Obj&& obj, Arg && arg)
|
||||
{ return typename result_of::make_expr_subscript<Obj,Arg>::type (tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg));}
|
||||
typename _result_of::make_expr_subscript<Obj,Arg>::type
|
||||
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* function class : stores any expression polymorphically
|
||||
@ -408,16 +465,21 @@ namespace triqs { namespace clef {
|
||||
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
|
||||
mutable std::shared_ptr < std_function_type > _fnt_ptr;
|
||||
public:
|
||||
function():_fnt_ptr(new std_function_type ()){}
|
||||
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
|
||||
|
||||
template<typename Expr, typename... X>
|
||||
explicit function(Expr const & _e, X... x) : _exp(new Expr(_e)),_fnt_ptr(new std_function_type(make_function(_e, x...))){}
|
||||
|
||||
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
|
||||
|
||||
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||
template< typename... Args>
|
||||
typename triqs::clef::result_of::make_expr_call<function,Args...>::type
|
||||
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
|
||||
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
|
||||
#else
|
||||
template< typename... Args>
|
||||
typename _result_of::make_expr_call<function const & ,Args...>::type
|
||||
operator()( Args&&... args ) const { return make_expr_call (*this,args...);}
|
||||
#endif
|
||||
|
||||
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
|
||||
* (x._fnt_ptr) = std_function_type (rhs);
|
||||
@ -425,6 +487,8 @@ namespace triqs { namespace clef {
|
||||
}
|
||||
|
||||
};
|
||||
template<typename F> struct force_copy_in_expr <function<F>> : std::true_type{};
|
||||
|
||||
/* --------------------------------------------------------------------------------------------------
|
||||
* The macro to make any function lazy
|
||||
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace
|
||||
@ -433,11 +497,54 @@ namespace triqs { namespace clef {
|
||||
* --------------------------------------------------------------------------------------------------- */
|
||||
#define TRIQS_CLEF_MAKE_FNT_LAZY(name)\
|
||||
struct name##_lazy_impl { \
|
||||
template<typename... A> auto operator()(A&&... a) const -> decltype (name(std::forward<A>(a)...)) { return name(std::forward<A>(a)...); }\
|
||||
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (name(std::forward<A>(a)...));\
|
||||
};\
|
||||
template< typename... A> \
|
||||
typename triqs::clef::result_of::make_expr_call<name##_lazy_impl,A...>::type name( A&& ... a) { return make_expr_call(name##_lazy_impl(),a...);}
|
||||
auto name( A&& ... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(),std::forward<A>(a)...));
|
||||
|
||||
}} // namespace triqs::clef
|
||||
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\
|
||||
struct __clef_lazy_method_impl_##name { \
|
||||
TY * _x;\
|
||||
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN ((*_x).name(std::forward<A>(a)...));\
|
||||
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
||||
};\
|
||||
template< typename... A> \
|
||||
auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...));
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...)\
|
||||
template< typename... Args>\
|
||||
auto operator()(Args&&... args ) const & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
||||
\
|
||||
template< typename... Args>\
|
||||
auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
||||
\
|
||||
template< typename... Args>\
|
||||
auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward<Args>(args)...));\
|
||||
|
||||
#else
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name,RETURN_TYPE)\
|
||||
struct __clef_lazy_method_impl_##name { \
|
||||
TY * _x;\
|
||||
template<typename... A> RETURN_TYPE operator()(A&&... a) const {return ((*_x).name(std::forward<A>(a)...));}\
|
||||
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
||||
};\
|
||||
template< typename... A> \
|
||||
typename _result_of::make_expr_call<__clef_lazy_method_impl_##name, A...>::type\
|
||||
name( A&& ... a) {return make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...);}
|
||||
|
||||
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(TY)\
|
||||
template< typename... Args>\
|
||||
typename triqs::clef::_result_of::make_expr_call<TY const &,Args...>::type\
|
||||
operator()(Args&&... args ) const {return make_expr_call (*this,std::forward<Args>(args)...);}\
|
||||
\
|
||||
template< typename... Args>\
|
||||
typename triqs::clef::_result_of::make_expr_call<TY &,Args...>::type\
|
||||
operator()(Args&&... args ) {return make_expr_call (*this,std::forward<Args>(args)...);}
|
||||
|
||||
#endif
|
||||
|
||||
}} // namespace triqs::clef
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@ namespace triqs { namespace clef {
|
||||
|
||||
template<int N> std::ostream &operator <<(std::ostream &sout, placeholder<N> ){return sout << "_"<<N ; }
|
||||
template<typename T> std::ostream & operator<<(std::ostream & out, std::reference_wrapper<T> const & x) { return out<< x.get(); }
|
||||
//template<typename T> std::ostream & operator<<(std::ostream & out, std::reference_wrapper<T> const & x) { return out<< "["<<x.get()<<"]"; }
|
||||
|
||||
inline std::ostream & variadic_print(std::ostream& out) { return out; }
|
||||
template<typename T0, typename... T> std::ostream & variadic_print(std::ostream& out, T0&& t0, T&&... t)
|
||||
|
@ -186,9 +186,14 @@ namespace triqs { namespace gfs {
|
||||
operator() (Arg0&& arg0, Args&&... args) const { return _evaluator(this,std::forward<Arg0>( arg0), std::forward<Args>(args)...); }
|
||||
|
||||
// Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression
|
||||
//template<typename Arg0, typename ...Args>
|
||||
// auto operator()(Arg0 arg0, Args... args) const DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...));
|
||||
|
||||
//template<typename Arg0, typename ...Args>
|
||||
// auto operator()(Arg0 arg0, Args... args) DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...));
|
||||
|
||||
template<typename Arg0, typename ...Args>
|
||||
typename clef::result_of::make_expr_call<view_type,Arg0, Args...>::type
|
||||
//typename clef::result_of::make_expr_call<gf_impl,Arg0, Args...>::type
|
||||
typename clef::_result_of::make_expr_call<view_type,Arg0, Args...>::type
|
||||
operator()(Arg0 arg0, Args... args) const {
|
||||
return clef::make_expr_call(view_type(*this),arg0, args...);
|
||||
}
|
||||
@ -197,15 +202,15 @@ namespace triqs { namespace gfs {
|
||||
// on mesh component for composite meshes
|
||||
// enable iif the first arg is a mesh_point_t for the first component of the mesh_t
|
||||
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
|
||||
operator() (Arg0 const & arg0, Args const & ... args)
|
||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
|
||||
operator() (Arg0 const & arg0, Args const & ... args)
|
||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||
|
||||
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type
|
||||
operator() (Arg0 const & arg0, Args const & ... args) const
|
||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||
*/
|
||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type
|
||||
operator() (Arg0 const & arg0, Args const & ... args) const
|
||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||
*/
|
||||
|
||||
//// [] and access to the grid point
|
||||
typedef typename std::result_of<data_proxy_t(data_t &,size_t)>::type r_type;
|
||||
@ -223,14 +228,29 @@ namespace triqs { namespace gfs {
|
||||
cr_type operator[] (closest_pt_wrap<U...> const & p) const { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point<Variable,Target,Opt>::invoke(this,p)));}
|
||||
|
||||
// Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression
|
||||
/* template<typename Arg>
|
||||
typename boost::lazy_enable_if< // enable the template if
|
||||
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
|
||||
clef::_result_of::make_expr_subscript<view_type,Arg>
|
||||
>::type // end of lazy_enable_if
|
||||
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));}
|
||||
*/
|
||||
|
||||
/*template<typename Arg>
|
||||
//auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
|
||||
auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
|
||||
|
||||
template<typename Arg>
|
||||
typename boost::lazy_enable_if< // enable the template if
|
||||
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
|
||||
clef::result_of::make_expr_subscript<view_type,Arg>
|
||||
>::type // end of lazy_enable_if
|
||||
//auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
|
||||
auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
|
||||
*/
|
||||
|
||||
template<typename Arg>
|
||||
typename clef::_result_of::make_expr_subscript<view_type,Arg>::type
|
||||
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));}
|
||||
|
||||
/// A direct access to the grid point
|
||||
|
||||
template<typename... Args>
|
||||
r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward<Args>(args)...)));}
|
||||
|
||||
@ -418,8 +438,8 @@ namespace triqs { namespace gfs {
|
||||
return gf_view<Variable,scalar_valued,Opt>(g.mesh(), g.data()(range(), args... ), sg, g.symmetry());
|
||||
}
|
||||
|
||||
// a scalar_valued gf can be viewed as a 1x1 matrix
|
||||
template<typename Variable, typename Opt, bool V, typename... Args>
|
||||
// a scalar_valued gf can be viewed as a 1x1 matrix
|
||||
template<typename Variable, typename Opt, bool V, typename... Args>
|
||||
gf_view<Variable,matrix_valued,Opt> reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl<Variable,scalar_valued,Opt,V> const & g) {
|
||||
typedef arrays::array_view<typename gfs_implementation::data_proxy<Variable,matrix_valued,Opt>::storage_t::value_type,3> a_t;
|
||||
auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector<size_t,3>(g.data().shape()[0],1,1)), g.data().storage()};
|
||||
|
@ -32,20 +32,11 @@
|
||||
#if GCC_VERSION < 40801
|
||||
//#warning "gcc compiler" GCC_VERSION
|
||||
#define TRIQS_COMPILER_IS_OBSOLETE
|
||||
#define TRIQS_COMPILER_OBSOLETE_GCC
|
||||
// we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
#define TRIQS_USE_STATIC_ASSERT
|
||||
//#define USE_VARIADIC_TEMPLATES
|
||||
#endif
|
||||
|
||||
#ifndef TRIQS_USE_STATIC_ASSERT
|
||||
#include "boost/static_assert.hpp"
|
||||
#define static_assert(X,MESS) BOOST_STATIC_ASSERT((X))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -36,5 +36,9 @@
|
||||
|
||||
#define DECL_AND_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__;}
|
||||
|
||||
namespace triqs {
|
||||
template<typename T> struct remove_cv_ref : std::remove_cv< typename std::remove_reference<T>::type> {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user