3
0
mirror of https://github.com/triqs/dft_tools synced 2024-12-25 13:53: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:
Olivier Parcollet 2013-09-07 15:27:10 +02:00
parent 27be5cbd5b
commit 2c542647fd
41 changed files with 813 additions and 980 deletions

View File

@ -1,58 +1,70 @@
.. highlight:: c .. 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_ If C is a container, ::
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
* Right Hand Side (RHS) of the = statement can be any expression. C(x_) << some_expression_of_x_
* Left Hand Side (LHS) of the = sign. A must be a `lazy-assignable`, called by [] or (), one or several time. 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. triqs_clef_auto_assign (C, x_ -> some_expression_of_x_); // pseudo code
A determines the range of value of x on which the function is called. 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:: .. compileblock::
#include "triqs/clef.hpp" #include "triqs/clef.hpp"
#include "triqs/clef/adapters/vector.hpp"
#include <iostream> #include <iostream>
using namespace triqs::clef;
int main() { int main() {
int N = 10; int N = 5;
double pi = std::acos(-1); double pi = std::acos(-1);
std::vector<double> V(N);
// automatic assignment of vector and use of lazy math function // automatic assignment of vector
triqs::clef::placeholder <0> k_; placeholder <0> k_;
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N ); 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... // 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); 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 obj(x_,y_, ...) = expression
@ -60,7 +72,7 @@ into ::
triqs_clef_auto_assign (obj, make_function( expression, x_, y_, ....)) 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 :: Similarly, for [ ], adding a function ::
@ -82,33 +94,22 @@ A complete example :
#include <triqs/clef.hpp> #include <triqs/clef.hpp>
#include <iostream> #include <iostream>
using namespace triqs::clef;
struct Obj{ struct Obj{
double v; double v;
Obj(double v_): v(v_){} TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
//
// 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) { 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; std::cout<< " called triqs_clef_auto_assign "<< f(x.v++)<<std::endl;
} }
friend std::ostream & triqs_clef_formal_print(std::ostream & out, Obj const & x) {return out<<"Obj";}
}; };
int main() { int main() {
Obj f(2); Obj f{2};
triqs::clef::placeholder<3> x_; placeholder<3> x_;
std::cout<< f.v << std::endl; std::cout<< f.v << std::endl;
f(x_ ) << 8*x_ ; f(x_ ) << 8*x_ ;
//f(x_ + y_) = 8*x_; // leads to a compile error as expected
std::cout<< f.v << std::endl; std::cout<< f.v << std::endl;
} }

View File

@ -1,25 +1,27 @@
Clef expressions library Clef
************************************* *************************************
.. highlight:: c .. highlight:: c
.. warning:: .. 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:: .. toctree::
:maxdepth: 1 :maxdepth: 2
introduction
expressions_form expressions_form
expressions_eval expressions_eval
function
lazy_call
assign assign
lazy_function_cls overload
function
examples/contents examples/contents

View File

@ -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....

View File

@ -1,12 +1,14 @@
.. highlight:: c .. highlight:: c
Examples More complex examples
======================= =======================
.. warning::
To be written.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
vector_and_math
lazy_sum lazy_sum
lazy_function

View File

@ -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

View File

@ -3,18 +3,13 @@
A lazy sum A lazy sum
-------------- --------------
Problem : we want Here is a little functional `sum` that sums a function f over various domains
and accepts lazy expressions as arguments.
* 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:
.. literalinclude:: src/sum_functional.cpp .. literalinclude:: src/sum_functional.cpp
which will print : Compiling and running this code reads :
.. literalinclude:: src/sum_functional2.output .. literalinclude:: src/sum_functional.output

View File

@ -0,0 +1 @@
../../../../../test/triqs/clef_examples/

View File

@ -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;
}

View File

@ -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_) );

View File

