mirror of
https://github.com/triqs/dft_tools
synced 2024-12-25 05:43:40 +01:00
clef : new version using lvalues and moving rvalues
- change : all objects are by default stored now by reference, not by copy any more. Unless the trait force_copy_in_expr is true. - rvalue refs are moved into the tree - simplifies a lot the writing of lazy method, objects. - added a macro for methods - tests ok. Further check needed to control absence of copies... - improved documentation
This commit is contained in:
parent
27be5cbd5b
commit
2c542647fd
@ -1,58 +1,70 @@
|
|||||||
.. highlight:: c
|
.. 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,
|
||||||
x_ -> some_expression_of_x_
|
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.
|
This statement simply will be rewritten by the CLEF library as ::
|
||||||
A determines the range of value of x on which the function is called.
|
|
||||||
|
|
||||||
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::
|
.. 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 Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
|
||||||
template< typename... Args>
|
std::cout<< " called triqs_clef_auto_assign "<< f(x.v++)<<std::endl;
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
|
}
|
||||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
|
|
||||||
|
|
||||||
// The non const version (which then stores a non-const reference ....)
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
|
|
||||||
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
|
|
||||||
|
|
||||||
template<typename Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
|
|
||||||
x.v++; std::cout<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;
|
|
||||||
}
|
|
||||||
friend std::ostream & triqs_clef_formal_print(std::ostream & out, Obj const & x) {return out<<"Obj";}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
Copy policy in building expressions [Advanced]
|
|
||||||
====================================================
|
|
||||||
|
|
||||||
When building expressions, a problem can appear for the object at the leaves of the expressions tree
|
|
||||||
(scalar, placeholders, various callable objects, etc...).
|
|
||||||
|
|
||||||
The question is whether they should be captured by value or by reference.
|
|
||||||
|
|
||||||
In the lazy library, the choice has been made to capture them **by value**.
|
|
||||||
|
|
||||||
This means that, by default, *all objects appearing in a lazy expression are copied, rather than captured by reference*.
|
|
||||||
|
|
||||||
This is necessary to store expressions (with auto like above) for future reuse, transform them into new expressions
|
|
||||||
(e.g. make partial evaluation). Expressions are objects.
|
|
||||||
Capturing the leaves by reference easily produces dangling references.
|
|
||||||
[Basically, an expression is a function of its placeholder. The leaves are the parameters of the function,
|
|
||||||
they must leave as long as the expression live. In other words, we need to have a closure of the function].
|
|
||||||
|
|
||||||
The drawback of this approach is that it can generate unless copies of large objects.
|
|
||||||
There are several solutions to this issue :
|
|
||||||
|
|
||||||
* The object is very small (like a double), hence making a copy in not a problem.
|
|
||||||
* You *know* that the object `A` will survive the expression, so using a reference is not a problem.
|
|
||||||
You can use the `lazy(A)` expression that will wrap the reference to the object.
|
|
||||||
* The object has a compagnon view object (like array, array_view). In this case,
|
|
||||||
one wishes to put a view of the object rather than a copy in the expression.
|
|
||||||
There are two cases.
|
|
||||||
|
|
||||||
* TRIQS objects like array, matrix, vector will do it automatically.
|
|
||||||
|
|
||||||
* For another object, if the object defines the tag `has_view_type_tag` as ::
|
|
||||||
|
|
||||||
typedef void has_view_type_tag;
|
|
||||||
typedef MY_VIEW_TYPE view_type;
|
|
||||||
|
|
||||||
the instance of the object will be replaced by an instance of its view_type in building the expression.
|
|
||||||
|
|
||||||
For an illustration, Cf....
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
|||||||
.. highlight:: c
|
.. 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
|
|
||||||
|
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
.. highlight:: c
|
|
||||||
|
|
||||||
.. _lazy_function_ex:
|
|
||||||
|
|
||||||
Using clef::function
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
The following code :
|
|
||||||
|
|
||||||
.. literalinclude:: src/lazyfunction.cpp
|
|
||||||
|
|
||||||
will print :
|
|
||||||
|
|
||||||
.. literalinclude:: src/lazyfunction2.output
|
|
||||||
|
|
@ -3,18 +3,13 @@
|
|||||||
A lazy sum
|
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
|
||||||
|
|
||||||
|
|
||||||
|
1
doc/reference/c++/clef/examples/src
Symbolic link
1
doc/reference/c++/clef/examples/src
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../../test/triqs/clef_examples/
|
@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
.. highlight:: c
|
|
||||||
|
|
||||||
std::vector and math
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
A simple example using std::vector.
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include "triqs/clef.hpp"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
// init some variables
|
|
||||||
int N = 10; double pi = std::acos(-1); std::vector<double> V(N);
|
|
||||||
|
|
||||||
// Filling the vector automatically from an expression of k_
|
|
||||||
triqs::clef::placeholder<0> k_;
|
|
||||||
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N );
|
|
||||||
|
|
||||||
// check result...
|
|
||||||
for (size_t u=0; u<V.size(); ++u)
|
|
||||||
std::cout<< u << " "<<V[u]<< " "<< cos((2*pi*u)/N)<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
|||||||
.. highlight:: c
|
|
||||||
|
|
||||||
Forming lazy expressions
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Expressions are composed from :
|
|
||||||
|
|
||||||
* Placeholders
|
|
||||||
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
|
|
||||||
* Callable objects (see below) called on expressions
|
|
||||||
* Conditional if_else expressions
|
|
||||||
|
|
||||||
Placeholders
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Placeholders are only defined by their type, they contain no data ::
|
|
||||||
|
|
||||||
triqs::lazy_expressions::placeholder <DOM,1> x_;
|
|
||||||
triqs::lazy_expressions::placeholder <DOM,2> y_;
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
As a consequence, if you define::
|
|
||||||
|
|
||||||
triqs::clef::placeholder <DOM,2> y_;
|
|
||||||
|
|
||||||
then `x_` is the same as `y_` : `x_` == `y_` will be always true.
|
|
||||||
|
|
||||||
|
|
||||||
Callable objects
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* The header `math.hpp` contains the declaration to make
|
|
||||||
the basic function of std `math.h` accept lazy_expressions.
|
|
||||||
Example ::
|
|
||||||
|
|
||||||
#include <triqs/clef/math.hpp>
|
|
||||||
cos(2*x_+1) (x_=2) ;
|
|
||||||
abs(2*x_-1) (x_=2) ;
|
|
||||||
floor(2*x_-1) (x_=2.3) ;
|
|
||||||
pow(2*x_+1,2) (x_=2) ;
|
|
||||||
|
|
||||||
|
|
||||||
* To make your object callable, or to overload a function to accept lazy argument, see :ref:`callable_object`.
|
|
||||||
|
|
||||||
|
|
||||||
Copy policy
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. warning:: All objects appearing in a lazy expressions are copied, rather than captured by reference.
|
|
||||||
|
|
||||||
This is necessary to store expressions, make partial evaluation.
|
|
||||||
In order to avoid unncessary copies for large objects, it is necessary to use view type objects ( or shared_ptr).
|
|
||||||
|
|
||||||
**NB** : for array, matrix, vector of the triqs::arrays library, this is automatic : triqs::clef
|
|
||||||
takes a *view* of the objects when building the expression tree.
|
|
||||||
|
|
||||||
Evaluating lazy expressions
|
|
||||||
===============================
|
|
||||||
|
|
||||||
Complete evaluation
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Expressions are evaluated used named arguments, following the pattern ::
|
|
||||||
|
|
||||||
expression ( placeholder_1 = value_1, placeholder_2 = value_2, ...)
|
|
||||||
|
|
||||||
Example ::
|
|
||||||
|
|
||||||
(x_ + 2*y_) ( x_=1, y_ = 2)
|
|
||||||
|
|
||||||
// or (in C++11)
|
|
||||||
auto e = x_ + 2*y_;
|
|
||||||
auto r = e ( x_=1, y_ = 2);
|
|
||||||
|
|
||||||
Note that :
|
|
||||||
|
|
||||||
* The order of placeholder does not matter
|
|
||||||
* It is an error to put the same placeholder twice.
|
|
||||||
|
|
||||||
Partial evaluation
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
The evaluation can also be partial, in which case the compiler replaces the placeholder whose value is provided
|
|
||||||
and rebuild a new expression tree.
|
|
||||||
|
|
||||||
Example ::
|
|
||||||
|
|
||||||
auto expr = x_ + 2*y_;
|
|
||||||
expr (x_ =1); // ---> 1 + (2 * y_)
|
|
||||||
expr (x_ =x_ + y_); // ---> ((x_ + y_) + (2 * y_))
|
|
||||||
expr(x_ =x_ + y_)( x_ = 1, y_ = 2)); //---> 7
|
|
||||||
|
|
||||||
During the partial evaluation, all subtrees that can evaluated are evaluated.
|
|
||||||
For example ::
|
|
||||||
|
|
||||||
(x_ + f(y_)) (y_=1); // --> x + f(1)
|
|
||||||
|
|
||||||
Assignment
|
|
||||||
------------
|
|
||||||
|
|
||||||
Some objects are `lazy-assignable`, which means that calling them on placeholders is a possible LHS.
|
|
||||||
Expressions like ::
|
|
||||||
|
|
||||||
F(x_,y_) = an_expression_of(x_,y_);
|
|
||||||
|
|
||||||
are rewritten by the compiler into ::
|
|
||||||
|
|
||||||
F.set_from( make_function( an_expression_of(x_,y_), x_, y_) );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
.. highlight:: c
|
.. 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
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -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_;
|
||||||
|
|
||||||
|
// 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_;
|
auto e = x_ + 2* y_;
|
||||||
|
// the type of e is something like
|
||||||
e has a complicated type (it is an expression template), which encodes the structure of the expression.
|
|
||||||
Typically here 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
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* 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::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
Exceptions : the following objects are always copied : placeholders, expression themselves.
|
||||||
int main () {
|
|
||||||
triqs::clef::placeholder <1> x_;
|
|
||||||
|
|
||||||
auto e1 = cos(2*x_+1);
|
Example ::
|
||||||
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`.
|
double a = 3;
|
||||||
|
auto e = a + 2* x_ ; // a is stored by reference (double &), but 2 is stored by value
|
||||||
*lazy* function
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
The *lazy* function can be called on any object to make it lazy, e.g.
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
#include <vector>
|
|
||||||
namespace tql = triqs::clef;
|
|
||||||
int main () {
|
|
||||||
std::vector<int> V;
|
|
||||||
tql::placeholder<1> i_;
|
|
||||||
auto e1 = tql::lazy(V)[i_];
|
|
||||||
}
|
|
||||||
|
|
||||||
Copy policy in building expressions
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
A central question when forming expressions is whether the object at the leaves of the expressions tree
|
|
||||||
(scalar, placeholders, various callable objects, etc...) should be captured by value or by reference.
|
|
||||||
|
|
||||||
In the clef library, the choice has been made to capture them **by value**, i.e. :
|
|
||||||
|
|
||||||
*By default, all objects appearing in a clef expression are* **copied**, *rather than captured by reference*.
|
|
||||||
|
|
||||||
This is necessary to store expressions (with auto like above) for future reuse, transform them into new expressions
|
|
||||||
(e.g. make partial evaluation). Expressions are ordinary objects.
|
|
||||||
If the leaves of the expression tree were captured by reference, a guarantee would have to be made that
|
|
||||||
they will live at least as long as the expression itself, or one gets dangling references.
|
|
||||||
|
|
||||||
The drawback of this approach is that it can generate useless copies of large objects.
|
|
||||||
There are two simple solutions to this issue :
|
|
||||||
|
|
||||||
* If you *know* that the object `A` will survive the expression, so using a reference is not a problem
|
|
||||||
and use std::reference_wrapper<A> instead of A in the tree.
|
|
||||||
|
|
||||||
* If the object has a compagnon view object (like array, array_view). In this case,
|
|
||||||
one wishes to put a view of the object rather than a copy in the expression.
|
|
||||||
|
|
||||||
|
The rational is as follows :
|
||||||
|
|
||||||
|
* rvalue must be moved, otherwise we would keep (dangling) reference to temporaries.
|
||||||
|
* for lvalue, keeping a reference is quicker. Of course, in the previous example,
|
||||||
|
it is mandatory that a live longer than e ...
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
.. highlight:: c
|
.. 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
|
@ -1,226 +0,0 @@
|
|||||||
|
|
||||||
.. highlight:: c
|
|
||||||
|
|
||||||
.. _callable_object:
|
|
||||||
|
|
||||||
Overloading functions and callable objects for clef expression arguments
|
|
||||||
=============================================================================
|
|
||||||
|
|
||||||
Given a callable object or a function, it is possible to overload it for clef expression arguments, returning a clef expression.
|
|
||||||
In all cases:
|
|
||||||
|
|
||||||
*Overloads that are activated iif at least one argument is a clef expression*.
|
|
||||||
|
|
||||||
Functions
|
|
||||||
------------
|
|
||||||
|
|
||||||
std math functions
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The overload is defined by clef automatically for usual functions :
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
int main() {
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
std::cout << 2.0 + std::cos(2.0) << std::endl;
|
|
||||||
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
|
|
||||||
}
|
|
||||||
|
|
||||||
Overloading a function for clef expressions arguments
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The `TRIQS_CLEF_MAKE_FNT_LAZY` macro defines the overload for clef expressions arguments of a function. Synopsis is ::
|
|
||||||
|
|
||||||
namespace triqs { namespace clef {
|
|
||||||
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
|
|
||||||
}}
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
double foo(double x) { return x/2;}
|
|
||||||
int foo(int x) { return x*2;}
|
|
||||||
|
|
||||||
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
std::cout << foo(2.0) << std::endl;
|
|
||||||
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
|
|
||||||
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that :
|
|
||||||
|
|
||||||
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
|
|
||||||
* The function `foo` can have many overloads.
|
|
||||||
* The function foo can be a template, BUT then the template must be disabled for lazy expressions, as in ::
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value,T>::type
|
|
||||||
foo (T const & x) { return x+1;}
|
|
||||||
|
|
||||||
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
std::cout << foo(2.0) << std::endl;
|
|
||||||
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
|
|
||||||
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable objects
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
Similarly to functions, classes can define an `operator()` for lazy expressions arguments.
|
|
||||||
It is an ordinary operator() that must :
|
|
||||||
|
|
||||||
* Be enabled only when one argument is a clef expression
|
|
||||||
|
|
||||||
* Return a clef expression.
|
|
||||||
|
|
||||||
The function make_expr_call helps.
|
|
||||||
|
|
||||||
Object stored by copy (default)
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The default behaviour is to store the object by copy in the expression tree...
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
|
|
||||||
struct Obj {
|
|
||||||
double v; // put something in it
|
|
||||||
Obj(double v_): v(v_){} // constructor
|
|
||||||
|
|
||||||
// The "normal", non lazy call operator ....
|
|
||||||
double operator() (double x) const { return 10*x;}
|
|
||||||
|
|
||||||
// Call operator for const object
|
|
||||||
// make_expr_call creates a clef expression with a "call" node at the top
|
|
||||||
// calling this object on the arguments.
|
|
||||||
// Obj is stored by making a copy in the expression tree.
|
|
||||||
// NB : the make_expr_call trait enabled only if one of the arguments is lazy
|
|
||||||
// hence if none of the Args are clef expression, the template is disabled by SFINAE.
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
|
|
||||||
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
|
|
||||||
|
|
||||||
// Just to print itself nicely in the expressions
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
Obj f(7);
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
triqs::clef::placeholder<4> y_;
|
|
||||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
|
||||||
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
|
||||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
|
||||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object stored by reference
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Sometimes, one want to escape the copy of the object in the tree.
|
|
||||||
In that case, just use a std::reference_wrapper in place of the object.
|
|
||||||
You have then to guarantee that the object will live longer that the expression
|
|
||||||
that you form.
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
|
|
||||||
struct Obj {
|
|
||||||
double v; // put something in it
|
|
||||||
Obj(double v_): v(v_){} // constructor
|
|
||||||
Obj(Obj const &) = delete; // a non copyable object
|
|
||||||
|
|
||||||
// The "normal", non lazy call operator ....
|
|
||||||
double operator() (double x) const { return 10*x;}
|
|
||||||
|
|
||||||
// Same as above, but now we stored a ref to the object and not a copy of the object.
|
|
||||||
// Reference are encapsulated in std::reference_wrapper (Cf C++ documentation).
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
|
|
||||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
|
|
||||||
|
|
||||||
// The non const version (which then stores a non-const reference ....)
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
|
|
||||||
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
|
|
||||||
|
|
||||||
// Just to print itself nicely in the expressions
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
Obj f(7);
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
triqs::clef::placeholder<4> y_;
|
|
||||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
|
||||||
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
|
||||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
|
||||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
|
||||||
}
|
|
||||||
|
|
||||||
.. note : one can of course replace the reference_wrapper by a view of the object, e.g....
|
|
||||||
|
|
||||||
|
|
||||||
NB: When non lazy operator() is already a template ?
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
Then it must be disabled for clef expression argument, using the trait ::
|
|
||||||
|
|
||||||
clef::is_any_lazy<T...> :: value // true iif one of the T is a clef expression
|
|
||||||
|
|
||||||
Example, derived from the previous one :
|
|
||||||
|
|
||||||
.. compileblock::
|
|
||||||
|
|
||||||
#include <triqs/clef.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct Obj {
|
|
||||||
double v; // put something in it
|
|
||||||
Obj(double v_): v(v_){} // constructor
|
|
||||||
|
|
||||||
// The "normal", non lazy call operator is now a template
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value, T>::type // correct
|
|
||||||
// T operator() (T const & x) const { return 10*x;} would be ambiguous !
|
|
||||||
operator() (T const & x) const { return 10*x;}
|
|
||||||
|
|
||||||
// lazy expression
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
|
|
||||||
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
|
|
||||||
|
|
||||||
// Just to print itself nicely in the expressions
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
Obj f(7);
|
|
||||||
triqs::clef::placeholder<3> x_;
|
|
||||||
triqs::clef::placeholder<4> y_;
|
|
||||||
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
|
||||||
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
|
||||||
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
.. highlight:: c
|
|
||||||
|
|
||||||
clef::function class
|
|
||||||
==========================
|
|
||||||
|
|
||||||
The class triqs::clef::function is similar to boost::function (std::function),
|
|
||||||
except that :
|
|
||||||
|
|
||||||
* it can be constructed from an expression and an ordered list of placeholders.
|
|
||||||
* it is `lazy-callable` and `lazy-assignable`
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
It stores the expression polymorphically, by erasing its type. (You can put various expressions into it, cf below).
|
|
||||||
This might lead to some performance penalty in some case, even though tests do not show that at present...
|
|
||||||
|
|
||||||
Example of usage is given in :ref:`lazy_function_ex`.
|
|
129
doc/reference/c++/clef/overload.rst
Normal file
129
doc/reference/c++/clef/overload.rst
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
.. highlight:: c
|
||||||
|
|
||||||
|
Overloading functions and methods for CLEF arguments
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
.. _overload_function:
|
||||||
|
|
||||||
|
Overloading functions
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Given a function, it is possible to overload it for CLEF expression arguments, returning a CLEF expression
|
||||||
|
using the `TRIQS_CLEF_MAKE_FNT_LAZY` macro.
|
||||||
|
|
||||||
|
**Synopsis** ::
|
||||||
|
|
||||||
|
namespace triqs { namespace clef {
|
||||||
|
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
|
||||||
|
}}
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. compileblock::
|
||||||
|
|
||||||
|
#include <triqs/clef.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// a simple foo function
|
||||||
|
double foo(double x) { return x/2;}
|
||||||
|
int foo(int x) { return x*2;}
|
||||||
|
|
||||||
|
// a more complex case : bar is already a template
|
||||||
|
// we have to disable it for CLEF expression to avoid ambiguity
|
||||||
|
|
||||||
|
// C++14 clean syntax will be (using concepts)
|
||||||
|
// template<NotClefExpression T>
|
||||||
|
// T bar (T const & x) { return x+1;}
|
||||||
|
|
||||||
|
// C++11 workaround
|
||||||
|
template<typename T>
|
||||||
|
typename std::enable_if<!triqs::clef::is_clef_expression<T>::value,T>::type
|
||||||
|
bar (T const & x) { return x+1;}
|
||||||
|
|
||||||
|
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; TRIQS_CLEF_MAKE_FNT_LAZY (bar) ; }}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
triqs::clef::placeholder<3> x_;
|
||||||
|
std::cout << foo(2.0)<<" "<<eval(x_ + foo(x_), x_ = 3)<<" "<<eval(x_ + foo(x_), x_ = 3.5) << std::endl;
|
||||||
|
std::cout << bar(2.0)<<" "<<eval(x_ + bar(x_), x_ = 3)<<" "<<eval(x_ + bar(x_), x_ = 3.5) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that :
|
||||||
|
|
||||||
|
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
|
||||||
|
* The function `foo` can have many overloads.
|
||||||
|
* The function `bar` can be a template, BUT then the template must be disabled for lazy expressions.
|
||||||
|
* The overload is already defined by clef for usual functions :
|
||||||
|
|
||||||
|
.. compileblock::
|
||||||
|
|
||||||
|
#include <triqs/clef.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
int main() {
|
||||||
|
triqs::clef::placeholder<3> x_;
|
||||||
|
std::cout << 2.0 + std::cos(2.0) << std::endl;
|
||||||
|
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
|
||||||
|
}
|
||||||
|
|
||||||
|
.. _callable_object:
|
||||||
|
|
||||||
|
Overloading operator() and other methods
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
Similarly to functions, classes can define an `operator()` for CLEF expressions arguments (or any other method).
|
||||||
|
It is an ordinary operator() that must :
|
||||||
|
|
||||||
|
* Be enabled only when one argument is a CLEF expression
|
||||||
|
* Return a CLEF expression.
|
||||||
|
|
||||||
|
Example :
|
||||||
|
|
||||||
|
.. compileblock::
|
||||||
|
|
||||||
|
#include <triqs/clef.hpp>
|
||||||
|
|
||||||
|
struct Obj {
|
||||||
|
double v; // put something in it
|
||||||
|
Obj(double v_): v(v_){} // constructor
|
||||||
|
Obj(Obj const &) = delete; // a non copyable object, to illustrate that we do NOT copy...
|
||||||
|
|
||||||
|
// The "normal", non CLEF call operator ....
|
||||||
|
double operator() (double x) const { return 10*x;}
|
||||||
|
|
||||||
|
// This macro implements properly an overload of the operator ()
|
||||||
|
TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
|
||||||
|
|
||||||
|
// a method
|
||||||
|
double my_method(double x) { return 2*x;}
|
||||||
|
|
||||||
|
// CLEF overload
|
||||||
|
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(Obj,my_method);
|
||||||
|
|
||||||
|
// Just to print itself nicely in the expressions
|
||||||
|
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Obj f(7);
|
||||||
|
triqs::clef::placeholder<1> x_; triqs::clef::placeholder<2> y_;
|
||||||
|
|
||||||
|
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
|
||||||
|
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
|
||||||
|
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
|
||||||
|
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl<<std::endl ;
|
||||||
|
|
||||||
|
std::cout << "Clef expression : "<< f.my_method(y_) + 2*x_ << std::endl ;
|
||||||
|
std::cout << "Complete evaluation : "<< eval(f.my_method(x_) + 2*x_, x_=1) << std::endl ;
|
||||||
|
std::cout << "Partial evaluation : "<< eval(f.my_method(y_) + 2*x_, y_=1) << std::endl ;
|
||||||
|
std::cout << "Complete evalution : "<< eval(f.my_method(y_) + 2*x_, x_=3, y_=1) << std::endl ;
|
||||||
|
}
|
||||||
|
|
||||||
|
**NB** When the method or the non CLEF operator() is already a template,
|
||||||
|
it must be disabled for clef expression argument, using the trait ::
|
||||||
|
|
||||||
|
clef::is_clef_expression<T...> // true iif one of the T is a clef expression
|
||||||
|
|
||||||
|
as the `bar` function above.
|
||||||
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
#include <triqs/clef/clef.hpp>
|
|
||||||
#include <triqs/clef/io.hpp>
|
|
||||||
#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) <<std::endl;
|
|
||||||
|
|
||||||
struct F1{
|
|
||||||
double v;
|
|
||||||
F1(double v_): v(v_){}
|
|
||||||
F1(F1 const &) = delete; // non copyable
|
|
||||||
double operator() (double x) const { return 10*x;}
|
|
||||||
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
|
|
||||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
|
||||||
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
|
|
||||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
|
||||||
|
|
||||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct F1b {
|
|
||||||
double v; std::shared_ptr<double> v_ptr;
|
|
||||||
|
|
||||||
F1b(double v_): v_ptr (new double(v_)) {v=v_;} // on purpose, I avoid adding a default constructor !
|
|
||||||
F1b (F1b const & x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
|
||||||
//F1b (F1b && x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
|
|
||||||
|
|
||||||
double operator() (double x) const { return 10*x;}
|
|
||||||
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<F1b,Args...>::type
|
|
||||||
operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);}
|
|
||||||
|
|
||||||
template<typename Fnt> friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, F1b const & x) { return out<<"F1b";}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct F2 {
|
|
||||||
|
|
||||||
double v;
|
|
||||||
F2() {v=0;}
|
|
||||||
|
|
||||||
double operator()(double x, double y) const { return 10*x + y;}
|
|
||||||
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F2>,Args...>::type
|
|
||||||
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
|
|
||||||
|
|
||||||
template< typename... Args>
|
|
||||||
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F2>,Args...>::type
|
|
||||||
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
|
|
||||||
|
|
||||||
template<typename Fnt> friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<<std::endl;}
|
|
||||||
friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
using namespace triqs::clef;
|
|
||||||
|
|
||||||
triqs::clef::placeholder <1> x_;
|
|
||||||
triqs::clef::placeholder <2> y_;
|
|
||||||
triqs::clef::placeholder <3> z_;
|
|
||||||
namespace tql= triqs::clef;
|
|
||||||
|
|
1
test/speed/clef_common.hpp
Symbolic link
1
test/speed/clef_common.hpp
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../triqs/clef/common.hpp
|
@ -5,13 +5,7 @@ struct F7 {
|
|||||||
F7(double v_): v(v_){}
|
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";}
|
||||||
|
@ -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";}
|
||||||
};
|
};
|
||||||
|
@ -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>
|
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;}
|
||||||
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";}
|
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";}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -58,31 +58,25 @@ 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;
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
37
test/triqs/clef/lazy_method.cpp
Normal file
37
test/triqs/clef/lazy_method.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "./common.hpp"
|
||||||
|
|
||||||
|
struct AA{
|
||||||
|
double v;
|
||||||
|
AA(double v_): v(v_){}
|
||||||
|
AA(AA const &) = delete; // non copyable
|
||||||
|
AA(AA &&x) : v(x.v) { std::cerr << "Moving AA "<< std::endl;}
|
||||||
|
|
||||||
|
double operator() (double x) const { return 10*x;}
|
||||||
|
|
||||||
|
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(AA);
|
||||||
|
|
||||||
|
template<typename Fnt> friend void triqs_clef_auto_assign (AA & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
|
||||||
|
|
||||||
|
friend std::ostream & operator<<(std::ostream & out, AA const & x) { return out<<"AA";}
|
||||||
|
|
||||||
|
double my_method(double x) { return 2*x;}
|
||||||
|
|
||||||
|
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||||
|
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method);
|
||||||
|
#else
|
||||||
|
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method,double);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
AA f{8};
|
||||||
|
|
||||||
|
TEST(eval( f.my_method(x_), x_ = 10));
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
1
test/triqs/clef/lazy_method.output
Normal file
1
test/triqs/clef/lazy_method.output
Normal file
@ -0,0 +1 @@
|
|||||||
|
(eval( f.my_method(x_), x_ = 10)) ---> 20
|
@ -13,15 +13,10 @@ struct F1{
|
|||||||
F1(F1 const &) = delete; // non copyable
|
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";}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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_;
|
|
||||||
|
// 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
|
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
test/triqs/clef_examples/sum_functional.output
Normal file
3
test/triqs/clef_examples/sum_functional.output
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
19
|
||||||
|
(_2 + sum(lazy function : (_1) --> ((2 * _1) + _2)))
|
||||||
|
9
|
@ -1,4 +0,0 @@
|
|||||||
19
|
|
||||||
sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))
|
|
||||||
(_2 + (2 * sum(lazy function : (_1) --> (((2 * _1) + 1) + _2))))
|
|
||||||
38
|
|
@ -10,9 +10,9 @@ int main() {
|
|||||||
double pi = std::acos(-1);
|
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)
|
||||||
|
@ -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 --------------------------------------------
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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,109 +37,130 @@
|
|||||||
|
|
||||||
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)};}
|
||||||
|
};
|
||||||
|
|
||||||
|
// placeholder will always be copied (they are empty anyway).
|
||||||
|
template< int N > struct force_copy_in_expr<placeholder<N>> : std::true_type{};
|
||||||
|
|
||||||
|
// represent a couple (placeholder, value).
|
||||||
|
template<int N, typename U> struct pair {
|
||||||
|
U rhs;
|
||||||
|
static constexpr int p = N;
|
||||||
|
typedef typename remove_cv_ref <U>::type value_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> struct is_placeholder : std::false_type {};
|
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
|
||||||
template<int N> struct is_placeholder <placeholder <N> > : std::true_type {};
|
// 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<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
||||||
template<typename... Args> struct is_any_lazy : std::false_type {};
|
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
||||||
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
|
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
||||||
template <typename T> struct is_any_lazy< T > : std::false_type {};
|
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
||||||
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
|
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
||||||
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
|
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
||||||
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
|
|
||||||
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
|
|
||||||
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
|
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 >
|
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
|
||||||
expr<tags::subscript, expr, typename remove_cv_ref<Args>::type > operator[](Args && args) const
|
// [] returns a new lazy expression, with one more layer
|
||||||
{ return expr<tags::subscript, expr, typename remove_cv_ref<Args>::type> (tags::subscript(), *this,std::forward<Args>(args));}
|
template<typename Args>
|
||||||
|
expr<tags::subscript, expr, typename expr_storage_t<Args>::type > operator[](Args && args) const
|
||||||
|
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
|
||||||
|
// () also ...
|
||||||
template< typename... Args >
|
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,18 +203,18 @@ 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;
|
||||||
// remove the reference because of ternary if_else in which decltype returns a ref...
|
// remove the reference because of ternary if_else in which decltype returns a ref...
|
||||||
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
|
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic case : do nothing (for the leaf of the tree except placeholder)
|
// Generic case : do nothing (for the leaf of the tree except placeholder)
|
||||||
template<typename T, typename ... Pairs> struct evaluator{
|
template<typename T, typename ... Pairs> struct evaluator{
|
||||||
typedef T rtype;
|
typedef T rtype;
|
||||||
rtype operator()( T const & k, Pairs const &... pairs) {return k;}
|
rtype operator()(T const & k, Pairs const &... pairs) {return k;}
|
||||||
};
|
};
|
||||||
|
|
||||||
// placeholder
|
// placeholder
|
||||||
@ -207,40 +224,53 @@ namespace triqs { namespace clef {
|
|||||||
rtype operator()(placeholder<N>, pair<i,T> const &, Pairs const& ... pairs) { return eval_t()(placeholder<N>(), pairs...);}
|
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,22 +314,28 @@ 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)
|
||||||
* --------------------------------------------------------------------------------------------------- */
|
* --------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
template <int N, typename Expr>
|
template <int N, typename Expr>
|
||||||
make_fun_impl<Expr,N > operator >> ( placeholder<N> p, Expr&& ex) { return {ex}; }
|
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------------------------------
|
||||||
* Auto assign for ()
|
* Auto assign for ()
|
||||||
@ -315,7 +352,7 @@ namespace triqs { namespace clef {
|
|||||||
template<typename Tag, typename... Childs, typename RHS>
|
template<typename Tag, typename... Childs, typename RHS>
|
||||||
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
|
||||||
|
|
||||||
template<typename Tag, typename... Childs, typename RHS>
|
template<typename Tag, typename... Childs, typename RHS>
|
||||||
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
|
||||||
|
|
||||||
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
|
||||||
@ -327,6 +364,10 @@ namespace triqs { namespace clef {
|
|||||||
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
|
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, typename... T>
|
template<typename F, typename RHS, int... Is>
|
||||||
|
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
|
||||||
|
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F, typename RHS, typename... T>
|
||||||
|
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
|
||||||
|
|
||||||
|
template<typename F, typename RHS, typename... T>
|
||||||
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
|
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,23 +465,30 @@ 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);
|
||||||
x._exp = std::shared_ptr <void> (new typename std::remove_cv<decltype(rhs.ex)>::type (rhs.ex));
|
x._exp = std::shared_ptr <void> (new typename std::remove_cv<decltype(rhs.ex)>::type (rhs.ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
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)...));
|
||||||
|
|
||||||
|
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
|
||||||
|
|
||||||
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\
|
||||||
|
struct __clef_lazy_method_impl_##name { \
|
||||||
|
TY * _x;\
|
||||||
|
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN ((*_x).name(std::forward<A>(a)...));\
|
||||||
|
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
||||||
|
};\
|
||||||
|
template< typename... A> \
|
||||||
|
auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...));
|
||||||
|
|
||||||
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...)\
|
||||||
|
template< typename... Args>\
|
||||||
|
auto operator()(Args&&... args ) const & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
||||||
|
\
|
||||||
|
template< typename... Args>\
|
||||||
|
auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
|
||||||
|
\
|
||||||
|
template< typename... Args>\
|
||||||
|
auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward<Args>(args)...));\
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name,RETURN_TYPE)\
|
||||||
|
struct __clef_lazy_method_impl_##name { \
|
||||||
|
TY * _x;\
|
||||||
|
template<typename... A> RETURN_TYPE operator()(A&&... a) const {return ((*_x).name(std::forward<A>(a)...));}\
|
||||||
|
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
|
||||||
|
};\
|
||||||
|
template< typename... A> \
|
||||||
|
typename _result_of::make_expr_call<__clef_lazy_method_impl_##name, A...>::type\
|
||||||
|
name( A&& ... a) {return make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...);}
|
||||||
|
|
||||||
|
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(TY)\
|
||||||
|
template< typename... Args>\
|
||||||
|
typename triqs::clef::_result_of::make_expr_call<TY const &,Args...>::type\
|
||||||
|
operator()(Args&&... args ) const {return make_expr_call (*this,std::forward<Args>(args)...);}\
|
||||||
|
\
|
||||||
|
template< typename... Args>\
|
||||||
|
typename triqs::clef::_result_of::make_expr_call<TY &,Args...>::type\
|
||||||
|
operator()(Args&&... args ) {return make_expr_call (*this,std::forward<Args>(args)...);}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
}} // namespace triqs::clef
|
}} // namespace triqs::clef
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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)
|
||||||
|
@ -186,26 +186,31 @@ 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...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// on mesh component for composite meshes
|
// on mesh component for composite meshes
|
||||||
// enable iif the first arg is a mesh_point_t for the first component of the mesh_t
|
// enable iif the first arg is a mesh_point_t for the first component of the mesh_t
|
||||||
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
||||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
|
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
|
||||||
operator() (Arg0 const & arg0, Args const & ... args)
|
operator() (Arg0 const & arg0, Args const & ... args)
|
||||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||||
|
|
||||||
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
|
||||||
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type
|
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
|
operator() (Arg0 const & arg0, Args const & ... args) const
|
||||||
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//// [] and access to the grid point
|
//// [] and access to the grid point
|
||||||
typedef typename std::result_of<data_proxy_t(data_t &,size_t)>::type r_type;
|
typedef typename std::result_of<data_proxy_t(data_t &,size_t)>::type r_type;
|
||||||
@ -223,14 +228,29 @@ namespace triqs { namespace gfs {
|
|||||||
cr_type operator[] (closest_pt_wrap<U...> const & p) const { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point<Variable,Target,Opt>::invoke(this,p)));}
|
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>
|
||||||
|
typename boost::lazy_enable_if< // enable the template if
|
||||||
|
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
|
||||||
|
clef::_result_of::make_expr_subscript<view_type,Arg>
|
||||||
|
>::type // end of lazy_enable_if
|
||||||
|
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*template<typename Arg>
|
||||||
|
//auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
|
||||||
|
auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
|
||||||
|
|
||||||
template<typename Arg>
|
template<typename Arg>
|
||||||
typename boost::lazy_enable_if< // enable the template if
|
//auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
|
||||||
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
|
auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
|
||||||
clef::result_of::make_expr_subscript<view_type,Arg>
|
*/
|
||||||
>::type // end of lazy_enable_if
|
|
||||||
|
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));}
|
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)...)));}
|
||||||
|
|
||||||
@ -418,8 +438,8 @@ namespace triqs { namespace gfs {
|
|||||||
return gf_view<Variable,scalar_valued,Opt>(g.mesh(), g.data()(range(), args... ), sg, g.symmetry());
|
return gf_view<Variable,scalar_valued,Opt>(g.mesh(), g.data()(range(), args... ), sg, g.symmetry());
|
||||||
}
|
}
|
||||||
|
|
||||||
// a scalar_valued gf can be viewed as a 1x1 matrix
|
// a scalar_valued gf can be viewed as a 1x1 matrix
|
||||||
template<typename Variable, typename Opt, bool V, typename... Args>
|
template<typename Variable, typename Opt, bool V, typename... Args>
|
||||||
gf_view<Variable,matrix_valued,Opt> reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl<Variable,scalar_valued,Opt,V> const & g) {
|
gf_view<Variable,matrix_valued,Opt> reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl<Variable,scalar_valued,Opt,V> const & g) {
|
||||||
typedef arrays::array_view<typename gfs_implementation::data_proxy<Variable,matrix_valued,Opt>::storage_t::value_type,3> a_t;
|
typedef arrays::array_view<typename gfs_implementation::data_proxy<Variable,matrix_valued,Opt>::storage_t::value_type,3> a_t;
|
||||||
auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector<size_t,3>(g.data().shape()[0],1,1)), g.data().storage()};
|
auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector<size_t,3>(g.data().shape()[0],1,1)), g.data().storage()};
|
||||||
|
@ -32,20 +32,11 @@
|
|||||||
#if GCC_VERSION < 40801
|
#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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user