From 2c542647fd08b9bca4e3b6273edfd60ce8118194 Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Sat, 7 Sep 2013 15:27:10 +0200 Subject: [PATCH] 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 --- doc/reference/c++/clef/assign.rst | 107 +++--- doc/reference/c++/clef/contents.rst | 24 +- doc/reference/c++/clef/copy_policy.rst | 40 --- doc/reference/c++/clef/examples/contents.rst | 8 +- .../c++/clef/examples/lazy_function.rst | 16 - doc/reference/c++/clef/examples/lazy_sum.rst | 17 +- doc/reference/c++/clef/examples/src | 1 + .../c++/clef/examples/vector_and_math.rst | 25 -- doc/reference/c++/clef/expressions.rst | 113 ------ doc/reference/c++/clef/expressions_eval.rst | 20 +- doc/reference/c++/clef/expressions_form.rst | 153 ++++---- doc/reference/c++/clef/function.rst | 115 +++--- doc/reference/c++/clef/introduction.rst | 71 +++- doc/reference/c++/clef/lazy_call.rst | 226 ------------ doc/reference/c++/clef/lazy_function_cls.rst | 16 - doc/reference/c++/clef/overload.rst | 129 +++++++ test/speed/clef_common.hpp | 68 +--- test/triqs/clef/F7.cpp | 8 +- test/triqs/clef/chain_call.cpp | 7 +- test/triqs/clef/common.hpp | 39 +-- test/triqs/clef/function.cpp | 3 + test/triqs/clef/function.output | 1 + test/triqs/clef/general.cpp | 26 +- test/triqs/clef/general.output | 3 - test/triqs/clef/lazy.cpp | 8 +- test/triqs/clef/lazy.output | 2 +- test/triqs/clef/lazy_method.cpp | 37 ++ test/triqs/clef/lazy_method.output | 1 + test/triqs/clef/test1.cpp | 9 +- test/triqs/clef_examples/sum_functional.cpp | 53 +-- .../triqs/clef_examples/sum_functional.output | 3 + .../clef_examples/sum_functional2.output | 4 - test/triqs/clef_examples/vector_and_math.cpp | 4 +- triqs/arrays/impl/indexmap_storage_pair.hpp | 38 +- triqs/arrays/make_immutable_array.hpp | 2 +- triqs/clef/adapters/math.hpp | 1 + triqs/clef/clef.hpp | 327 ++++++++++++------ triqs/clef/io.hpp | 1 + triqs/gfs/gf.hpp | 52 ++- triqs/utility/compiler_details.hpp | 11 +- triqs/utility/macros.hpp | 4 + 41 files changed, 813 insertions(+), 980 deletions(-) delete mode 100644 doc/reference/c++/clef/copy_policy.rst delete mode 100644 doc/reference/c++/clef/examples/lazy_function.rst create mode 120000 doc/reference/c++/clef/examples/src delete mode 100644 doc/reference/c++/clef/examples/vector_and_math.rst delete mode 100644 doc/reference/c++/clef/expressions.rst delete mode 100644 doc/reference/c++/clef/lazy_call.rst delete mode 100644 doc/reference/c++/clef/lazy_function_cls.rst create mode 100644 doc/reference/c++/clef/overload.rst mode change 100644 => 120000 test/speed/clef_common.hpp create mode 100644 test/triqs/clef/lazy_method.cpp create mode 100644 test/triqs/clef/lazy_method.output create mode 100644 test/triqs/clef_examples/sum_functional.output delete mode 100644 test/triqs/clef_examples/sum_functional2.output diff --git a/doc/reference/c++/clef/assign.rst b/doc/reference/c++/clef/assign.rst index 7467905c..193e08eb 100644 --- a/doc/reference/c++/clef/assign.rst +++ b/doc/reference/c++/clef/assign.rst @@ -1,58 +1,70 @@ .. highlight:: c -Automatic assignment -======================= +Automatic assignment of containers +=================================== -Principle ----------------- +Another use of expression is the automatic assignment of containers. -It is possible to use a subset of possible expressions as Left Hand Side (LHS) in an assignment statement, e.g. :: +**Synopsis** : - A(x_) = some_expression_of_x_ - A[i_] = some_expression_of_i_ - A(x_)(i_,j_) = some_expression_of_x_i_j - A[x_](i_,j_) = some_expression_of_x_i_j + If C is a container, :: -* Right Hand Side (RHS) of the = statement can be any expression. -* Left Hand Side (LHS) of the = sign. A must be a `lazy-assignable`, called by [] or (), one or several time. + C(x_) << some_expression_of_x_ + C[i_] << some_expression_of_i_ + C(x_)(i_,j_) << some_expression_of_x_i_j + C[x_](i_,j_) << some_expression_of_x_i_j -This writing means that a regular function :: - - x_ -> some_expression_of_x_ +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). -will be given to A so that it can fill itself by evaluating this function. -A determines the range of value of x on which the function is called. +This statement simply will be rewritten by the CLEF library as :: -Example ---------- + triqs_clef_auto_assign (C, x_ -> some_expression_of_x_); // pseudo code + triqs_clef_auto_assign (C, [](auto x_) {return some_expression_of_x_;}); // or in C++ lambda syntax + +The function `triqs_clef_auto_assign` has to be overloaded for the container and the correct +functional form, and it is expected to fill C by evaluating this function. + +Such a function is provided for TRIQS objects (arrays, matrix, Green function), +and also for some STL container like std::vector. + +Example : .. compileblock:: #include "triqs/clef.hpp" - #include "triqs/clef/adapters/vector.hpp" #include + using namespace triqs::clef; int main() { - int N = 10; + int N = 5; double pi = std::acos(-1); - std::vector V(N); - // automatic assignment of vector and use of lazy math function - triqs::clef::placeholder <0> k_; - triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N ); + // automatic assignment of vector + placeholder <0> k_; + std::vector V(N); + make_expr(V) [k_] << cos( (2* pi* k_)/ N ); + + // chaining them ... + placeholder <1> i_; + std::vector> W(3, std::vector(N)); + make_expr(W)[i_] [k_] << i_ + cos( (2* pi* k_)/ N ); // check result... - for (size_t u=0; u 1.e-10) throw "error!"; + for (size_t w=0; w 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 void triqs_clef_auto_assign (Obj & x, Fnt f); -The compiler will rewrite :: +The compiler will then rewrite :: obj(x_,y_, ...) = expression @@ -60,7 +72,7 @@ into :: triqs_clef_auto_assign (obj, make_function( expression, x_, y_, ....)) -The function is found by ADL. It is therefore useful to implement it e.g. as a friend function. +The function must be found by ADL. It is therefore useful to implement it e.g. as a friend function. Similarly, for [ ], adding a function :: @@ -82,33 +94,22 @@ A complete example : #include #include + using namespace triqs::clef; struct Obj{ - double v; - Obj(double v_): v(v_){} - - // lazy call : cf ... - template< typename... Args> - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);} - - template friend void triqs_clef_auto_assign (Obj & x, Fnt f) { - x.v++; std::cout<< " called triqs_clef_auto_assign "<< f(100)< friend void triqs_clef_auto_assign (Obj & x, Fnt f) { + std::cout<< " called triqs_clef_auto_assign "<< f(x.v++)< x_; - std::cout<< f.v << std::endl; - f(x_ ) << 8*x_ ; - //f(x_ + y_) = 8*x_; // leads to a compile error as expected - std::cout<< f.v << std::endl; + Obj f{2}; + placeholder<3> x_; + std::cout<< f.v << std::endl; + f(x_ ) << 8*x_ ; + std::cout<< f.v << std::endl; } diff --git a/doc/reference/c++/clef/contents.rst b/doc/reference/c++/clef/contents.rst index 13a1db23..b00d451b 100644 --- a/doc/reference/c++/clef/contents.rst +++ b/doc/reference/c++/clef/contents.rst @@ -1,25 +1,27 @@ -Clef expressions library +Clef ************************************* .. highlight:: c .. warning:: - This library is still a prototype, of alpha quality. - - Documentation is not fully up to date : work in progress. + This library is still a prototype. Its basic features are used in our codes, but + there are probably still some dark corners ... + + Documentation in progress. + +The CLEF library (**C**\ompile time **L**\azy **E**\xpressions and **F**\unctions) is a little +library to manipulate simple expressions at compile-time and use them e.g. +to automatically fill containers. -The little CLEF library (Compile time Lazy Expression and Function) -is a simple lambda library for C++11, to store and code formal expressions -using placeholders. .. toctree:: - :maxdepth: 1 + :maxdepth: 2 + introduction expressions_form expressions_eval - function - lazy_call assign - lazy_function_cls + overload + function examples/contents diff --git a/doc/reference/c++/clef/copy_policy.rst b/doc/reference/c++/clef/copy_policy.rst deleted file mode 100644 index c6e259b4..00000000 --- a/doc/reference/c++/clef/copy_policy.rst +++ /dev/null @@ -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.... - diff --git a/doc/reference/c++/clef/examples/contents.rst b/doc/reference/c++/clef/examples/contents.rst index 5deac3bc..fac09a3c 100644 --- a/doc/reference/c++/clef/examples/contents.rst +++ b/doc/reference/c++/clef/examples/contents.rst @@ -1,12 +1,14 @@ .. highlight:: c -Examples +More complex examples ======================= +.. warning:: + + To be written. + .. toctree:: :maxdepth: 1 - vector_and_math lazy_sum - lazy_function diff --git a/doc/reference/c++/clef/examples/lazy_function.rst b/doc/reference/c++/clef/examples/lazy_function.rst deleted file mode 100644 index 50ba4f66..00000000 --- a/doc/reference/c++/clef/examples/lazy_function.rst +++ /dev/null @@ -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 - diff --git a/doc/reference/c++/clef/examples/lazy_sum.rst b/doc/reference/c++/clef/examples/lazy_sum.rst index 9e25d264..38abc02d 100644 --- a/doc/reference/c++/clef/examples/lazy_sum.rst +++ b/doc/reference/c++/clef/examples/lazy_sum.rst @@ -3,18 +3,13 @@ A lazy sum -------------- -Problem : we want - -* a functional `sum` that sums a function f over various domains, with various methods. - -* that this functionnal accepts lazy expressions as arguments. - -This is done by the little code: +Here is a little functional `sum` that sums a function f over various domains +and accepts lazy expressions as arguments. .. literalinclude:: src/sum_functional.cpp -which will print : +Compiling and running this code reads : -.. literalinclude:: src/sum_functional2.output - - +.. literalinclude:: src/sum_functional.output + + diff --git a/doc/reference/c++/clef/examples/src b/doc/reference/c++/clef/examples/src new file mode 120000 index 00000000..62be4d0e --- /dev/null +++ b/doc/reference/c++/clef/examples/src @@ -0,0 +1 @@ +../../../../../test/triqs/clef_examples/ \ No newline at end of file diff --git a/doc/reference/c++/clef/examples/vector_and_math.rst b/doc/reference/c++/clef/examples/vector_and_math.rst deleted file mode 100644 index 320ba60e..00000000 --- a/doc/reference/c++/clef/examples/vector_and_math.rst +++ /dev/null @@ -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 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, <, >=, <=, ==)` -* 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 x_; - triqs::lazy_expressions::placeholder y_; - -.. warning:: - As a consequence, if you define:: - - triqs::clef::placeholder 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 - 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_) ); - - - - - diff --git a/doc/reference/c++/clef/expressions_eval.rst b/doc/reference/c++/clef/expressions_eval.rst index 7f6808f3..5c3dd9b5 100644 --- a/doc/reference/c++/clef/expressions_eval.rst +++ b/doc/reference/c++/clef/expressions_eval.rst @@ -1,7 +1,7 @@ .. highlight:: c -Evaluating clef expressions +Evaluating CLEF expressions =============================== Forming expressions is nice, but completely useless unless one can *evaluate* them @@ -22,19 +22,21 @@ The evaluation can be : Complete evaluation -------------------- -Example :: - - eval (x_ + 2*y_ , x_=1, y_ = 2) - - auto e = x_ + 2*y_; - auto r = eval( e , x_=1, y_ = 2); +.. compileblock:: + + #include + using namespace triqs::clef; + int main () { + placeholder<1> x_; placeholder<2> y_; + std::cout << eval (x_ + 2*y_ , x_=1, y_ =2) << std::endl; + std::cout << eval (x_ + 2*y_ , y_=2, x_ =1) << std::endl; + } Note that : * The order of placeholder does not matter in calling eval. * It is an error to put the same placeholder twice. -* The correct version of eval is found by ADL (Argument Dependent Lookup). - (It if the clef::eval since arguments are defined in the clef namespace) +* The correct version of eval is found by ADL (Argument Dependent Lookup) in the triqs::clef namespace. Partial evaluation -------------------- diff --git a/doc/reference/c++/clef/expressions_form.rst b/doc/reference/c++/clef/expressions_form.rst index da327d01..1f81d5b1 100644 --- a/doc/reference/c++/clef/expressions_form.rst +++ b/doc/reference/c++/clef/expressions_form.rst @@ -1,28 +1,25 @@ .. highlight:: c -Introduction +Forming CLEF expressions =========================== -The first step consists in forming lazy expressions, before evaluating them. +In this section, we describe how to form CLEF expressions. Placeholders ----------------- +------------------- Loosely speaking, a placeholder is a "variable name" used to build an expression. -Technically, it is a trivial object, with a type but containing no data. Placeholders are declared as :: placeholder Name; -This declares a placeholder called Name (an empty object for C++). - Example :: placeholder <1> x_; placeholder <2> y_; -Note that the only thing of significance in a placeholder is its type, since it contains no data. -In other words, a placeholder is **empty**. It contains **no value** at runtime. +Note that the only thing of significance in a placeholder is its type (i.e. Number). +A placeholder is **empty** : it contains **no value** at runtime. .. warning:: @@ -33,18 +30,62 @@ In other words, a placeholder is **empty**. It contains **no value** at runtime. would imply that `x_` is the same as `y_` : `x_` == `y_` will be always true. Forming an expression -------------------------- +------------------------ -Using simple operators, one can form a more complex expression, e.g.:: +CLEF expressions are made of : + +* Placeholders +* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)` +* Ternary conditional if_else expressions +* Callable objects which overload the operator () for CLEF expressions, See :ref:`callable_object`. +* Functions overloaded for CLEF expressions. For example, the header `math.hpp` contains the declaration to make + the basic function of std `math.h` accept CLEF_expressions. +* In fact, almost anything : the *make_expr* function can be called on any object to make it lazy. + +Examples : + +.. compileblock:: + + #include + #include + using namespace triqs::clef; + int main () { + placeholder<0> i_; placeholder<1> x_; placeholder<2> y_; + std::vector V; + + // arithmetic + auto e = x_ + 2* y_; + + // simple math function + auto e1 = cos(2*x_+1); + auto e2 = abs(2*x_-1); + + // making V lazy + auto e0 = make_expr(V)[i_]; + } + +Note that : + +* Expressions do not compute anything, they just store the expression tree. +* There is no check of correctness here in general : an expression can be well formed, + but meaningless, e.g. :: + + auto e = cos(2*x_, 8); // ! + + +.. highlight:: c + +Storage of expressions [advanced] +----------------------------------- + +CLEF expressions have a complicated (expression template) type encoding the structure of the expression +at compile time:: auto e = x_ + 2* y_; - -e has a complicated type (it is an expression template), which encodes the structure of the expression. -Typically here something like :: - + // the type of e is something like expr, expr > -It is worth noting that : +Note that : * As a user, one *never* has to write such a type One always use expression "on the fly", or use auto. @@ -52,81 +93,27 @@ It is worth noting that : * Having the whole structure of the expression at compile time allows efficient evaluation (it is the principle of expression template : add a ref here). -* Declaring an expression does not do any computation, hence the name of the library (lazy ...). +* Declaring an expression does not do any computation. It just stores the expression tree (its structure in the type, and the leaves of the tree). -What is allowed in clef expressions ? -========================================== +* Every object in the expression tree is captured by : -Expressions are composed of : + * reference it is an lvalue. -* Placeholders -* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)` -* Conditional if_else expressions -* Callable objects (see below) called on expressions - -Callable objects --------------------- - -* Objects can overload the operator () for lazy expressions in order to build more complex - expressions. - -* For example, the header `math.hpp` contains the declaration to make - the basic function of std `math.h` accept lazy_expressions. - - .. compileblock:: + * value it is an rvalue : an rvalue (i.e. a temporary) is *moved* into the tree, using + move semantics. - #include - int main () { - triqs::clef::placeholder <1> x_; + Exceptions : the following objects are always copied : placeholders, expression themselves. - 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); - } + Example :: -* 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 - #include - namespace tql = triqs::clef; - int main () { - std::vector 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 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. + double a = 3; + auto e = a + 2* x_ ; // a is stored by reference (double &), but 2 is stored by value + The rational is as follows : + * rvalue must be moved, otherwise we would keep (dangling) reference to temporaries. + * for lvalue, keeping a reference is quicker. Of course, in the previous example, + it is mandatory that a live longer than e ... + diff --git a/doc/reference/c++/clef/function.rst b/doc/reference/c++/clef/function.rst index 0366b982..ac60e076 100644 --- a/doc/reference/c++/clef/function.rst +++ b/doc/reference/c++/clef/function.rst @@ -1,8 +1,8 @@ .. highlight:: c -Clef expressions vs functions -===================================================================== +Transform CLEF expressions into functions +=============================================== Clef expressions are **NOT** functions. In short, @@ -14,22 +14,12 @@ Clef expressions are **NOT** functions. In short, f(1,2) -It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*, -and back. - -Function to clef expressions -------------------------------------- - -This is immediate, if the function accept lazy arguments, cf :ref:`callable_object`:: - - auto e1 = f(x_); +It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*. +(the opposite is true, if the function accept lazy arguments, cf :ref:`overload_function`). -Transforming clef expressions into functions ----------------------------------------------------- - -make_function -..................... +make_function +--------------- Given any expression with placeholder `x_`, `y_`, `z_`, ..., `make_function` transform them into a regular function. If we say :: @@ -38,41 +28,13 @@ transform them into a regular function. If we say :: then f is :: - a function (placeholder_1, placeholder_2, placeholder_3, ...) --> RESULT + a function (x1,x2,x3) --> RESULT where RESULT is : * the result of the complete evaluation of the expression if the list of placeholder exhausts the placeholders of the expression. * otherwise a clef_expression of the remaining placeholders, returning a **function**. -Examples : - -* With one variable:: - - auto e1 = 2*x_ + 1; - auto f = make_function( e1, x_); - f(3) == 7; // ok - std::function 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 F(f); // ok - -* Make a function partially :: - - auto f = make_function( 2*x_ + y_ + 1, x_); - // f is a lazy expression expression with placeholder y_, returning a function... - auto f1 = eval (f, y_=1); // f1 is a function x-> 2*x + 2 - f1 (10) == 22; - -* Currifying a function :: - auto f = make_function ( make_function( 2*x\_ + y\_ + 1, x\_), y\_); - // f a function y-> x-> 2x+y+1 - // f(y) returns a function x-> 2x+y+1 - Short notation with >> operator ..................................... @@ -95,4 +57,67 @@ For function of *one* variable, the make_function notation can be simplified int is banned because it conflicts with the standard priority of >>. Use parenthesis. +clef::function +-------------------------- + +The class triqs::clef::function stored a function of a given signature +It is similar to std::function but +it can be constructed from an expression and an ordered list of placeholders. + +clef::function can be assigned with the = operator, Cf example below. + +.. note:: + Like std::function, it stores the expression polymorphically, by erasing its type. + This might lead to some performance penalty in some case, even though tests do not show that at present... + + +Examples +--------- + + .. compileblock:: + + #include + #include + 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 F(f); + } + { //with two variables + auto f = make_function(2*x_ + y_ + 1, x_, y_); + std::cout << f(3,4) << std::endl; + std::function 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 f2,g2; + f2(x_,y_) = x_ + y_; + std::cout << f2(2,3) << std::endl; + + std::function sf2 = f2; + std::cout << sf2(2,3) << std::endl; + + g2(x_,y_) = x_ - y_ + f2(x_,2*y_); + + std::function sf = x_>> 2*x_ + 1; + std::cout << sf(3) << std::endl; + } + } diff --git a/doc/reference/c++/clef/introduction.rst b/doc/reference/c++/clef/introduction.rst index 4ce51ca3..a8382d62 100644 --- a/doc/reference/c++/clef/introduction.rst +++ b/doc/reference/c++/clef/introduction.rst @@ -1,15 +1,72 @@ .. highlight:: c -Motivation -======================= +Motivation : a little tour of CLEF +===================================== + +A usual, the best is to start with a few examples, to show the library in action. -The purpose of the Named Parameter Lambda (nplambda) library is to help -the manipulation of formal expressions. +.. compileblock:: + + #include + #include + #include + #include + 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 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 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"<> W(3, std::vector(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 f = i_ >> 2*i_ +1; + // a function (i,j) -> 2*i +j + std::function 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 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 < - #include - 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 - #include - - 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 - #include - - template - typename std::enable_if::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 - - 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::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 - - 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,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,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 :: value // true iif one of the T is a clef expression - -Example, derived from the previous one : - -.. compileblock:: - - #include - #include - - 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 std::enable_if::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::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 ; - } - - diff --git a/doc/reference/c++/clef/lazy_function_cls.rst b/doc/reference/c++/clef/lazy_function_cls.rst deleted file mode 100644 index fdcac15a..00000000 --- a/doc/reference/c++/clef/lazy_function_cls.rst +++ /dev/null @@ -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`. diff --git a/doc/reference/c++/clef/overload.rst b/doc/reference/c++/clef/overload.rst new file mode 100644 index 00000000..94eb219b --- /dev/null +++ b/doc/reference/c++/clef/overload.rst @@ -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 + #include + + // 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 + // T bar (T const & x) { return x+1;} + + // C++11 workaround + template + typename std::enable_if::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)<<" "< + #include + 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 + + 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< // true iif one of the T is a clef expression + + as the `bar` function above. + + diff --git a/test/speed/clef_common.hpp b/test/speed/clef_common.hpp deleted file mode 100644 index 4369a405..00000000 --- a/test/speed/clef_common.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) < - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} - - template friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< 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 "< - typename triqs::clef::result_of::make_expr_call::type - operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);} - - template friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} - - template friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)< x_; -triqs::clef::placeholder <2> y_; -triqs::clef::placeholder <3> z_; -namespace tql= triqs::clef; - diff --git a/test/speed/clef_common.hpp b/test/speed/clef_common.hpp new file mode 120000 index 00000000..ae8455aa --- /dev/null +++ b/test/speed/clef_common.hpp @@ -0,0 +1 @@ +../triqs/clef/common.hpp \ No newline at end of file diff --git a/test/triqs/clef/F7.cpp b/test/triqs/clef/F7.cpp index a9a6efd6..484818ec 100644 --- a/test/triqs/clef/F7.cpp +++ b/test/triqs/clef/F7.cpp @@ -5,13 +5,7 @@ struct F7 { F7(double v_): v(v_){} double operator() (int i1, int i2, int i3, int i4, int i5, int i6, int i7 ) const { return 10*i1;} - template< typename... Args> - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F7); template 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)< - typename triqs::clef::result_of::make_expr_call::type - operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2_vec); template 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";} }; diff --git a/test/triqs/clef/common.hpp b/test/triqs/clef/common.hpp index 4369a405..54b9feaf 100644 --- a/test/triqs/clef/common.hpp +++ b/test/triqs/clef/common.hpp @@ -6,37 +6,17 @@ struct F1{ double v; F1(double v_): v(v_){} F1(F1 const &) = delete; // non copyable + F1(F1 &&x) : v(x.v) { std::cerr << "Moving F1 "<< v< - typename triqs::clef::result_of::make_expr_call,Args...>::type - operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1); - template< typename... Args> - typename triqs::clef::result_of::make_expr_call,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} - - template friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< 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 "< - typename triqs::clef::result_of::make_expr_call::type - operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);} - - template friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2); template friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<> 2*x_ + y_; + std::cout << hh (3,1) << std::endl; + } diff --git a/test/triqs/clef/function.output b/test/triqs/clef/function.output index b66f5012..8144d91e 100644 --- a/test/triqs/clef/function.output +++ b/test/triqs/clef/function.output @@ -9,3 +9,4 @@ lazy function : (_1) --> (((2 * _1) + 1) + 1) (tql::eval( h, y_=1) (10)) ---> 22 (h) ---> lazy function : (_1) --> (((2 * _1) + _2) + 1) +7 diff --git a/test/triqs/clef/general.cpp b/test/triqs/clef/general.cpp index a14761fc..2a4573bf 100644 --- a/test/triqs/clef/general.cpp +++ b/test/triqs/clef/general.cpp @@ -58,31 +58,25 @@ int main() { { // 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 "< > v2 (3, std::vector(2)); - lazy(v2)[i_][j_] << (i_ + j_ + 1); + make_expr(v2)[i_][j_] << (i_ + j_ + 1); for (size_t u=0; u 14 +(tql::eval(make_expr(V) [i_], i_=0)) ---> 14 V = 2 3 4 W = 2 4 6 11 diff --git a/test/triqs/clef/lazy_method.cpp b/test/triqs/clef/lazy_method.cpp new file mode 100644 index 00000000..708d8323 --- /dev/null +++ b/test/triqs/clef/lazy_method.cpp @@ -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 friend void triqs_clef_auto_assign (AA & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< 20 diff --git a/test/triqs/clef/test1.cpp b/test/triqs/clef/test1.cpp index 95c2eb17..8d110541 100644 --- a/test/triqs/clef/test1.cpp +++ b/test/triqs/clef/test1.cpp @@ -13,15 +13,10 @@ struct F1{ F1(F1 const &) = delete; // non copyable double operator() (double x) const { return 10*x;} - template< typename... Args> - typename triqs::clef::result_of::make_expr_call,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,Args...>::type - operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1); template friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)< -#include -// a general implementation type for all domain and summation methods -template struct sum_impl; -struct Riemann{}; // one sum method -template struct sum_impl { +template struct sum_impl { Domain d; - sum_impl(Domain const &d_):d(d_) {} - // Disabled when F is a lazy_expression + // C++14 + // double operator() (NotClefExpression const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;} + + // C++11 form template - typename std::enable_if< !triqs::clef::is_any_lazy ::value, double >::type + typename std::enable_if< !triqs::clef::is_clef_expression ::value, double >::type operator() (F const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;} - // Defines operator(). Enabled iff one argument is a clef expression. - template< typename... Args> - typename triqs::clef::result_of::make_expr_call::type - operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);} + TRIQS_CLEF_IMPLEMENT_LAZY_CALL(sum_impl); - // How to print this object in the printing of clef expression friend std::ostream & operator<<(std::ostream & out, sum_impl const & x) { return out<<"sum";} }; -template -sum_impl sum_functional (Domain && d, Option) {return d;} - -//--------- MAIN --------------------------------------- +// a little factory ... +template sum_impl sum_functional (Domain d) {return {d};} struct DOM{}; int main() { - // two placeholders - triqs::clef::placeholder <1> x_; - triqs::clef::placeholder <2> y_; + triqs::clef::placeholder <1> x_; triqs::clef::placeholder <2> y_; + DOM d; + + // integrate_on_d is the integration functional + auto integrate_on_d = sum_functional(d); - DOM d; // a domain - - // 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 std::cout<< integrate_on_d( x_ >> 2*x_ + 1 ) << std::endl; - // This creates a clef expression of placeholder y_, waiting to make the sum - // Indeed the argument is a clef expression of y_ returning a function - // composed by integrate_on_d, it is a clef expression of y_ returning a double - std::cout<< integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl; - - // Of course this expression can be mixed with others... - std::cout<< y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl; - - // and it can be evaluated - std::cout<< eval (y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) ,y_ =0) << std::endl; + // A function y -> y_ + integrate (x -> 2*x + y) + auto e1 = y_ + integrate_on_d( x_ >> 2*x_ + y_ ); + std::cout<< e1 << std::endl; + std::cout<< eval (e1 ,y_ =0) << std::endl; } diff --git a/test/triqs/clef_examples/sum_functional.output b/test/triqs/clef_examples/sum_functional.output new file mode 100644 index 00000000..b6b39195 --- /dev/null +++ b/test/triqs/clef_examples/sum_functional.output @@ -0,0 +1,3 @@ +19 +(_2 + sum(lazy function : (_1) --> ((2 * _1) + _2))) +9 diff --git a/test/triqs/clef_examples/sum_functional2.output b/test/triqs/clef_examples/sum_functional2.output deleted file mode 100644 index 09cf2939..00000000 --- a/test/triqs/clef_examples/sum_functional2.output +++ /dev/null @@ -1,4 +0,0 @@ -19 -sum(lazy function : (_1) --> (((2 * _1) + 1) + _2)) -(_2 + (2 * sum(lazy function : (_1) --> (((2 * _1) + 1) + _2)))) -38 diff --git a/test/triqs/clef_examples/vector_and_math.cpp b/test/triqs/clef_examples/vector_and_math.cpp index 6998b5c0..1203c36d 100644 --- a/test/triqs/clef_examples/vector_and_math.cpp +++ b/test/triqs/clef_examples/vector_and_math.cpp @@ -10,9 +10,9 @@ int main() { double pi = std::acos(-1); std::vector V(N); - // automatic assignment of vector and use of lazy math function + // automatic assignment of vector and use of make_expr math function tql::placeholder <0> k_; - tql::lazy(V) [k_] << cos( (2* pi* k_)/ N ); + tql::make_expr(V) [k_] << cos( (2* pi* k_)/ N ); // check result... for (size_t u=0; u::type operator()() && { return *this; } + // Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression + // NB : this is ok because indexmap_storage_pair has a shallow copy constructor ... + // Correction : no copy, just a ref... + // so A(i_) if A is an array will NOT copy the data.... + template< typename... Args> + typename clef::_result_of::make_expr_call::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::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::type + operator()( Args&&... args ) && { + static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ... + return make_expr_call(std::move(*this),args...); + } + #else template // non const version @@ -258,18 +283,25 @@ namespace triqs { namespace arrays { typename ISPViewType::type operator()() { return *this; } -#endif // Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression // NB : this is ok because indexmap_storage_pair has a shallow copy constructor ... + // Correction : no copy, just a ref... // so A(i_) if A is an array will NOT copy the data.... template< typename... Args> - typename clef::result_of::make_expr_call::type + typename clef::_result_of::make_expr_call::type operator()( Args&&... args ) const { static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ... return make_expr_call(*this,args...); - //return make_expr_call( view_type(*this),args...); } + template< typename... Args> + typename clef::_result_of::make_expr_call::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 friend void triqs_clef_auto_assign (indexmap_storage_pair & x, Fnt f) { assign_foreach(x,f);} // ------------------------------- Iterators -------------------------------------------- diff --git a/triqs/arrays/make_immutable_array.hpp b/triqs/arrays/make_immutable_array.hpp index 0b162163..320b571e 100644 --- a/triqs/arrays/make_immutable_array.hpp +++ b/triqs/arrays/make_immutable_array.hpp @@ -30,7 +30,7 @@ namespace triqs { namespace arrays { template struct _si { typedef size_t type;}; public : immutable_array_expr_impl(Expr e_, clef::pair ... p): - f(clef::make_function(e_, clef::placeholder()...)), dom_(make_shape(p.rhs().size()...)) {}; + f(clef::make_function(e_, clef::placeholder()...)), dom_(make_shape(p.rhs.size()...)) {}; typedef typename triqs::clef::result_of::make_function... >::type function_type; typedef typename std::result_of::type...)>::type value_type; typedef indexmaps::cuboid::domain_t domain_type; diff --git a/triqs/clef/adapters/math.hpp b/triqs/clef/adapters/math.hpp index e824a4ac..84bcdf2d 100644 --- a/triqs/clef/adapters/math.hpp +++ b/triqs/clef/adapters/math.hpp @@ -23,6 +23,7 @@ #include "../clef.hpp" #include #include +#include #define TRIQS_CLEF_STD_MATH_FNT_TO_MAKE_LAZY (cos)(sin)(tan)(cosh)(sinh)(tanh)(acos)(asin)(atan)(exp)(log)(sqrt)(abs)(floor)(pow) diff --git a/triqs/clef/clef.hpp b/triqs/clef/clef.hpp index 23a31c89..96133a13 100644 --- a/triqs/clef/clef.hpp +++ b/triqs/clef/clef.hpp @@ -2,7 +2,7 @@ * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * - * Copyright (C) 2012 by O. Parcollet + * Copyright (C) 2012-2013 by O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software @@ -21,12 +21,13 @@ #ifndef TRIQS_CLEF_CORE_H #define TRIQS_CLEF_CORE_H #include +#include +#include #include #include #include #include #include -#include #include #include #include @@ -36,109 +37,130 @@ namespace triqs { namespace clef { typedef unsigned long long ull_t; - template struct remove_cv_ref : std::remove_cv< typename std::remove_reference::type> {}; namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; } + // Compute the type to put in the expression tree. + // If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr::value == true + // If T is an rvalue reference, we store it as the type (using move semantics). + template struct force_copy_in_expr : std::false_type{}; + template struct force_copy_in_expr : force_copy_in_expr{}; + + template< class T > struct expr_storage_t {typedef T type;}; + template< class T > struct expr_storage_t : std::conditional::value, T ,std::reference_wrapper>{}; + template< class T > struct expr_storage_t {typedef T type;}; + /* --------------------------------------------------------------------------------------------------- * Placeholder and corresponding traits * --------------------------------------------------------------------------------------------------- */ - template struct pair { - static constexpr int p = i; - typedef typename remove_cv_ref ::type value_type; - value_type const & r; - value_type const & rhs() const { return r;} - pair (T const & t) : r(t){} - }; + template class pair; // forward + // a placeholder is an empty struct, labelled by an int. template struct placeholder { static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); static constexpr int index = N; - template pair operator = (RHS const & rhs) { return pair(rhs);} + template pair operator = (RHS && rhs) { return {std::forward(rhs)};} + }; + + // placeholder will always be copied (they are empty anyway). + template< int N > struct force_copy_in_expr> : std::true_type{}; + + // represent a couple (placeholder, value). + template struct pair { + U rhs; + static constexpr int p = N; + typedef typename remove_cv_ref ::type value_type; }; - template struct is_placeholder : std::false_type {}; - template struct is_placeholder > : std::true_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 template struct ph_set; template struct ph_set{static constexpr ull_t value= ph_set::value| ph_set::value;}; template struct ph_set {static constexpr ull_t value= 0;}; template struct ph_set> {static constexpr ull_t value= 1ull< struct ph_set > : ph_set>{}; - /* --------------------------------------------------------------------------------------------------- - * Detect if an object is a lazy expression - * --------------------------------------------------------------------------------------------------- */ - template struct is_any_lazy : std::false_type {}; - template struct is_any_lazy > : std::true_type {}; - template struct is_any_lazy< T > : std::false_type {}; - template struct is_any_lazy< T&& > : is_any_lazy {}; - template struct is_any_lazy< T& > : is_any_lazy {}; - template struct is_any_lazy< T const > : is_any_lazy {}; - template struct is_any_lazy : + // in_any_lazy : trait to detect if any of Args is a lazy expression + template struct is_any_lazy : std::false_type {}; + template struct is_any_lazy > : std::true_type {}; + template struct is_any_lazy< T > : std::false_type {}; + template struct is_any_lazy< T&& > : is_any_lazy {}; + template struct is_any_lazy< T& > : is_any_lazy {}; + template struct is_any_lazy< T const > : is_any_lazy {}; + template struct is_any_lazy : std::integral_constant::value || is_any_lazy::value> {}; - // a trait that checks the type are value i.e. no &, && - template struct has_no_ref : std::true_type {}; - template struct has_no_ref : std::integral_constant::value)&& has_no_ref::value> {}; + template + constexpr bool ClefExpression() { return is_any_lazy::value;} - /* --------------------------------------------------------------------------------------------------- + template struct is_clef_expression : is_any_lazy{}; + +/* --------------------------------------------------------------------------------------------------- * Node of the expression tree * --------------------------------------------------------------------------------------------------- */ template struct expr { - static_assert( has_no_ref::value , "Internal error : expr childs can not be reference "); - typedef std::tuple< T ...> childs_t; + // T can be U, U & (a reference or a value). + typedef std::tuple childs_t; childs_t childs; expr(expr const & x) = default; - expr(expr && x) : childs(std::move(x.childs)) {} - template explicit expr(Tag, Args&&...args) : childs(std::forward(args)...) {} - template< typename Args > - expr::type > operator[](Args && args) const - { return expr::type> (tags::subscript(), *this,std::forward(args));} + expr(expr && x) noexcept : childs(std::move(x.childs)) {} + // a constructor with the Tag make it unambiguous with other constructors... + template expr(Tag, Args&&...args) : childs(std::forward(args)...) {} + // [] returns a new lazy expression, with one more layer + template + expr::type > operator[](Args && args) const + { return {tags::subscript(), *this,std::forward(args)};} + // () also ... template< typename... Args > - expr::type...> operator()(Args && ... args) const - { return expr::type...>(tags::function(), *this,std::forward(args)...);} - // only f(i,j) = expr is allowed, in case where f is a clef::function - // otherwise use the << operator + expr::type...> operator()(Args && ... args) const + { return {tags::function(), *this,std::forward(args)...};} + // assignement is in general deleted + expr & operator= (expr const &) = delete; // no ordinary assignment + expr & operator= (expr &&) = default; // move assign ok + // however, this is ok in the case f(i,j) = expr, where f is a clef::function template - typename std::enable_if::type>::value>::type + ENABLE_IF(std::is_base_of::type>) operator= (RHS const & rhs) { *this << rhs;} template - typename std::enable_if::type>::value>::type + DISABLE_IF(std::is_base_of::type>) operator= (RHS const & rhs) = delete; - expr & operator= (expr const & ) = delete; // no ordinary copy }; + // set some traits template struct ph_set< expr > : ph_set {}; template struct is_any_lazy< expr >: std::true_type {}; + // if we want that subexpression are copied ? + template struct force_copy_in_expr< expr > : std::true_type{}; /* --------------------------------------------------------------------------------------------------- * The basic operations put in a template.... * --------------------------------------------------------------------------------------------------- */ template struct operation; - + + // a little function to clean the reference_wrapper + template U & _cl(U & x) { return x;} + template U & _cl(std::reference_wrapper x) { return x.get();} + /// Terminal template<> struct operation { template L operator()(L&& l) const { return std::forward(l);} }; /// Function call template<> struct operation { - template auto operator()(F const & f, Args const & ... args) const -> decltype(f(args...)) { return f(args...);} - template auto operator()(std::reference_wrapper const &f, Args const & ... args) const -> decltype(f.get()(args...)) { return f.get()(args...);} + template auto operator()(F const & f, Args const & ... args) const DECL_AND_RETURN(_cl(f)(_cl(args)...)); }; /// [ ] Call template<> struct operation { - template auto operator()(F const & f, Args const & args) const -> decltype(f[args]) { return f[args];} - template auto operator()(std::reference_wrapper const &f, Args const & args) const -> decltype(f.get()[args]) { return f.get()[args];} + template auto operator()(F const & f, Args const & args) const DECL_AND_RETURN(_cl(f)[_cl(args)]); }; // all binary operators.... #define TRIQS_CLEF_OPERATION(TAG,OP)\ namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ template<> struct operation {\ - template auto operator()(L const & l, R const & r) const -> decltype(l OP r) { return l OP r;}\ + template auto operator()(L const & l, R const & r) const DECL_AND_RETURN ( _cl(l) OP _cl(r));\ };\ template\ - typename std::enable_if::value, expr::type,typename remove_cv_ref::type> >::type \ - operator OP (L && l, R && r) { return expr::type,typename remove_cv_ref::type> (tags::TAG(),std::forward(l),std::forward(r));}\ + typename std::enable_if::value, expr::type,typename expr_storage_t::type> >::type \ + operator OP (L && l, R && r) { return {tags::TAG(),std::forward(l),std::forward(r)};}\ TRIQS_CLEF_OPERATION(plus, +); TRIQS_CLEF_OPERATION(minus, -); @@ -155,11 +177,11 @@ namespace triqs { namespace clef { #define TRIQS_CLEF_OPERATION(TAG,OP)\ namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\ template<> struct operation {\ - template auto operator()(L const & l) const -> decltype(OP l) { return OP l;}\ + template auto operator()(L const & l) const DECL_AND_RETURN (OP _cl(l));\ };\ template\ - typename std::enable_if::value, expr::type> >::type \ - operator OP (L && l) { return expr::type> (tags::TAG(),std::forward(l));}\ + typename std::enable_if::value, expr::type> >::type \ + operator OP (L && l) { return {tags::TAG(),std::forward(l)};}\ TRIQS_CLEF_OPERATION(negate, -); TRIQS_CLEF_OPERATION(loginot, !); @@ -167,17 +189,12 @@ namespace triqs { namespace clef { /// the only ternary node : expression if template<> struct operation { - template auto operator()(C const & c, A const & a, B const & b) const -> decltype((c?a:b)) { - //static_assert(std::is_same::type,typename remove_cv_ref::type>::value, "Expression if : evaluation type must be the same"); - return (c ? a: b); - } + template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); }; // operator is : if_else( Condition, A, B) template - expr::type,typename remove_cv_ref::type,typename remove_cv_ref::type> - if_else(C && c, A && a, B && b) { - return expr::type,typename remove_cv_ref::type,typename remove_cv_ref::type> - (tags::if_else(),std::forward(c),std::forward(a),std::forward(b));} + expr::type,typename expr_storage_t::type,typename expr_storage_t::type> + if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward(c),std::forward(a),std::forward(b)};} /* --------------------------------------------------------------------------------------------------- * Evaluation of the expression tree. @@ -186,18 +203,18 @@ namespace triqs { namespace clef { template struct operation2; template struct operation2 { typedef expr::type ...> rtype; - rtype operator()(Args && ... args) const {return rtype (Tag(), std::forward(args)...);} + rtype operator()(Args const & ... args) const {return rtype {Tag(), args...};} }; template struct operation2 { typedef typename std::remove_reference(Args...)>::type>::type rtype; // remove the reference because of ternary if_else in which decltype returns a ref... - rtype operator()(Args const & ... args) const {return operation()(args...); } + rtype operator()(Args const & ... args) const {return operation()(args...); } }; // Generic case : do nothing (for the leaf of the tree except placeholder) template struct evaluator{ typedef T rtype; - rtype operator()( T const & k, Pairs const &... pairs) {return k;} + rtype operator()(T const & k, Pairs const &... pairs) {return k;} }; // placeholder @@ -207,40 +224,53 @@ namespace triqs { namespace clef { rtype operator()(placeholder, pair const &, Pairs const& ... pairs) { return eval_t()(placeholder(), pairs...);} }; template struct evaluator< placeholder, pair, Pairs... > { - typedef typename pair::value_type const & rtype; - rtype operator()(placeholder, pair const & p, Pairs const& ...) { return p.r;} + typedef T const & rtype; + //typedef typename pair::value_type const & rtype; + rtype operator()(placeholder, pair const & p, Pairs const& ...) { return p.rhs;} }; // general expr node template struct evaluator, Pairs...> { typedef operation2::rtype... >::value, typename evaluator::rtype... > OPTYPE; typedef typename OPTYPE::rtype rtype; + + // first done manually for clearer error messages ... + template< int arity = sizeof...(Childs)> + typename std::enable_if< arity==1, rtype>::type + operator()(expr 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 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