@ -1,7 +1,7 @@
.. highlight:: c .. highlight:: c
Evaluating clef expressions Evaluating CLEF expressions
=============================== ===============================
Forming expressions is nice, but completely useless unless one can *evaluate* them Forming expressions is nice, but completely useless unless one can *evaluate* them
@ -22,19 +22,21 @@ The evaluation can be :
Complete evaluation Complete evaluation
-------------------- --------------------
Example :: .. compileblock::
eval (x_ + 2*y_ , x_=1, y_ = 2) #include <triqs/clef.hpp>
using namespace triqs::clef;
auto e = x_ + 2*y_; int main () {
auto r = eval( e , x_=1, y_ = 2); 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 : Note that :
* The order of placeholder does not matter in calling eval. * The order of placeholder does not matter in calling eval.
* It is an error to put the same placeholder twice. * It is an error to put the same placeholder twice.
* The correct version of eval is found by ADL (Argument Dependent Lookup). * The correct version of eval is found by ADL (Argument Dependent Lookup) in the triqs::clef namespace.
(It if the clef::eval since arguments are defined in the clef namespace)
Partial evaluation Partial evaluation
-------------------- --------------------

View File

@ -1,28 +1,25 @@
.. highlight:: c .. 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 Placeholders
---------------- -------------------
Loosely speaking, a placeholder is a "variable name" used to build an expression. 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 :: Placeholders are declared as ::
placeholder<Number> Name; placeholder<Number> Name;
This declares a placeholder called Name (an empty object for C++).
Example :: Example ::
placeholder <1> x_; placeholder <1> x_;
placeholder <2> y_; placeholder <2> y_;
Note that the only thing of significance in a placeholder is its type, since it contains no data. Note that the only thing of significance in a placeholder is its type (i.e. Number).
In other words, a placeholder is **empty**. It contains **no value** at runtime. A placeholder is **empty** : it contains **no value** at runtime.
.. warning:: .. 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. would imply that `x_` is the same as `y_` : `x_` == `y_` will be always true.
Forming an expression 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_; auto e = x_ + 2* y_;
e has a complicated type (it is an expression template), which encodes the structure of the expression. // simple math function
Typically here something like :: 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_;
// the type of e is something like
expr<tags::plus, placeholder<1>, expr<tags::multiplies, int, placeholder<2> > 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 * As a user, one *never* has to write such a type
One always use expression "on the fly", or use auto. 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 * Having the whole structure of the expression at compile time allows
efficient evaluation (it is the principle of expression template : add a ref here). 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). 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 * value it is an rvalue : an rvalue (i.e. a temporary) is *moved* into the tree, using
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)` move semantics.
* Conditional if_else expressions
* Callable objects (see below) called on expressions
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 Example ::
expressions.
* For example, the header `math.hpp` contains the declaration to make double a = 3;
the basic function of std `math.h` accept lazy_expressions. auto e = a + 2* x_ ; // a is stored by reference (double &), but 2 is stored by value
.. compileblock:: The rational is as follows :
#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.
* 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 ...

View File

@ -1,8 +1,8 @@
.. highlight:: c .. highlight:: c
Clef expressions vs functions Transform CLEF expressions into functions
===================================================================== ===============================================
Clef expressions are **NOT** functions. In short, Clef expressions are **NOT** functions. In short,
@ -14,22 +14,12 @@ Clef expressions are **NOT** functions. In short,
f(1,2) f(1,2)
It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*, It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*.
and back. (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 make_function
..................... ---------------
Given any expression with placeholder `x_`, `y_`, `z_`, ..., `make_function` Given any expression with placeholder `x_`, `y_`, `z_`, ..., `make_function`
transform them into a regular function. If we say :: 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 :: then f is ::
a function (placeholder_1, placeholder_2, placeholder_3, ...) --> RESULT a function (x1,x2,x3) --> RESULT
where RESULT is : where RESULT is :
* the result of the complete evaluation of the expression if the list of placeholder exhausts the placeholders of the expression. * 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**. * 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 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 >>. is banned because it conflicts with the standard priority of >>.
Use parenthesis. 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;
}
}

View File

@ -1,15 +1,72 @@
.. highlight:: c .. 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 .. compileblock::
the manipulation of formal expressions.
#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

View File

@ -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 ;
}

View File

@ -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`.