(ex.childs),pairs...) #define IMPL(z, NN, unused) \ template< int arity = sizeof...(Childs)>\ typename std::enable_if< arity==NN, rtype>::type\ operator()(expr const & ex, Pairs const & ... pairs) const\ { return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));} - BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); + BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); #undef AUX #undef IMPL }; +#ifdef TRIQS_CLEF_EVAL_SHORT_CIRCUIT + // A short circuit if intersection of ph and is 0, no need to evaluate the whole tree...... + // Seems useless, && the second eval is not correct if hte expression is a terminal. + template + typename std::enable_if< (ph_set::value & ph_set::value) !=0, typename evaluator::rtype > ::type + eval (T const & ex, Pairs const &... pairs) { return evaluator()(ex, pairs...); } + + template + typename std::enable_if< (ph_set::value & ph_set::value) ==0, T const &> ::type + eval (T const & ex, Pairs const &... pairs) { return ex;} +#else // The general eval function for expressions template typename evaluator::rtype eval (T const & ex, Pairs const &... pairs) { return evaluator()(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 - template - typename std::enable_if< (ph_set::value & ph_set::value) !=0, typename evaluator,Pairs...>::rtype > ::type - eval (expr const & ex, Pairs const &... pairs) { return evaluator, Pairs...>()(ex, pairs...); } - - template - typename std::enable_if< (ph_set::value & ph_set::value) ==0, expr > ::type - eval (expr const & ex, Pairs const &... pairs) { return ex; } #endif /* --------------------------------------------------------------------------------------------------- @@ -252,29 +282,30 @@ namespace triqs { namespace clef { make_fun_impl(Expr const & ex_) : ex(ex_) {} // gcc 4.6 crashes (!!!) on the first variant -#define TRIQS_WORKAROUND_GCC46BUG -#ifndef TRIQS_WORKAROUND_GCC46BUG +#ifndef TRIQS_COMPILER_OBSOLETE_GCC template typename evaluator...>::rtype - operator()(Args const &... args) const - { return evaluator...>() ( ex, pair(args)...); } + operator()(Args &&... args) const + { return evaluator...>() ( ex, pair{std::forward(args)}...); } #else template struct __eval { typedef evaluator...> eval_t; typedef typename eval_t::rtype rtype; - rtype operator()(Expr const &ex , Args const &... args) const { return eval_t() ( ex, pair(args)...); } + rtype operator()(Expr const &ex , Args &&... args) const { return eval_t() ( ex, pair{std::forward(args)}...); } }; template - typename __eval::rtype operator()(Args const &... args) const { return __eval() ( ex, args...); } + typename __eval::rtype operator()(Args &&... args) const { return __eval() ( ex, std::forward(args)...); } #endif }; + // values of the ph, excluding the Is ... template struct ph_filter; template struct ph_filter { static constexpr ull_t value = ph_filter::value & (~ (1ull< struct ph_filter { static constexpr ull_t value = x; }; template< typename Expr, int... Is> struct ph_set > { static constexpr ull_t value = ph_filter ::value, Is...>::value;}; template< typename Expr, int... Is> struct is_any_lazy > : std::integral_constant>::value !=0>{}; + template< typename Expr, int... Is> struct force_copy_in_expr > : std::true_type{}; template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { typedef evaluator e_t; @@ -283,22 +314,28 @@ namespace triqs { namespace clef { }; template< typename Expr, typename ... Phs> - make_fun_impl::type>::type,Phs::index...> + make_fun_impl::type,Phs::index...> make_function(Expr && ex, Phs...) { return {ex}; } namespace result_of { template< typename Expr, typename ... Phs> struct make_function { - typedef make_fun_impl::type>::type,Phs::index...> type; + typedef make_fun_impl::type,Phs::index...> type; }; } + template + std::tuple...> var( placeholder ...) { return std::make_tuple(placeholder()...);} + + template + auto operator >> (std::tuple...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder()...)); + /* -------------------------------------------------------------------------------------------------- * make_function * x_ >> expression is the same as make_function(expression,x) * --------------------------------------------------------------------------------------------------- */ template - make_fun_impl operator >> ( placeholder p, Expr&& ex) { return {ex}; } + make_fun_impl operator >> (placeholder p, Expr&& ex) { return {ex}; } /* --------------------------------------------------------------------------------------------------- * Auto assign for () @@ -315,7 +352,7 @@ namespace triqs { namespace clef { template void triqs_clef_auto_assign (expr && ex, RHS const & rhs) { ex << rhs;} - template + template void triqs_clef_auto_assign (expr const & ex, RHS const & rhs) { ex << rhs;} // The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL) @@ -327,6 +364,10 @@ namespace triqs { namespace clef { void operator<<(expr...> const & ex, RHS && rhs) { triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); } + template + void operator<<(expr...> & ex, RHS && rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } // any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop template @@ -348,6 +389,9 @@ namespace triqs { namespace clef { { triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward(f));} // auto assign of an expr ? (for chain calls) : just reuse the same operator + template + void triqs_clef_auto_assign_subscript (expr && ex, RHS const & rhs) { ex << rhs;} + template void triqs_clef_auto_assign_subscript (expr const & ex, RHS const & rhs) { ex << rhs;} @@ -356,45 +400,58 @@ namespace triqs { namespace clef { void operator<<(expr...> const & ex, RHS && rhs) { triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); } - template + template + void operator<<(expr...> && ex, RHS && rhs) { + triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + + template + void operator<<(expr && ex, RHS && rhs) = delete; + + template void operator<<(expr 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 expr::type > - make_expr(T && x){ return expr::type >(tags::terminal(), std::forward(x));} + // make a node with the ref, unless it is an rvalue (which is moved). + template expr::type > + make_expr(T && x){ return {tags::terminal(), std::forward(x)};} - template 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 expr::type > + make_expr_from_clone(T && x){ return {tags::terminal(), std::forward(x)};} /* -------------------------------------------------------------------------------------------------- * Create a call node of an object * The object can be kept as a : a ref, a copy, a view * --------------------------------------------------------------------------------------------------- */ - namespace result_of { + template struct arity { static constexpr int value =-1;}; + + namespace _result_of { template< typename Obj, typename... Args > struct make_expr_call : - std::enable_if< is_any_lazy::value, expr::type, typename remove_cv_ref::type ...> > {}; + std::enable_if< is_any_lazy::value, expr::type, typename expr_storage_t::type ...> > { + static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); + }; } template< typename Obj, typename... Args > - typename result_of::make_expr_call::type - make_expr_call(Obj&& obj, Args &&... args) - { return typename result_of::make_expr_call::type (tags::function(),std::forward(obj), std::forward(args)...);} + typename _result_of::make_expr_call::type + make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward(obj), std::forward(args)...};} /* -------------------------------------------------------------------------------------------------- * Create a [] call (subscript) node of an object * The object can be kept as a : a ref, a copy, a view * --------------------------------------------------------------------------------------------------- */ - namespace result_of { + namespace _result_of { template< typename Obj, typename Arg> struct make_expr_subscript : - std::enable_if< is_any_lazy::value, expr::type, typename remove_cv_ref::type> > {}; + std::enable_if< is_any_lazy::value, expr::type, typename expr_storage_t::type> > {}; } template< typename Obj, typename Arg> - typename result_of::make_expr_subscript::type - make_expr_subscript(Obj&& obj, Arg && arg) - { return typename result_of::make_expr_subscript::type (tags::subscript(),std::forward(obj), std::forward(arg));} + typename _result_of::make_expr_subscript::type + make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward(obj), std::forward(arg)};} /* -------------------------------------------------------------------------------------------------- * function class : stores any expression polymorphically @@ -408,23 +465,30 @@ namespace triqs { namespace clef { mutable std::shared_ptr _exp; // CLEAN THIS MUTABLE ? mutable std::shared_ptr < std_function_type > _fnt_ptr; public: - function():_fnt_ptr(new std_function_type ()){} + function():_fnt_ptr{std::make_shared ()}{} template explicit function(Expr const & _e, X... x) : _exp(new Expr(_e)),_fnt_ptr(new std_function_type(make_function(_e, x...))){} ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);} +#ifndef TRIQS_COMPILER_OBSOLETE_GCC template< typename... Args> - typename triqs::clef::result_of::make_expr_call::type - operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);} + auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...)); +#else + template< typename... Args> + typename _result_of::make_expr_call::type + operator()( Args&&... args ) const { return make_expr_call (*this,args...);} +#endif template friend void triqs_clef_auto_assign (function const & x, RHS rhs) { * (x._fnt_ptr) = std_function_type (rhs); x._exp = std::shared_ptr (new typename std::remove_cv::type (rhs.ex)); } - }; + }; + template struct force_copy_in_expr > : std::true_type{}; + /* -------------------------------------------------------------------------------------------------- * The macro to make any function lazy * TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace @@ -433,11 +497,54 @@ namespace triqs { namespace clef { * --------------------------------------------------------------------------------------------------- */ #define TRIQS_CLEF_MAKE_FNT_LAZY(name)\ struct name##_lazy_impl { \ - template auto operator()(A&&... a) const -> decltype (name(std::forward(a)...)) { return name(std::forward(a)...); }\ + template auto operator()(A&&... a) const DECL_AND_RETURN (name(std::forward(a)...));\ };\ template< typename... A> \ - typename triqs::clef::result_of::make_expr_call::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)...)); + +#ifndef TRIQS_COMPILER_OBSOLETE_GCC + + #define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\ + struct __clef_lazy_method_impl_##name { \ + TY * _x;\ + template auto operator()(A&&... a) const DECL_AND_RETURN ((*_x).name(std::forward(a)...));\ + friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out< \ + auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward(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)...));\ + \ + template< typename... Args>\ + auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...));\ + \ + template< typename... Args>\ + auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward(args)...));\ + +#else + +#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name,RETURN_TYPE)\ + struct __clef_lazy_method_impl_##name { \ + TY * _x;\ + template RETURN_TYPE operator()(A&&... a) const {return ((*_x).name(std::forward(a)...));}\ + friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out< \ + 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)...);} + +#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(TY)\ + template< typename... Args>\ + typename triqs::clef::_result_of::make_expr_call::type\ + operator()(Args&&... args ) const {return make_expr_call (*this,std::forward(args)...);}\ + \ + template< typename... Args>\ + typename triqs::clef::_result_of::make_expr_call::type\ + operator()(Args&&... args ) {return make_expr_call (*this,std::forward(args)...);} + +#endif }} // namespace triqs::clef - #endif diff --git a/triqs/clef/io.hpp b/triqs/clef/io.hpp index c1204b56..8b92c32c 100644 --- a/triqs/clef/io.hpp +++ b/triqs/clef/io.hpp @@ -31,6 +31,7 @@ namespace triqs { namespace clef { template std::ostream &operator <<(std::ostream &sout, placeholder ){return sout << "_"< std::ostream & operator<<(std::ostream & out, std::reference_wrapper const & x) { return out<< x.get(); } + //template std::ostream & operator<<(std::ostream & out, std::reference_wrapper const & x) { return out<< "["< std::ostream & variadic_print(std::ostream& out, T0&& t0, T&&... t) diff --git a/triqs/gfs/gf.hpp b/triqs/gfs/gf.hpp index 6c9c0f58..f2422468 100644 --- a/triqs/gfs/gf.hpp +++ b/triqs/gfs/gf.hpp @@ -186,26 +186,31 @@ namespace triqs { namespace gfs { operator() (Arg0&& arg0, Args&&... args) const { return _evaluator(this,std::forward( arg0), std::forward(args)...); } // Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression + //template + // auto operator()(Arg0 arg0, Args... args) const DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...)); + + //template + // auto operator()(Arg0 arg0, Args... args) DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...)); + template - typename clef::result_of::make_expr_call::type - //typename clef::result_of::make_expr_call::type + typename clef::_result_of::make_expr_call::type operator()(Arg0 arg0, Args... args) const { return clef::make_expr_call(view_type(*this),arg0, args...); } - + /* // on mesh component for composite meshes // enable iif the first arg is a mesh_point_t for the first component of the mesh_t template::value > - typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type - operator() (Arg0 const & arg0, Args const & ... args) - { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} + typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type + operator() (Arg0 const & arg0, Args const & ... args) + { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} template::value > - typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type - operator() (Arg0 const & arg0, Args const & ... args) const - { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} -*/ + typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type + operator() (Arg0 const & arg0, Args const & ... args) const + { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} + */ //// [] and access to the grid point typedef typename std::result_of::type r_type; @@ -223,14 +228,29 @@ namespace triqs { namespace gfs { cr_type operator[] (closest_pt_wrap const & p) const { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point::invoke(this,p)));} // Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression + /* template + typename boost::lazy_enable_if< // enable the template if + clef::is_any_lazy, // One of Args is a lazy expression + clef::_result_of::make_expr_subscript + >::type // end of lazy_enable_if + operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward(arg));} + */ + + /*template + //auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward(arg))); + auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward(arg))); + template - typename boost::lazy_enable_if< // enable the template if - clef::is_any_lazy, // One of Args is a lazy expression - clef::result_of::make_expr_subscript - >::type // end of lazy_enable_if + //auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward(arg))); + auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward(arg))); + */ + + template + typename clef::_result_of::make_expr_subscript::type operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward(arg));} /// A direct access to the grid point + template r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward(args)...)));} @@ -418,8 +438,8 @@ namespace triqs { namespace gfs { return gf_view(g.mesh(), g.data()(range(), args... ), sg, g.symmetry()); } - // a scalar_valued gf can be viewed as a 1x1 matrix - template + // a scalar_valued gf can be viewed as a 1x1 matrix + template gf_view reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl const & g) { typedef arrays::array_view::storage_t::value_type,3> a_t; auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector(g.data().shape()[0],1,1)), g.data().storage()}; diff --git a/triqs/utility/compiler_details.hpp b/triqs/utility/compiler_details.hpp index 9273c956..c4a0f5e7 100644 --- a/triqs/utility/compiler_details.hpp +++ b/triqs/utility/compiler_details.hpp @@ -32,20 +32,11 @@ #if GCC_VERSION < 40801 //#warning "gcc compiler" GCC_VERSION #define TRIQS_COMPILER_IS_OBSOLETE +#define TRIQS_COMPILER_OBSOLETE_GCC // we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11 #endif #endif -#ifdef __GXX_EXPERIMENTAL_CXX0X__ -#define TRIQS_USE_STATIC_ASSERT -//#define USE_VARIADIC_TEMPLATES -#endif - -#ifndef TRIQS_USE_STATIC_ASSERT -#include "boost/static_assert.hpp" -#define static_assert(X,MESS) BOOST_STATIC_ASSERT((X)) -#endif - #endif diff --git a/triqs/utility/macros.hpp b/triqs/utility/macros.hpp index 8bc662bf..16fceca7 100644 --- a/triqs/utility/macros.hpp +++ b/triqs/utility/macros.hpp @@ -36,5 +36,9 @@ #define DECL_AND_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__;} +namespace triqs { + template struct remove_cv_ref : std::remove_cv< typename std::remove_reference::type> {}; +}; + #endif