View 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.

View File

@ -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
View File

@ -0,0 +1 @@
../triqs/clef/common.hpp

View File

@ -5,13 +5,7 @@ struct F7 {
F7(double v_): v(v_){} 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;} double operator() (int i1, int i2, int i3, int i4, int i5, int i6, int i7 ) const { return 10*i1;}
template< typename... Args> TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F7);
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...);}
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;} 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";} friend std::ostream & operator<<(std::ostream & out, F7 const & x) { return out<<"F7";}

View File

@ -9,13 +9,12 @@ struct F2_vec {
F2 const & operator()(size_t i) const { return vec[i];} F2 const & operator()(size_t i) const { return vec[i];}
template< typename... Args> TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2_vec);
typename triqs::clef::result_of::make_expr_call<F2_vec,Args...>::type
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
template<typename Fnt> template<typename Fnt>
friend void triqs_clef_auto_assign (F2_vec const & x, Fnt f) { 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";} friend std::ostream & operator<<(std::ostream & out, F2_vec const & x) { return out<<"F2_vec";}
}; };

View File

@ -6,37 +6,17 @@ struct F1{
double v; double v;
F1(double v_): v(v_){} F1(double v_): v(v_){}
F1(F1 const &) = delete; // non copyable 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;} double operator() (double x) const { return 10*x;}
template< typename... Args> TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
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;} 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";} 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 { struct F2 {
@ -45,15 +25,10 @@ struct F2 {
double operator()(double x, double y) const { return 10*x + y;} double operator()(double x, double y) const { return 10*x + y;}
template< typename... Args> TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2);
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;} 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";} friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
}; };

View File

@ -34,5 +34,8 @@ int main() {
TEST(tql::eval( h, y_=1) (10)); TEST(tql::eval( h, y_=1) (10));
TEST(h); TEST(h);
auto hh = var(x_, y_) >> 2*x_ + y_;
std::cout << hh (3,1) << std::endl;
} }

View File

@ -9,3 +9,4 @@
lazy function : (_1) --> (((2 * _1) + 1) + 1) lazy function : (_1) --> (((2 * _1) + 1) + 1)
(tql::eval( h, y_=1) (10)) ---> 22 (tql::eval( h, y_=1) (10)) ---> 22
(h) ---> lazy function : (_1) --> (((2 * _1) + _2) + 1) (h) ---> lazy function : (_1) --> (((2 * _1) + _2) + 1)
7

View File

@ -59,30 +59,24 @@ int main() {
{ {
// testing the LHS wrting on an object caught by ref // testing the LHS wrting on an object caught by ref
F1 f(7); F1 f(7);
std::cerr << " operator(double) still ok "<< f(2) << std::endl;
std::cout<< " f.v before assign "<<f.v<<" "<< std::endl; std::cout<< " f.v before assign "<<f.v<<" "<< std::endl;
f(x_ ) << 8*x_ ; 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 '=' // 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<< " f.v after assign "<<f.v<<" "<< std::endl;
std::cout<<"-------------"<<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 // testing fnt of 2 variables
F2 ff; F2 ff;

View File

@ -45,9 +45,6 @@
------------- -------------
f.v before assign 7 f.v before assign 7
f.v after assign 8 f.v after assign 8
-------------
fb.v before assign 7 7
fb.v after assign 7 8
------------- -------------
expr = (F2(_1, _2) + (2 * _2)) expr = (F2(_1, _2) + (2 * _2))
eval(expr,x_ =1, y_ =2) = 16 and it should be 16 eval(expr,x_ =1, y_ =2) = 16 and it should be 16

View File

@ -12,19 +12,19 @@ int main() {
V[0]=14; V[1]=2; V[2]=3; V[0]=14; V[1]=2; V[2]=3;
std::cout<< "V = "<< V[0]<<" "<<V[1]<<" "<<V[2]<<std::endl; 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; 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::cout<< "W = "<< W[0]<<" "<<W[1]<<" "<<W[2]<<std::endl;
std::vector< std::vector< int> > v2 (3, std::vector<int>(2)); 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 u=0; u<v2.size(); ++u)
for (size_t up=0; up<v2[0].size(); ++up) for (size_t up=0; up<v2[0].size(); ++up)

View File

@ -1,5 +1,5 @@
V = 14 2 3 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 V = 2 3 4
W = 2 4 6 W = 2 4 6
11 11

View 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));
};

View File

@ -0,0 +1 @@
(eval( f.my_method(x_), x_ = 10)) ---> 20

View File

@ -13,15 +13,10 @@ struct F1{
F1(F1 const &) = delete; // non copyable F1(F1 const &) = delete; // non copyable
double operator() (double x) const { return 10*x;} double operator() (double x) const { return 10*x;}
template< typename... Args> TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
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;} 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";} friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
}; };

View File

@ -1,56 +1,39 @@
#include <triqs/clef.hpp> #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; 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> 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;} 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. TRIQS_CLEF_IMPLEMENT_LAZY_CALL(sum_impl);
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...);}
// 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";} friend std::ostream & operator<<(std::ostream & out, sum_impl const & x) { return out<<"sum";}
}; };
template<typename Domain, typename Option> // a little factory ...
sum_impl<Domain,Option> sum_functional (Domain && d, Option) {return d;} template<typename Domain> sum_impl<Domain> sum_functional (Domain d) {return {d};}
//--------- MAIN ---------------------------------------
struct DOM{}; struct DOM{};
int main() { int main() {
// two placeholders triqs::clef::placeholder <1> x_; triqs::clef::placeholder <2> y_;
triqs::clef::placeholder <1> x_; DOM d;
triqs::clef::placeholder <2> y_;
DOM d; // a domain // integrate_on_d is the integration functional
auto integrate_on_d = sum_functional(d);
// integrate_on_d is the integration (!) over d with Riemann method
auto integrate_on_d = sum_functional( d, Riemann());
// This is a simple application of the sum to a function // This is a simple application of the sum to a function
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 ) << std::endl; std::cout<< integrate_on_d( x_ >> 2*x_ + 1 ) << std::endl;
// This creates a clef expression of placeholder y_, waiting to make the sum // A function y -> y_ + integrate (x -> 2*x + y)
// Indeed the argument is a clef expression of y_ returning a function auto e1 = y_ + integrate_on_d( x_ >> 2*x_ + y_ );
// composed by integrate_on_d, it is a clef expression of y_ returning a double std::cout<< e1 << std::endl;
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl; std::cout<< eval (e1 ,y_ =0) << 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;
} }

View File

@ -0,0 +1,3 @@
19
(_2 + sum(lazy function : (_1) --> ((2 * _1) + _2)))
9

View File

@ -1,4 +0,0 @@
19
sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))
(_2 + (2 * sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))))
38

View File

@ -10,9 +10,9 @@ int main() {
double pi = std::acos(-1); double pi = std::acos(-1);
std::vector<double> V(N); 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::placeholder <0> k_;
tql::lazy(V) [k_] << cos( (2* pi* k_)/ N ); tql::make_expr(V) [k_] << cos( (2* pi* k_)/ N );
// check result... // check result...
for (size_t u=0; u<V.size(); ++u) for (size_t u=0; u<V.size(); ++u)

View File

@ -232,6 +232,31 @@ namespace triqs { namespace arrays {
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, StorageType::is_weak >::type typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, StorageType::is_weak >::type
operator()() && { return *this; } 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 #else
template<typename... Args> // non const version 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 typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, false >::type
operator()() { return *this; } operator()() { return *this; }
#endif
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression // 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 ... // 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.... // so A(i_) if A is an array will NOT copy the data....
template< typename... Args> 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 { operator()( Args&&... args ) const {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ... 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(*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);} template<typename Fnt> friend void triqs_clef_auto_assign (indexmap_storage_pair & x, Fnt f) { assign_foreach(x,f);}
// ------------------------------- Iterators -------------------------------------------- // ------------------------------- Iterators --------------------------------------------

View File

@ -30,7 +30,7 @@ namespace triqs { namespace arrays {
template<int I> struct _si { typedef size_t type;}; template<int I> struct _si { typedef size_t type;};
public : public :
immutable_array_expr_impl(Expr e_, clef::pair<ph,range> ... p): 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 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 typename std::result_of<function_type(typename _si<ph>::type...)>::type value_type;
typedef indexmaps::cuboid::domain_t<sizeof...(ph)> domain_type; typedef indexmaps::cuboid::domain_t<sizeof...(ph)> domain_type;

View File

@ -23,6 +23,7 @@
#include "../clef.hpp" #include "../clef.hpp"
#include <math.h> #include <math.h>
#include <boost/preprocessor/seq/for_each.hpp> #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) #define TRIQS_CLEF_STD_MATH_FNT_TO_MAKE_LAZY (cos)(sin)(tan)(cosh)(sinh)(tanh)(acos)(asin)(atan)(exp)(log)(sqrt)(abs)(floor)(pow)

View File

@ -2,7 +2,7 @@
* *
* TRIQS: a Toolbox for Research in Interacting Quantum Systems * 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 * 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 * terms of the GNU General Public License as published by the Free Software
@ -21,12 +21,13 @@
#ifndef TRIQS_CLEF_CORE_H #ifndef TRIQS_CLEF_CORE_H
#define TRIQS_CLEF_CORE_H #define TRIQS_CLEF_CORE_H
#include <triqs/utility/first_include.hpp> #include <triqs/utility/first_include.hpp>
#include <triqs/utility/macros.hpp>
#include <triqs/utility/compiler_details.hpp>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <complex> #include <complex>
#include <assert.h>
#include <boost/preprocessor/stringize.hpp> #include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum.hpp>
@ -36,38 +37,49 @@
namespace triqs { namespace clef { namespace triqs { namespace clef {
typedef unsigned long long ull_t; 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{}; } 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 * Placeholder and corresponding traits
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<int i, typename T> struct pair { template<int i, typename T> class pair; // forward
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){}
};
// a placeholder is an empty struct, labelled by an int.
template<int N> struct placeholder { template<int N> struct placeholder {
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
static constexpr int index = N; 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 {}; // placeholder will always be copied (they are empty anyway).
template<int N> struct is_placeholder <placeholder <N> > : std::true_type {}; 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... 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 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<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 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>>{}; template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
/* --------------------------------------------------------------------------------------------------- // in_any_lazy : trait to detect if any of Args is a lazy expression
* Detect if an object is a lazy expression
* --------------------------------------------------------------------------------------------------- */
template<typename... Args> struct is_any_lazy : std::false_type {}; template<typename... Args> struct is_any_lazy : std::false_type {};
template<int N> struct is_any_lazy <placeholder <N> > : std::true_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 > : std::false_type {};
@ -77,68 +89,78 @@ namespace triqs { namespace clef {
template<typename T, typename... Args> struct is_any_lazy<T, Args...> : 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> {}; 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>
template<typename... T> struct has_no_ref : std::true_type {}; constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
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> struct is_clef_expression : is_any_lazy<T>{};
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* Node of the expression tree * Node of the expression tree
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<typename Tag, typename... T> struct expr { template<typename Tag, typename... T> struct expr {
static_assert( has_no_ref<T...>::value , "Internal error : expr childs can not be reference "); // T can be U, U & (a reference or a value).
typedef std::tuple<T...> childs_t; typedef std::tuple<T...> childs_t;
childs_t childs; childs_t childs;
expr(expr const & x) = default; expr(expr const & x) = default;
expr(expr && x) : childs(std::move(x.childs)) {} expr(expr && x) noexcept : childs(std::move(x.childs)) {}
template<typename... Args> explicit expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {} // 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> template<typename Args>
expr<tags::subscript, expr, typename remove_cv_ref<Args>::type > operator[](Args && args) const expr<tags::subscript, expr, typename expr_storage_t<Args>::type > operator[](Args && args) const
{ return expr<tags::subscript, expr, typename remove_cv_ref<Args>::type> (tags::subscript(), *this,std::forward<Args>(args));} { return {tags::subscript(), *this,std::forward<Args>(args)};}
// () also ...
template< typename... Args > template< typename... Args >
expr<tags::function, expr, typename remove_cv_ref<Args>::type...> operator()(Args && ... args) const expr<tags::function, expr, typename expr_storage_t<Args>::type...> operator()(Args && ... args) const
{ return expr<tags::function, expr, typename remove_cv_ref<Args>::type...>(tags::function(), *this,std::forward<Args>(args)...);} { return {tags::function(), *this,std::forward<Args>(args)...};}
// only f(i,j) = expr is allowed, in case where f is a clef::function // assignement is in general deleted
// otherwise use the << operator 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> 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;} operator= (RHS const & rhs) { *this << rhs;}
template<typename RHS, typename CH = childs_t> 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; 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 ph_set< expr<Tag,T... > > : ph_set<T...> {};
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {}; 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.... * The basic operations put in a template....
* --------------------------------------------------------------------------------------------------- */ * --------------------------------------------------------------------------------------------------- */
template<typename Tag> struct operation; 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 /// Terminal
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} }; template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
/// Function call /// Function call
template<> struct operation<tags::function> { 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()(F const & f, Args const & ... args) const DECL_AND_RETURN(_cl(f)(_cl(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...);}
}; };
/// [ ] Call /// [ ] Call
template<> struct operation<tags::subscript> { 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()(F const & f, Args const & args) const DECL_AND_RETURN(_cl(f)[_cl(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];}
}; };
// all binary operators.... // all binary operators....
#define TRIQS_CLEF_OPERATION(TAG,OP)\ #define TRIQS_CLEF_OPERATION(TAG,OP)\
namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
template<> struct operation<tags::TAG> {\ 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>\ 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 \ 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 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));}\ operator OP (L && l, R && r) { return {tags::TAG(),std::forward<L>(l),std::forward<R>(r)};}\
TRIQS_CLEF_OPERATION(plus, +); TRIQS_CLEF_OPERATION(plus, +);
TRIQS_CLEF_OPERATION(minus, -); TRIQS_CLEF_OPERATION(minus, -);
@ -155,11 +177,11 @@ namespace triqs { namespace clef {
#define TRIQS_CLEF_OPERATION(TAG,OP)\ #define TRIQS_CLEF_OPERATION(TAG,OP)\
namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
template<> struct operation<tags::TAG> {\ 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>\ template<typename L>\
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename remove_cv_ref<L>::type> >::type \ typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename expr_storage_t<L>::type> >::type \
operator OP (L && l) { return expr<tags::TAG,typename remove_cv_ref<L>::type> (tags::TAG(),std::forward<L>(l));}\ operator OP (L && l) { return {tags::TAG(),std::forward<L>(l)};}\
TRIQS_CLEF_OPERATION(negate, -); TRIQS_CLEF_OPERATION(negate, -);
TRIQS_CLEF_OPERATION(loginot, !); TRIQS_CLEF_OPERATION(loginot, !);
@ -167,17 +189,12 @@ namespace triqs { namespace clef {
/// the only ternary node : expression if /// the only ternary node : expression if
template<> struct operation<tags::if_else> { 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)) { 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));
//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);
}
}; };
// operator is : if_else( Condition, A, B) // operator is : if_else( Condition, A, B)
template<typename C, typename A, typename 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> 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) { if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<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));}
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
* Evaluation of the expression tree. * Evaluation of the expression tree.
@ -186,7 +203,7 @@ namespace triqs { namespace clef {
template<typename Tag, bool IsLazy, typename... Args> struct operation2; template<typename Tag, bool IsLazy, typename... Args> struct operation2;
template<typename Tag, typename... Args> struct operation2<Tag, true, Args...> { template<typename Tag, typename... Args> struct operation2<Tag, true, Args...> {
typedef expr<Tag,typename remove_cv_ref<Args>::type ...> rtype; 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...> { 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; typedef typename std::remove_reference<typename std::result_of<operation<Tag>(Args...)>::type>::type rtype;
@ -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...);} 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... > { template<int N, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<N,T>, Pairs... > {
typedef typename pair<N,T>::value_type const & rtype; typedef T const & rtype;
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.r;} //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 // general expr node
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> { 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 operation2<Tag, is_any_lazy<typename evaluator<Childs, Pairs...>::rtype... >::value, typename evaluator<Childs, Pairs...>::rtype... > OPTYPE;
typedef typename OPTYPE::rtype rtype; 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 AUX(z,p,unused) eval(std::get<p>(ex.childs),pairs...)
#define IMPL(z, NN, unused) \ #define IMPL(z, NN, unused) \
template< int arity = sizeof...(Childs)>\ template< int arity = sizeof...(Childs)>\
typename std::enable_if< arity==NN, rtype>::type\ typename std::enable_if< arity==NN, rtype>::type\
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\ operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\
{ return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));} { 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 AUX
#undef IMPL #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 // The general eval function for expressions
template<typename T, typename... Pairs> template<typename T, typename... Pairs>
typename evaluator<T,Pairs...>::rtype typename evaluator<T,Pairs...>::rtype
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); } 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 #endif
/* --------------------------------------------------------------------------------------------------- /* ---------------------------------------------------------------------------------------------------
@ -252,29 +282,30 @@ namespace triqs { namespace clef {
make_fun_impl(Expr const & ex_) : ex(ex_) {} make_fun_impl(Expr const & ex_) : ex(ex_) {}
// gcc 4.6 crashes (!!!) on the first variant // gcc 4.6 crashes (!!!) on the first variant
#define TRIQS_WORKAROUND_GCC46BUG #ifndef TRIQS_COMPILER_OBSOLETE_GCC
#ifndef TRIQS_WORKAROUND_GCC46BUG
template<typename... Args> template<typename... Args>
typename evaluator<Expr,pair<Is,Args>...>::rtype typename evaluator<Expr,pair<Is,Args>...>::rtype
operator()(Args const &... args) const operator()(Args &&... args) const
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>(args)...); } { return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
#else #else
template<typename... Args> struct __eval { template<typename... Args> struct __eval {
typedef evaluator<Expr,pair<Is,Args>...> eval_t; typedef evaluator<Expr,pair<Is,Args>...> eval_t;
typedef typename eval_t::rtype rtype; 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> 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 #endif
}; };
// values of the ph, excluding the Is ...
template<ull_t x, int... Is> struct ph_filter; 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, 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<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 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 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...> { template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
typedef evaluator<Expr,Pairs...> e_t; typedef evaluator<Expr,Pairs...> e_t;
@ -283,15 +314,21 @@ namespace triqs { namespace clef {
}; };
template< typename Expr, typename ... Phs> 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}; } make_function(Expr && ex, Phs...) { return {ex}; }
namespace result_of { namespace result_of {
template< typename Expr, typename ... Phs> struct make_function { 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 * make_function
* x_ >> expression is the same as make_function(expression,x) * x_ >> expression is the same as make_function(expression,x)
@ -327,6 +364,10 @@ namespace triqs { namespace clef {
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) { 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>()...)); 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 // any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
template<typename F, typename RHS, typename... T> 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));} { 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 // 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> template<typename Tag, typename... Childs, typename RHS>
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << 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) { 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>()...)); triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
} }
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> template<typename F, typename RHS, typename... T>
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete; 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 a node with the ref, unless it is an rvalue (which is moved).
make_expr(T && x){ return expr<tags::terminal,typename remove_cv_ref<T>::type >(tags::terminal(), std::forward<T>(x));} 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 * Create a call node of an object
* The object can be kept as a : a ref, a copy, a view * 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 : 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 > template< typename Obj, typename... Args >
typename result_of::make_expr_call<Obj,Args...>::type typename _result_of::make_expr_call<Obj,Args...>::type
make_expr_call(Obj&& obj, Args &&... args) make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
{ return typename result_of::make_expr_call<Obj,Args...>::type (tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...);}
/* -------------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------------
* Create a [] call (subscript) node of an object * Create a [] call (subscript) node of an object
* The object can be kept as a : a ref, a copy, a view * 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 : 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> template< typename Obj, typename Arg>
typename result_of::make_expr_subscript<Obj,Arg>::type typename _result_of::make_expr_subscript<Obj,Arg>::type
make_expr_subscript(Obj&& obj, Arg && arg) make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
{ return typename result_of::make_expr_subscript<Obj,Arg>::type (tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg));}
/* -------------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------------
* function class : stores any expression polymorphically * 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 <void> _exp; // CLEAN THIS MUTABLE ?
mutable std::shared_ptr < std_function_type > _fnt_ptr; mutable std::shared_ptr < std_function_type > _fnt_ptr;
public: public:
function():_fnt_ptr(new std_function_type ()){} function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
template<typename Expr, typename... X> 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...))){} 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...);} ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
template< typename... Args> template< typename... Args>
typename triqs::clef::result_of::make_expr_call<function,Args...>::type auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,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) { template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
* (x._fnt_ptr) = std_function_type (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 * The macro to make any function lazy
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace * 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)\ #define TRIQS_CLEF_MAKE_FNT_LAZY(name)\
struct name##_lazy_impl { \ 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> \ 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 #endif
}} // namespace triqs::clef
#endif

View File

@ -31,6 +31,7 @@ namespace triqs { namespace clef {
template<int N> std::ostream &operator <<(std::ostream &sout, placeholder<N> ){return sout << "_"<<N ; } 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(); }
//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; } 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) template<typename T0, typename... T> std::ostream & variadic_print(std::ostream& out, T0&& t0, T&&... t)

View File

@ -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)...); } 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 // 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> template<typename Arg0, typename ...Args>
typename clef::result_of::make_expr_call<view_type,Arg0, Args...>::type typename clef::_result_of::make_expr_call<view_type,Arg0, Args...>::type
//typename clef::result_of::make_expr_call<gf_impl,Arg0, Args...>::type
operator()(Arg0 arg0, Args... args) const { operator()(Arg0 arg0, Args... args) const {
return clef::make_expr_call(view_type(*this),arg0, args...); return clef::make_expr_call(view_type(*this),arg0, args...);
} }
@ -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)));} 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 // Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression
template<typename Arg> /* template<typename Arg>
typename boost::lazy_enable_if< // enable the template if typename boost::lazy_enable_if< // enable the template if
clef::is_any_lazy<Arg>, // One of Args is a lazy expression clef::is_any_lazy<Arg>, // One of Args is a lazy expression
clef::result_of::make_expr_subscript<view_type,Arg> clef::_result_of::make_expr_subscript<view_type,Arg>
>::type // end of lazy_enable_if >::type // end of lazy_enable_if
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));} 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>
//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 /// A direct access to the grid point
template<typename... Args> template<typename... Args>
r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward<Args>(args)...)));} r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward<Args>(args)...)));}

View File

@ -32,20 +32,11 @@
#if GCC_VERSION < 40801 #if GCC_VERSION < 40801
//#warning "gcc compiler" GCC_VERSION //#warning "gcc compiler" GCC_VERSION
#define TRIQS_COMPILER_IS_OBSOLETE #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 // we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11
#endif #endif
#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 #endif

View File

@ -36,5 +36,9 @@
#define DECL_AND_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__;} #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 #endif